Skip to content

Commit

Permalink
little refactor on XCUIElement query
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladimir Espinola committed May 22, 2024
1 parent 1e30952 commit 2c951c5
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 30 deletions.
4 changes: 4 additions & 0 deletions Example/CreativeUITest/CreativeUITest-Bridging-Header.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//

57 changes: 27 additions & 30 deletions Example/CreativeUITest/CreativeUITest.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#import <WebKit/WebKit.h>
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "CreativeUITest-Swift.h"

@interface CreativeUITest : XCTestCase

Expand Down Expand Up @@ -38,72 +39,69 @@ + (void)tearDown {

- (void)testLoadCreative_clickClose_closesCreative {
[self launchAppWithMode:@"production"];
[app.buttons[@"Push me for Creative!"] tap];
[app.buttons[@"Push me for Creative!"] tapOnElement];

sleep(2);

// Close the creative
XCTAssertTrue([app.webViews.buttons[@"Dismiss this popup"] waitForExistenceWithTimeout:5.0]);
[app.webViews.buttons[@"Dismiss this popup"] tap];
[app.webViews.buttons[@"Dismiss this popup"] tapOnElement];

// Assert that the creative is closed
XCTAssertTrue([app.buttons[@"Push me for Creative!"] waitForExistenceWithTimeout:5.0]);
XCTAssertTrue([app.buttons[@"Push me for Creative!"] elementExists]);
XCTAssertEqual(app.buttons[@"Push me for Creative!"].isHittable, true);
}


- (void)testLoadCreative_fillOutFormAndSubmit_launchesSmsAppWithPrePopulatedText {
[self launchAppWithMode:@"production"];
[app.buttons[@"Push me to clear the User!"] tap];
[app.buttons[@"Push me for Creative!"] tap];
[app.buttons[@"Push me to clear the User!"] tapOnElement];
[app.buttons[@"Push me for Creative!"] tapOnElement];

// Fill in the email
XCTAssertTrue([app.webViews.textFields[@"Email Address"] waitForExistenceWithTimeout:5.0]);
XCUIElement *emailField = app.webViews.textFields[@"Email Address"];
[emailField tap];
[emailField tapOnElement];
[emailField typeText:@"[email protected]"];

// Tap something else on the creative to dismiss the keyboard
[app.staticTexts[@"10% OFF"] tap];
[app.staticTexts[@"10% OFF"] tapOnElement];

// Submit email
XCTAssertTrue([app.buttons[@"CONTINUE"] waitForExistenceWithTimeout:5.0]);
[app.webViews.buttons[@"CONTINUE"] tap];
[app.webViews.buttons[@"CONTINUE"] tapOnElement];

// Click subscribe button
XCTAssertTrue([app.buttons[@"GET 10% OFF NOW when you sign up for email and texts"] waitForExistenceWithTimeout:5.0]);
[app.buttons[@"GET 10% OFF NOW when you sign up for email and texts"] tap];
// Click subscribe button waitForExistenceWithTimeout:5.0]);
[app.buttons[@"GET 10% OFF NOW when you sign up for email and texts"] tapOnElement];

// Assert that the SMS app is opened with prepopulated text if running locally
// (AWS Device Farm doesn't allow use of SMS apps)
NSString *envHost = [[[NSProcessInfo processInfo] environment] objectForKey:@"COM_ATTENTIVE_EXAMPLE_HOST"];
if ([envHost isEqualToString:@"local"]) {
XCUIApplication *smsApp = [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.MobileSMS"];
XCTAssertTrue([smsApp.textFields[@"Message"] waitForExistenceWithTimeout:5.0]);
XCTAssertTrue([smsApp.textFields[@"Message"] elementExists]);
XCTAssertTrue([smsApp.textFields[@"Message"].value containsString:@"Send this text to subscribe to recurring automated personalized marketing alerts (e.g. cart reminders) from Attentive Mobile Apps Test"]);
}
}


- (void)testLoadCreative_clickPrivacyLink_opensPrivacyPageInWebApp {
[self launchAppWithMode:@"production"];
[app.buttons[@"Push me for Creative!"] tap];
[app.buttons[@"Push me for Creative!"] tapOnElement];

// Click privacy link
XCTAssertTrue([app.webViews.links[@"Privacy"] waitForExistenceWithTimeout:5.0]);
[app.webViews.links[@"Privacy"] tap];
[app.webViews.links[@"Privacy"] tapOnElement];

// Wait for a moment to allow the app to react
sleep(5);

// Check if the app is no longer active
XCTAssertFalse([app.webViews.links[@"Privacy"] waitForExistenceWithTimeout:5.0]);

XCTAssertFalse([app.webViews.links[@"Privacy"] elementExists]);
// AWS Device Farm doesn't always acknowledge separate apps, leading to flakiness here
NSString *envHost = [[[NSProcessInfo processInfo] environment] objectForKey:@"COM_ATTENTIVE_EXAMPLE_HOST"];
if ([envHost isEqualToString:@"local"]) {
// Verify that the privacy page is visible in the external browser
XCUIApplication *safariApp = [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.mobilesafari"];
BOOL privacyPolicyExists = [safariApp.staticTexts[@"Privacy Policy"] waitForExistenceWithTimeout:5.0];
BOOL messagingPrivacyPolicyExists = [safariApp.staticTexts[@"Messaging Privacy Policy"] waitForExistenceWithTimeout:5.0];
BOOL privacyPolicyExists = [safariApp.staticTexts[@"Privacy Policy"] elementExists];
BOOL messagingPrivacyPolicyExists = [safariApp.staticTexts[@"Messaging Privacy Policy"] elementExists];

XCTAssertTrue(privacyPolicyExists || messagingPrivacyPolicyExists);
}
Expand All @@ -112,26 +110,25 @@ - (void)testLoadCreative_clickPrivacyLink_opensPrivacyPageInWebApp {

- (void)testLoadCreative_inDebugMode_showsDebugMessage {
[self launchAppWithMode:@"debug"];
[app.buttons[@"Push me for Creative!"] tap];
[app.buttons[@"Push me for Creative!"] tapOnElement];

// Verify debug page shows
XCTAssertTrue([app.staticTexts[@"Debug output JSON"] waitForExistenceWithTimeout:5.0]);
XCTAssertTrue([app.staticTexts[@"Debug output JSON"] elementExists]);
}

- (void)testLoadCreative_clickProductPage_closesCreative {
[self launchAppWithMode:@"production"];
[app.buttons[@"Push me for Creative!"] tap];
[app.buttons[@"Push me for Creative!"] tapOnElement];

// Click privacy link
XCTAssertTrue([app.webViews.links[@"Privacy"] waitForExistenceWithTimeout:5.0]);
[app.tabBars.buttons[@"Product"] tap];
[app.tabBars.buttons[@"Product"] tapOnElement];

// Verify that the product page is visible
XCTAssertTrue([app.buttons[@"Add To Cart"] waitForExistenceWithTimeout:5.0]);
XCTAssertTrue([app.buttons[@"Add To Cart"] elementExists]);

// Nav back, and verify the creative is closed
[app.tabBars.buttons[@"Main"] tap];
XCTAssertTrue([app.buttons[@"Push me for Creative!"] waitForExistenceWithTimeout:5.0]);
[app.tabBars.buttons[@"Main"] tapOnElement];
XCTAssertTrue([app.buttons[@"Push me for Creative!"] elementExists]);
}


Expand Down
30 changes: 30 additions & 0 deletions Example/CreativeUITest/XCUIElement+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// XCUIElement+Extension.swift
// CreativeUITest
//
// Created by Vladimir - Work on 2024-05-22.
//

import XCTest

extension XCUIElement {
/// Verify element existence and then proceed with tapping on it
@objc func tapOnElement() {
guard elementExists() else {
XCTFail("Element with \(identifier) and type \(elementType) does not exists")
return
}
tap()
}

/// Verify element existence on the app view hierarchy
@objc func elementExists() -> Bool {
elementExists(timeout: 5)
}
}

fileprivate extension XCUIElement {
func elementExists(timeout: TimeInterval) -> Bool {
waitForExistence(timeout: timeout)
}
}
14 changes: 14 additions & 0 deletions Example/Example.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
69CCAF6228DCDE5A007620BD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 69CCAF6128DCDE5A007620BD /* main.m */; };
69D3C14C299EF2D10027934F /* CreativeUITest.m in Sources */ = {isa = PBXBuildFile; fileRef = 69D3C14B299EF2D10027934F /* CreativeUITest.m */; };
C77C85E38A76EFB4A30A63ED /* Pods_Example___Pod.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E225173AF4DB16299D85458 /* Pods_Example___Pod.framework */; };
FB51061A2BFE4A9700D9A72D /* XCUIElement+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB5106192BFE4A9700D9A72D /* XCUIElement+Extension.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -81,6 +82,8 @@
6F479792BC83079236F72CF1 /* Pods-Example - Pod.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example - Pod.debug.xcconfig"; path = "Target Support Files/Pods-Example - Pod/Pods-Example - Pod.debug.xcconfig"; sourceTree = "<group>"; };
7B8828B08D7E2DB6703354E8 /* Pods-Example - Pod.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example - Pod.release.xcconfig"; path = "Target Support Files/Pods-Example - Pod/Pods-Example - Pod.release.xcconfig"; sourceTree = "<group>"; };
A6F5932642D2BF98834A4354 /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = "<group>"; };
FB5106182BFE4A9700D9A72D /* CreativeUITest-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CreativeUITest-Bridging-Header.h"; sourceTree = "<group>"; };
FB5106192BFE4A9700D9A72D /* XCUIElement+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCUIElement+Extension.swift"; sourceTree = "<group>"; };
FDEDF14001E311BED132C759 /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -176,6 +179,8 @@
isa = PBXGroup;
children = (
69D3C14B299EF2D10027934F /* CreativeUITest.m */,
FB5106192BFE4A9700D9A72D /* XCUIElement+Extension.swift */,
FB5106182BFE4A9700D9A72D /* CreativeUITest-Bridging-Header.h */,
);
path = CreativeUITest;
sourceTree = "<group>";
Expand Down Expand Up @@ -263,6 +268,7 @@
};
69D3C148299EF2D10027934F = {
CreatedOnToolsVersion = 14.2;
LastSwiftMigration = 1530;
TestTargetID = 58317964292EEEAA0003D6B0;
};
};
Expand Down Expand Up @@ -391,6 +397,7 @@
buildActionMask = 2147483647;
files = (
69D3C14C299EF2D10027934F /* CreativeUITest.m in Sources */,
FB51061A2BFE4A9700D9A72D /* XCUIElement+Extension.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -662,6 +669,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
Expand Down Expand Up @@ -690,6 +698,9 @@
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_OBJC_BRIDGING_HEADER = "CreativeUITest/CreativeUITest-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = "Example - Local";
};
Expand All @@ -699,6 +710,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
Expand Down Expand Up @@ -727,6 +739,8 @@
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_OBJC_BRIDGING_HEADER = "CreativeUITest/CreativeUITest-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = "Example - Local";
};
Expand Down

0 comments on commit 2c951c5

Please sign in to comment.