diff --git a/PrivateHeaders/XCTest/XCUIApplication.h b/PrivateHeaders/XCTest/XCUIApplication.h index 34bf69032..e092f26db 100644 --- a/PrivateHeaders/XCTest/XCUIApplication.h +++ b/PrivateHeaders/XCTest/XCUIApplication.h @@ -39,7 +39,6 @@ @property(readonly) id/*XCAccessibilityElement*/ accessibilityElement; + (instancetype)applicationWithPID:(pid_t)processID; -/*! DO NOT USE DIRECTLY! Please use fb_activate instead */ - (void)activate; - (void)dismissKeyboard; diff --git a/WebDriverAgent.xcodeproj/project.pbxproj b/WebDriverAgent.xcodeproj/project.pbxproj index 836267cce..4c098bde8 100644 --- a/WebDriverAgent.xcodeproj/project.pbxproj +++ b/WebDriverAgent.xcodeproj/project.pbxproj @@ -109,7 +109,6 @@ 641EE61E2240C5CA00173FCB /* FBExceptionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = EEC088E71CB56DA400B65968 /* FBExceptionHandler.m */; }; 641EE61F2240C5CA00173FCB /* FBXCodeCompatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = EE5A24411F136C8D0078B1D9 /* FBXCodeCompatibility.m */; }; 641EE6212240C5CA00173FCB /* FBElementTypeTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = EE9AB7901CAEDF0C008C271F /* FBElementTypeTransformer.m */; }; - 641EE6222240C5CA00173FCB /* FBApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = EE9AB7671CAEDF0C008C271F /* FBApplication.m */; }; 641EE6232240C5CA00173FCB /* FBScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 715AFAC01FFA29180053896D /* FBScreen.m */; }; 641EE6242240C5CA00173FCB /* FBXCTestDaemonsProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = EE35AD7A1E3B80C000A02D78 /* FBXCTestDaemonsProxy.m */; }; 641EE6262240C5CA00173FCB /* FBMathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = EE1888391DA661C400307AA8 /* FBMathUtils.m */; }; @@ -142,7 +141,6 @@ 641EE64B2240C5CA00173FCB /* XCTAsyncActivity.h in Headers */ = {isa = PBXBuildFile; fileRef = EE35ACCB1E3B77D600A02D78 /* XCTAsyncActivity.h */; settings = {ATTRIBUTES = (Public, ); }; }; 641EE64C2240C5CA00173FCB /* XCTestMisuseObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = EE35ACDF1E3B77D600A02D78 /* XCTestMisuseObserver.h */; settings = {ATTRIBUTES = (Public, ); }; }; 641EE64D2240C5CA00173FCB /* XCTRunnerDaemonSession.h in Headers */ = {isa = PBXBuildFile; fileRef = EE35ACEF1E3B77D600A02D78 /* XCTRunnerDaemonSession.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 641EE64E2240C5CA00173FCB /* FBApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = EE9AB7661CAEDF0C008C271F /* FBApplication.h */; settings = {ATTRIBUTES = (Public, ); }; }; 641EE64F2240C5CA00173FCB /* XCTestExpectationWaiter.h in Headers */ = {isa = PBXBuildFile; fileRef = EE35ACDA1E3B77D600A02D78 /* XCTestExpectationWaiter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 641EE6502240C5CA00173FCB /* UIGestureRecognizer-RecordingAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = EE35ACAD1E3B77D600A02D78 /* UIGestureRecognizer-RecordingAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 641EE6512240C5CA00173FCB /* XCKeyboardKeyMap.h in Headers */ = {isa = PBXBuildFile; fileRef = EE35ACBF1E3B77D600A02D78 /* XCKeyboardKeyMap.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -619,8 +617,6 @@ EE158AE91CBD456F00A3E3F0 /* FBElementTypeTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = EE9AB7901CAEDF0C008C271F /* FBElementTypeTransformer.m */; }; EE158AEA1CBD456F00A3E3F0 /* FBRuntimeUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = EE9AB7911CAEDF0C008C271F /* FBRuntimeUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; EE158AEB1CBD456F00A3E3F0 /* FBRuntimeUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = EE9AB7921CAEDF0C008C271F /* FBRuntimeUtils.m */; }; - EE158AF51CBD456F00A3E3F0 /* FBApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = EE9AB7661CAEDF0C008C271F /* FBApplication.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EE158AF61CBD456F00A3E3F0 /* FBApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = EE9AB7671CAEDF0C008C271F /* FBApplication.m */; }; EE158B5A1CBD462100A3E3F0 /* WebDriverAgentLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE158A991CBD452B00A3E3F0 /* WebDriverAgentLib.framework */; }; EE158B5F1CBD47A000A3E3F0 /* WebDriverAgentLib.h in Headers */ = {isa = PBXBuildFile; fileRef = EE158B5E1CBD47A000A3E3F0 /* WebDriverAgentLib.h */; settings = {ATTRIBUTES = (Public, ); }; }; EE18883A1DA661C400307AA8 /* FBMathUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = EE1888381DA661C400307AA8 /* FBMathUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -756,7 +752,7 @@ EE55B3271D1D54CF003AAAEC /* FBScrollingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EE55B3261D1D54CF003AAAEC /* FBScrollingTests.m */; }; EE5A24421F136D360078B1D9 /* FBXCodeCompatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = EE5A24411F136C8D0078B1D9 /* FBXCodeCompatibility.m */; }; EE6A89261D0B19E60083E92B /* FBSessionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EE6A89251D0B19E60083E92B /* FBSessionTests.m */; }; - EE6A892B1D0B25820083E92B /* FBApplicationDouble.m in Sources */ = {isa = PBXBuildFile; fileRef = EE6A89281D0B257B0083E92B /* FBApplicationDouble.m */; }; + EE6A892B1D0B25820083E92B /* XCUIApplicationDouble.m in Sources */ = {isa = PBXBuildFile; fileRef = EE6A89281D0B257B0083E92B /* XCUIApplicationDouble.m */; }; EE6A892D1D0B2AF40083E92B /* FBErrorBuilderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EE6A892C1D0B2AF40083E92B /* FBErrorBuilderTests.m */; }; EE6A89371D0B35920083E92B /* FBFailureProofTestCaseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EE6A89361D0B35920083E92B /* FBFailureProofTestCaseTests.m */; }; EE6A893A1D0B38640083E92B /* FBFailureProofTestCase.h in Headers */ = {isa = PBXBuildFile; fileRef = EE6A89381D0B38640083E92B /* FBFailureProofTestCase.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1254,8 +1250,8 @@ EE5A24401F136C8D0078B1D9 /* FBXCodeCompatibility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBXCodeCompatibility.h; sourceTree = ""; }; EE5A24411F136C8D0078B1D9 /* FBXCodeCompatibility.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBXCodeCompatibility.m; sourceTree = ""; }; EE6A89251D0B19E60083E92B /* FBSessionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBSessionTests.m; sourceTree = ""; }; - EE6A89271D0B257B0083E92B /* FBApplicationDouble.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBApplicationDouble.h; sourceTree = ""; }; - EE6A89281D0B257B0083E92B /* FBApplicationDouble.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBApplicationDouble.m; sourceTree = ""; }; + EE6A89271D0B257B0083E92B /* XCUIApplicationDouble.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XCUIApplicationDouble.h; sourceTree = ""; }; + EE6A89281D0B257B0083E92B /* XCUIApplicationDouble.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XCUIApplicationDouble.m; sourceTree = ""; }; EE6A892C1D0B2AF40083E92B /* FBErrorBuilderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBErrorBuilderTests.m; sourceTree = ""; }; EE6A89361D0B35920083E92B /* FBFailureProofTestCaseTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBFailureProofTestCaseTests.m; sourceTree = ""; }; EE6A89381D0B38640083E92B /* FBFailureProofTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBFailureProofTestCase.h; sourceTree = ""; }; @@ -1296,8 +1292,6 @@ EE9AB7631CAEDF0C008C271F /* FBTouchIDCommands.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBTouchIDCommands.m; sourceTree = ""; }; EE9AB7641CAEDF0C008C271F /* FBUnknownCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBUnknownCommands.h; sourceTree = ""; }; EE9AB7651CAEDF0C008C271F /* FBUnknownCommands.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBUnknownCommands.m; sourceTree = ""; }; - EE9AB7661CAEDF0C008C271F /* FBApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FBApplication.h; path = WebDriverAgentLib/FBApplication.h; sourceTree = SOURCE_ROOT; }; - EE9AB7671CAEDF0C008C271F /* FBApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FBApplication.m; path = WebDriverAgentLib/FBApplication.m; sourceTree = SOURCE_ROOT; }; EE9AB7731CAEDF0C008C271F /* WebDriverAgent.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = WebDriverAgent.bundle; sourceTree = ""; }; EE9AB7751CAEDF0C008C271F /* FBCommandHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBCommandHandler.h; sourceTree = ""; }; EE9AB7761CAEDF0C008C271F /* FBCommandStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBCommandStatus.h; sourceTree = ""; }; @@ -1615,8 +1609,8 @@ 13FFF2F1287DBEE600E561E4 /* XCElementSnapshotDouble.m */, ADBC39961D07842800327304 /* XCUIElementDouble.h */, ADBC39971D07842800327304 /* XCUIElementDouble.m */, - EE6A89271D0B257B0083E92B /* FBApplicationDouble.h */, - EE6A89281D0B257B0083E92B /* FBApplicationDouble.m */, + EE6A89271D0B257B0083E92B /* XCUIApplicationDouble.h */, + EE6A89281D0B257B0083E92B /* XCUIApplicationDouble.m */, ); path = Doubles; sourceTree = ""; @@ -2096,8 +2090,6 @@ EE158B5E1CBD47A000A3E3F0 /* WebDriverAgentLib.h */, AD6C26921CF2379700F8B5FF /* FBAlert.h */, AD6C26931CF2379700F8B5FF /* FBAlert.m */, - EE9AB7661CAEDF0C008C271F /* FBApplication.h */, - EE9AB7671CAEDF0C008C271F /* FBApplication.m */, EE3A18641CDE734B00DE4205 /* FBKeyboard.h */, EE3A18651CDE734B00DE4205 /* FBKeyboard.m */, EE158B5D1CBD479000A3E3F0 /* Info.plist */, @@ -2283,7 +2275,6 @@ 641EE64D2240C5CA00173FCB /* XCTRunnerDaemonSession.h in Headers */, 714E14B929805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.h in Headers */, 64B2650B228CE4FF002A5025 /* FBTVNavigationTracker-Private.h in Headers */, - 641EE64E2240C5CA00173FCB /* FBApplication.h in Headers */, 641EE64F2240C5CA00173FCB /* XCTestExpectationWaiter.h in Headers */, 13DE7A5C287CA444003243C6 /* FBXCElementSnapshotWrapper+Helpers.h in Headers */, 641EE6502240C5CA00173FCB /* UIGestureRecognizer-RecordingAdditions.h in Headers */, @@ -2515,7 +2506,6 @@ EE35AD601E3B77D600A02D78 /* XCTRunnerDaemonSession.h in Headers */, 71414ED62670A1EE003A8C5D /* LRUCacheNode.h in Headers */, 64B2650A228CE4FF002A5025 /* FBTVNavigationTracker-Private.h in Headers */, - EE158AF51CBD456F00A3E3F0 /* FBApplication.h in Headers */, 71B155DF23080CA600646AFB /* FBProtocolHelpers.h in Headers */, EE35AD4B1E3B77D600A02D78 /* XCTestExpectationWaiter.h in Headers */, EE35AD1E1E3B77D600A02D78 /* UIGestureRecognizer-RecordingAdditions.h in Headers */, @@ -3158,7 +3148,6 @@ 641EE61F2240C5CA00173FCB /* FBXCodeCompatibility.m in Sources */, 71E75E70254824230099FC87 /* XCUIElementQuery+FBHelpers.m in Sources */, 641EE6212240C5CA00173FCB /* FBElementTypeTransformer.m in Sources */, - 641EE6222240C5CA00173FCB /* FBApplication.m in Sources */, 13DE7A5E287CA444003243C6 /* FBXCElementSnapshotWrapper+Helpers.m in Sources */, 641EE6232240C5CA00173FCB /* FBScreen.m in Sources */, 71D04DCB25356C43008A052C /* XCUIElement+FBCaching.m in Sources */, @@ -3292,7 +3281,6 @@ E444DC9D249131D40060D7EB /* HTTPMessage.m in Sources */, E444DCB024913C220060D7EB /* RouteResponse.m in Sources */, 71D3B3D7267FC7260076473D /* XCUIElement+FBResolve.m in Sources */, - EE158AF61CBD456F00A3E3F0 /* FBApplication.m in Sources */, 715AFAC21FFA29180053896D /* FBScreen.m in Sources */, 71B155DC230711E900646AFB /* FBCommandStatus.m in Sources */, EE35AD7C1E3B80C000A02D78 /* FBXCTestDaemonsProxy.m in Sources */, @@ -3360,7 +3348,7 @@ EE9B76591CF7987800275851 /* FBRouteTests.m in Sources */, 7139145C1DF01A12005896C2 /* NSExpressionFBFormatTests.m in Sources */, 71A224E81DE326C500844D55 /* NSPredicateFBFormatTests.m in Sources */, - EE6A892B1D0B25820083E92B /* FBApplicationDouble.m in Sources */, + EE6A892B1D0B25820083E92B /* XCUIApplicationDouble.m in Sources */, 716F0DA62A17323300CDD977 /* NSDictionaryFBUtf8SafeTests.m in Sources */, EE6A892D1D0B2AF40083E92B /* FBErrorBuilderTests.m in Sources */, 712A0C851DA3E459007D02E5 /* FBXPathTests.m in Sources */, diff --git a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h index 13fabcf88..3ef66423b 100644 --- a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h +++ b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h @@ -122,6 +122,44 @@ NS_ASSUME_NONNULL_BEGIN */ - (nullable NSArray *> *)fb_performAccessibilityAuditWithAuditTypes:(uint64_t)auditTypes error:(NSError **)error; +/** + Constructor used to get current active application + */ ++ (instancetype)fb_activeApplication; + +/** + Constructor used to get current active application + + @param bundleId The bundle identifier of an app, which should be selected as active by default + if it is present in the list of active applications + */ ++ (instancetype)fb_activeApplicationWithDefaultBundleId:(nullable NSString *)bundleId; + +/** + Constructor used to get the system application (e.g. Springboard on iOS) + */ ++ (instancetype)fb_systemApplication; + +/** + Retrieves the list of all currently active applications + */ ++ (NSArray *)fb_activeApplications; + +/** + Switch to system app (called Springboard on iOS) + + @param error If there is an error, upon return contains an NSError object that describes the problem. + @return YES if the operation succeeds, otherwise NO. + */ ++ (BOOL)fb_switchToSystemApplicationWithError:(NSError **)error; + +/** + Determines whether the other app is the same as the current one + + @param otherApp Other app instance + @return YES if the other app has the same identifier + */ +- (BOOL)fb_isSameAppAs:(nullable XCUIApplication *)otherApp; @end diff --git a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m index 2656de7d6..251fb7ad9 100644 --- a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +++ b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m @@ -9,13 +9,14 @@ #import "XCUIApplication+FBHelpers.h" +#import "FBActiveAppDetectionPoint.h" #import "FBElementTypeTransformer.h" #import "FBKeyboard.h" #import "FBLogger.h" #import "FBExceptions.h" #import "FBMacros.h" #import "FBMathUtils.h" -#import "FBActiveAppDetectionPoint.h" +#import "FBRunLoopSpinner.h" #import "FBXCodeCompatibility.h" #import "FBXPath.h" #import "FBXCAccessibilityElement.h" @@ -23,14 +24,19 @@ #import "FBXCElementSnapshotWrapper+Helpers.h" #import "FBXCAXClientProxy.h" #import "FBXMLGenerationOptions.h" +#import "XCTestManager_ManagerInterface-Protocol.h" +#import "XCTestPrivateSymbols.h" +#import "XCTRunnerDaemonSession.h" +#import "XCUIApplication.h" +#import "XCUIApplicationImpl.h" +#import "XCUIApplicationProcess.h" #import "XCUIDevice+FBHelpers.h" +#import "XCUIElement.h" #import "XCUIElement+FBCaching.h" #import "XCUIElement+FBIsVisible.h" #import "XCUIElement+FBUtilities.h" #import "XCUIElement+FBWebDriverAttributes.h" -#import "XCTestManager_ManagerInterface-Protocol.h" -#import "XCTestPrivateSymbols.h" -#import "XCTRunnerDaemonSession.h" +#import "XCUIElementQuery.h" static NSString* const FBUnknownBundleId = @"unknown"; @@ -141,7 +147,7 @@ - (BOOL)fb_deactivateWithDuration:(NSTimeInterval)duration error:(NSError **)err return NO; } [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:MAX(duration, .0)]]; - [self fb_activate]; + [self activate]; return YES; } @@ -393,4 +399,141 @@ - (BOOL)fb_dismissKeyboardWithKeyNames:(nullable NSArray *)keyNames return isSuccessful ? resultArray.copy : nil; } ++ (instancetype)fb_activeApplication +{ + return [self fb_activeApplicationWithDefaultBundleId:nil]; +} + ++ (NSArray *)fb_activeApplications +{ + NSArray> *activeApplicationElements = [FBXCAXClientProxy.sharedClient activeApplications]; + NSMutableArray *result = [NSMutableArray array]; + if (activeApplicationElements.count > 0) { + for (id applicationElement in activeApplicationElements) { + XCUIApplication *app = [XCUIApplication fb_applicationWithPID:applicationElement.processIdentifier]; + if (nil != app) { + [result addObject:app]; + } + } + } + return result.count > 0 ? result.copy : @[self.class.fb_systemApplication]; +} + ++ (instancetype)fb_activeApplicationWithDefaultBundleId:(nullable NSString *)bundleId +{ + NSArray> *activeApplicationElements = [FBXCAXClientProxy.sharedClient activeApplications]; + id activeApplicationElement = nil; + id currentElement = nil; + if (nil != bundleId) { + currentElement = FBActiveAppDetectionPoint.sharedInstance.axElement; + if (nil != currentElement) { + NSArray *appInfos = [self fb_appsInfoWithAxElements:@[currentElement]]; + [FBLogger logFmt:@"Detected on-screen application: %@", appInfos.firstObject[@"bundleId"]]; + if ([[appInfos.firstObject objectForKey:@"bundleId"] isEqualToString:(id)bundleId]) { + activeApplicationElement = currentElement; + } + } + } + if (nil == activeApplicationElement && activeApplicationElements.count > 1) { + if (nil != bundleId) { + NSArray *appInfos = [self fb_appsInfoWithAxElements:activeApplicationElements]; + NSMutableArray *bundleIds = [NSMutableArray array]; + for (NSDictionary *appInfo in appInfos) { + [bundleIds addObject:(NSString *)appInfo[@"bundleId"]]; + } + [FBLogger logFmt:@"Detected system active application(s): %@", bundleIds]; + // Try to select the desired application first + for (NSUInteger appIdx = 0; appIdx < appInfos.count; appIdx++) { + if ([[[appInfos objectAtIndex:appIdx] objectForKey:@"bundleId"] isEqualToString:(id)bundleId]) { + activeApplicationElement = [activeApplicationElements objectAtIndex:appIdx]; + break; + } + } + } + // Fall back to the "normal" algorithm if the desired application is either + // not set or is not active + if (nil == activeApplicationElement) { + if (nil == currentElement) { + currentElement = FBActiveAppDetectionPoint.sharedInstance.axElement; + } + if (nil == currentElement) { + [FBLogger log:@"Cannot precisely detect the current application. Will use the system's recently active one"]; + if (nil == bundleId) { + [FBLogger log:@"Consider changing the 'defaultActiveApplication' setting to the bundle identifier of the desired application under test"]; + } + } else { + for (id appElement in activeApplicationElements) { + if (appElement.processIdentifier == currentElement.processIdentifier) { + activeApplicationElement = appElement; + break; + } + } + } + } + } + + if (nil != activeApplicationElement) { + XCUIApplication *application = [XCUIApplication fb_applicationWithPID:activeApplicationElement.processIdentifier]; + if (nil != application) { + return application; + } + [FBLogger log:@"Cannot translate the active process identifier into an application object"]; + } + + if (activeApplicationElements.count > 0) { + [FBLogger logFmt:@"Getting the most recent active application (out of %@ total items)", @(activeApplicationElements.count)]; + for (id appElement in activeApplicationElements) { + XCUIApplication *application = [XCUIApplication fb_applicationWithPID:appElement.processIdentifier]; + if (nil != application) { + return application; + } + } + } + + [FBLogger log:@"Cannot retrieve any active applications. Assuming the system application is the active one"]; + return [self fb_systemApplication]; +} + ++ (instancetype)fb_systemApplication +{ + return [self fb_applicationWithPID: + [[FBXCAXClientProxy.sharedClient systemApplication] processIdentifier]]; +} + ++ (instancetype)fb_applicationWithPID:(pid_t)processID +{ + return [FBXCAXClientProxy.sharedClient monitoredApplicationWithProcessIdentifier:processID]; +} + ++ (BOOL)fb_switchToSystemApplicationWithError:(NSError **)error +{ + XCUIApplication *systemApp = self.fb_systemApplication; + @try { + if (!systemApp.running) { + [systemApp launch]; + } else { + [systemApp activate]; + } + } @catch (NSException *e) { + return [[[FBErrorBuilder alloc] + withDescription:nil == e ? @"Cannot open the home screen" : e.reason] + buildError:error]; + } + return [[[[FBRunLoopSpinner new] + timeout:5] + timeoutErrorMessage:@"Timeout waiting until the home screen is visible"] + spinUntilTrue:^BOOL{ + return [systemApp fb_isSameAppAs:self.fb_activeApplication]; + } + error:error]; +} + +- (BOOL)fb_isSameAppAs:(nullable XCUIApplication *)otherApp +{ + if (nil == otherApp) { + return NO; + } + return [self.bundleID isEqualToString:(NSString *)otherApp.bundleID]; +} + @end diff --git a/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m b/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m index 959ae2831..5b95b8c62 100644 --- a/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m +++ b/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m @@ -56,7 +56,7 @@ + (void)fb_registerAppforDetectLockState - (BOOL)fb_goToHomescreenWithError:(NSError **)error { - return [FBApplication fb_switchToSystemApplicationWithError:error]; + return [XCUIApplication fb_switchToSystemApplicationWithError:error]; } - (BOOL)fb_lockScreen:(NSError **)error diff --git a/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.h b/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.h index 79271e628..993c301c7 100644 --- a/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.h +++ b/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.h @@ -8,7 +8,6 @@ */ #import -#import NS_ASSUME_NONNULL_BEGIN diff --git a/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.m b/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.m index cff45cf6a..68b9b20a9 100644 --- a/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.m +++ b/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.m @@ -10,6 +10,8 @@ #import "XCUIDevice+FBRotation.h" #import "FBConfiguration.h" +#import "XCUIApplication.h" +#import "XCUIApplication+FBHelpers.h" #import "XCUIElement+FBUtilities.h" # if !TARGET_OS_TV @@ -18,7 +20,7 @@ @implementation XCUIDevice (FBRotation) - (BOOL)fb_setDeviceInterfaceOrientation:(UIDeviceOrientation)orientation { - FBApplication *application = FBApplication.fb_activeApplication; + XCUIApplication *application = XCUIApplication.fb_activeApplication; [XCUIDevice sharedDevice].orientation = orientation; return [self waitUntilInterfaceIsAtOrientation:orientation application:application]; } @@ -30,12 +32,12 @@ - (BOOL)fb_setDeviceRotation:(NSDictionary *)rotationObj return NO; } NSInteger orientation = keysForRotationObj.firstObject.integerValue; - FBApplication *application = FBApplication.fb_activeApplication; + XCUIApplication *application = XCUIApplication.fb_activeApplication; [XCUIDevice sharedDevice].orientation = orientation; return [self waitUntilInterfaceIsAtOrientation:orientation application:application]; } -- (BOOL)waitUntilInterfaceIsAtOrientation:(NSInteger)orientation application:(FBApplication *)application +- (BOOL)waitUntilInterfaceIsAtOrientation:(NSInteger)orientation application:(XCUIApplication *)application { // Tapping elements immediately after rotation may fail due to way UIKit is handling touches. // We should wait till UI cools off, before continuing diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBTVFocuse.m b/WebDriverAgentLib/Categories/XCUIElement+FBTVFocuse.m index 9c82515ad..30037646d 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBTVFocuse.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBTVFocuse.m @@ -10,10 +10,10 @@ #import "XCUIElement+FBTVFocuse.h" #import -#import "FBApplication.h" #import "FBConfiguration.h" #import "FBErrorBuilder.h" #import +#import "XCUIApplication+FBHelpers.h" #import "XCUIElement+FBUtilities.h" #import "XCUIElement+FBWebDriverAttributes.h" @@ -25,7 +25,7 @@ @implementation XCUIElement (FBTVFocuse) - (BOOL)fb_setFocusWithError:(NSError**) error { - [FBApplication.fb_activeApplication fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout]; + [XCUIApplication.fb_activeApplication fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout]; if (!self.wdEnabled) { if (error) { diff --git a/WebDriverAgentLib/Commands/FBAlertViewCommands.m b/WebDriverAgentLib/Commands/FBAlertViewCommands.m index dd195fbb8..760244629 100644 --- a/WebDriverAgentLib/Commands/FBAlertViewCommands.m +++ b/WebDriverAgentLib/Commands/FBAlertViewCommands.m @@ -10,9 +10,9 @@ #import "FBAlertViewCommands.h" #import "FBAlert.h" -#import "FBApplication.h" #import "FBRouteRequest.h" #import "FBSession.h" +#import "XCUIApplication+FBHelpers.h" @implementation FBAlertViewCommands @@ -38,7 +38,7 @@ + (NSArray *)routes + (id)handleAlertGetTextCommand:(FBRouteRequest *)request { - FBApplication *application = request.session.activeApplication ?: FBApplication.fb_activeApplication; + XCUIApplication *application = request.session.activeApplication ?: XCUIApplication.fb_activeApplication; NSString *alertText = [FBAlert alertWithApplication:application].text; if (!alertText) { return FBResponseWithStatus([FBCommandStatus noAlertOpenErrorWithMessage:nil @@ -73,7 +73,7 @@ + (NSArray *)routes + (id)handleAlertAcceptCommand:(FBRouteRequest *)request { - FBApplication *application = request.session.activeApplication ?: FBApplication.fb_activeApplication; + XCUIApplication *application = request.session.activeApplication ?: XCUIApplication.fb_activeApplication; NSString *name = request.arguments[@"name"]; FBAlert *alert = [FBAlert alertWithApplication:application]; NSError *error; @@ -96,7 +96,7 @@ + (NSArray *)routes + (id)handleAlertDismissCommand:(FBRouteRequest *)request { - FBApplication *application = request.session.activeApplication ?: FBApplication.fb_activeApplication; + XCUIApplication *application = request.session.activeApplication ?: XCUIApplication.fb_activeApplication; NSString *name = request.arguments[@"name"]; FBAlert *alert = [FBAlert alertWithApplication:application]; NSError *error; diff --git a/WebDriverAgentLib/Commands/FBCustomCommands.m b/WebDriverAgentLib/Commands/FBCustomCommands.m index 5b1ce72ae..f31c96739 100644 --- a/WebDriverAgentLib/Commands/FBCustomCommands.m +++ b/WebDriverAgentLib/Commands/FBCustomCommands.m @@ -12,7 +12,6 @@ #import #import -#import "FBApplication.h" #import "FBConfiguration.h" #import "FBKeyboard.h" #import "FBNotificationsHelper.h" @@ -24,6 +23,7 @@ #import "FBScreen.h" #import "FBSession.h" #import "FBXCodeCompatibility.h" +#import "XCUIApplication.h" #import "XCUIApplication+FBHelpers.h" #import "XCUIDevice+FBHelpers.h" #import "XCUIElement.h" @@ -171,7 +171,7 @@ + (NSArray *)routes + (id)handleActiveAppInfo:(FBRouteRequest *)request { - XCUIApplication *app = request.session.activeApplication ?: FBApplication.fb_activeApplication; + XCUIApplication *app = request.session.activeApplication ?: XCUIApplication.fb_activeApplication; return FBResponseWithObject(@{ @"pid": @(app.processID), @"bundleId": app.bundleID, diff --git a/WebDriverAgentLib/Commands/FBDebugCommands.m b/WebDriverAgentLib/Commands/FBDebugCommands.m index d290ebe6c..dc96958d0 100644 --- a/WebDriverAgentLib/Commands/FBDebugCommands.m +++ b/WebDriverAgentLib/Commands/FBDebugCommands.m @@ -9,7 +9,6 @@ #import "FBDebugCommands.h" -#import "FBApplication.h" #import "FBRouteRequest.h" #import "FBSession.h" #import "FBXMLGenerationOptions.h" @@ -42,7 +41,7 @@ + (NSArray *)routes + (id)handleGetSourceCommand:(FBRouteRequest *)request { // This method might be called without session - FBApplication *application = request.session.activeApplication ?: FBApplication.fb_activeApplication; + XCUIApplication *application = request.session.activeApplication ?: XCUIApplication.fb_activeApplication; NSString *sourceType = request.parameters[@"format"] ?: SOURCE_FORMAT_XML; NSString *sourceScope = request.parameters[@"scope"]; id result; @@ -71,7 +70,7 @@ + (NSArray *)routes + (id)handleGetAccessibleSourceCommand:(FBRouteRequest *)request { // This method might be called without session - FBApplication *application = request.session.activeApplication ?: FBApplication.fb_activeApplication; + XCUIApplication *application = request.session.activeApplication ?: XCUIApplication.fb_activeApplication; return FBResponseWithObject(application.fb_accessibilityTree ?: @{}); } diff --git a/WebDriverAgentLib/Commands/FBElementCommands.m b/WebDriverAgentLib/Commands/FBElementCommands.m index a749c00a7..4d5a69ea3 100644 --- a/WebDriverAgentLib/Commands/FBElementCommands.m +++ b/WebDriverAgentLib/Commands/FBElementCommands.m @@ -9,7 +9,6 @@ #import "FBElementCommands.h" -#import "FBApplication.h" #import "FBConfiguration.h" #import "FBKeyboard.h" #import "FBRoute.h" @@ -18,7 +17,6 @@ #import "FBElementCache.h" #import "FBErrorBuilder.h" #import "FBSession.h" -#import "FBApplication.h" #import "FBElementUtils.h" #import "FBMacros.h" #import "FBMathUtils.h" @@ -529,7 +527,7 @@ + (NSArray *)routes { XCUIElement *element = nil; if (nil == request.parameters[@"uuid"]) { - element = [FBApplication fb_activeApplication]; + element = XCUIApplication.fb_activeApplication; } else { FBElementCache *elementCache = request.session.elementCache; element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; @@ -567,7 +565,7 @@ + (NSArray *)routes + (id)handleGetWindowSize:(FBRouteRequest *)request { - XCUIApplication *app = request.session.activeApplication ?: FBApplication.fb_activeApplication; + XCUIApplication *app = request.session.activeApplication ?: XCUIApplication.fb_activeApplication; #if TARGET_OS_TV CGSize screenSize = app.frame.size; diff --git a/WebDriverAgentLib/Commands/FBFindElementCommands.m b/WebDriverAgentLib/Commands/FBFindElementCommands.m index 037dbae15..ba30a7170 100644 --- a/WebDriverAgentLib/Commands/FBFindElementCommands.m +++ b/WebDriverAgentLib/Commands/FBFindElementCommands.m @@ -10,7 +10,6 @@ #import "FBFindElementCommands.h" #import "FBAlert.h" -#import "FBApplication.h" #import "FBConfiguration.h" #import "FBElementCache.h" #import "FBExceptions.h" diff --git a/WebDriverAgentLib/Commands/FBOrientationCommands.m b/WebDriverAgentLib/Commands/FBOrientationCommands.m index 185b6f2f3..aa4de26f7 100644 --- a/WebDriverAgentLib/Commands/FBOrientationCommands.m +++ b/WebDriverAgentLib/Commands/FBOrientationCommands.m @@ -12,7 +12,8 @@ #import "FBRouteRequest.h" #import "FBMacros.h" #import "FBSession.h" -#import "FBApplication.h" +#import "XCUIApplication.h" +#import "XCUIApplication+FBHelpers.h" #import "XCUIDevice.h" extern const struct FBWDOrientationValues { @@ -55,14 +56,14 @@ + (NSArray *)routes + (id)handleGetOrientation:(FBRouteRequest *)request { - FBApplication *application = request.session.activeApplication ?: FBApplication.fb_activeApplication; + XCUIApplication *application = request.session.activeApplication ?: XCUIApplication.fb_activeApplication; NSString *orientation = [self.class interfaceOrientationForApplication:application]; return FBResponseWithObject([[self _wdOrientationsMapping] objectForKey:orientation]); } + (id)handleSetOrientation:(FBRouteRequest *)request { - FBApplication *application = request.session.activeApplication ?: FBApplication.fb_activeApplication; + XCUIApplication *application = request.session.activeApplication ?: XCUIApplication.fb_activeApplication; if ([self.class setDeviceOrientation:request.arguments[@"orientation"] forApplication:application]) { return FBResponseWithOK(); } @@ -73,7 +74,7 @@ + (NSArray *)routes + (id)handleGetRotation:(FBRouteRequest *)request { XCUIDevice *device = [XCUIDevice sharedDevice]; - FBApplication *application = request.session.activeApplication ?: FBApplication.fb_activeApplication; + XCUIApplication *application = request.session.activeApplication ?: XCUIApplication.fb_activeApplication; UIInterfaceOrientation orientation = application.interfaceOrientation; return FBResponseWithObject(device.fb_rotationMapping[@(orientation)]); } @@ -101,7 +102,7 @@ + (NSArray *)routes traceback:nil]); } - FBApplication *application = request.session.activeApplication ?: FBApplication.fb_activeApplication; + XCUIApplication *application = request.session.activeApplication ?: XCUIApplication.fb_activeApplication; if (![self.class setDeviceRotation:request.arguments forApplication:application]) { NSString *errMessage = [ NSString stringWithFormat:@"The current rotation cannot be set to %@. Make sure the %@ application supports it", @@ -116,7 +117,7 @@ + (NSArray *)routes #pragma mark - Helpers -+ (NSString *)interfaceOrientationForApplication:(FBApplication *)application ++ (NSString *)interfaceOrientationForApplication:(XCUIApplication *)application { NSNumber *orientation = @(application.interfaceOrientation); NSSet *keys = [[self _orientationsMapping] keysOfEntriesPassingTest:^BOOL(id key, NSNumber *obj, BOOL *stop) { @@ -128,12 +129,12 @@ + (NSString *)interfaceOrientationForApplication:(FBApplication *)application return keys.anyObject; } -+ (BOOL)setDeviceRotation:(NSDictionary *)rotationObj forApplication:(FBApplication *)application ++ (BOOL)setDeviceRotation:(NSDictionary *)rotationObj forApplication:(XCUIApplication *)application { return [[XCUIDevice sharedDevice] fb_setDeviceRotation:rotationObj]; } -+ (BOOL)setDeviceOrientation:(NSString *)orientation forApplication:(FBApplication *)application ++ (BOOL)setDeviceOrientation:(NSString *)orientation forApplication:(XCUIApplication *)application { NSNumber *orientationValue = [[self _orientationsMapping] objectForKey:[orientation uppercaseString]]; if (orientationValue == nil) { diff --git a/WebDriverAgentLib/Commands/FBSessionCommands.m b/WebDriverAgentLib/Commands/FBSessionCommands.m index 4a7ae1a8d..f5abdc55a 100644 --- a/WebDriverAgentLib/Commands/FBSessionCommands.m +++ b/WebDriverAgentLib/Commands/FBSessionCommands.m @@ -9,7 +9,6 @@ #import "FBSessionCommands.h" -#import "FBApplication.h" #import "FBCapabilities.h" #import "FBConfiguration.h" #import "FBLogger.h" @@ -17,7 +16,6 @@ #import "FBRouteRequest.h" #import "FBSession.h" #import "FBSettings.h" -#import "FBApplication.h" #import "FBRuntimeUtils.h" #import "FBActiveAppDetectionPoint.h" #import "FBXCodeCompatibility.h" @@ -138,15 +136,15 @@ + (NSArray *)routes } NSString *bundleID = capabilities[FB_CAP_BUNDLE_ID]; - FBApplication *app = nil; + XCUIApplication *app = nil; if (bundleID != nil) { - app = [[FBApplication alloc] initWithBundleIdentifier:bundleID]; + app = [[XCUIApplication alloc] initWithBundleIdentifier:bundleID]; BOOL forceAppLaunch = YES; if (nil != capabilities[FB_CAP_FORCE_APP_LAUNCH]) { forceAppLaunch = [capabilities[FB_CAP_FORCE_APP_LAUNCH] boolValue]; } - NSUInteger appState = [app fb_state]; - BOOL isAppRunning = appState >= 2; + XCUIApplicationState appState = app.state; + BOOL isAppRunning = appState >= XCUIApplicationStateRunningBackground; if (!isAppRunning || (isAppRunning && forceAppLaunch)) { app.fb_shouldWaitForQuiescence = nil == capabilities[FB_CAP_SHOULD_WAIT_FOR_QUIESCENCE] || [capabilities[FB_CAP_SHOULD_WAIT_FOR_QUIESCENCE] boolValue]; @@ -158,8 +156,8 @@ + (NSArray *)routes return FBResponseWithStatus([FBCommandStatus sessionNotCreatedError:errorMsg traceback:nil]); } - } else if (appState < 4 && !forceAppLaunch) { - [app fb_activate]; + } else if (appState == XCUIApplicationStateRunningBackground && !forceAppLaunch) { + [app activate]; } } @@ -265,7 +263,7 @@ + (NSArray *)routes + (id)handleGetHealthCheck:(FBRouteRequest *)request { - if (![[XCUIDevice sharedDevice] fb_healthCheckWithApplication:[FBApplication fb_activeApplication]]) { + if (![[XCUIDevice sharedDevice] fb_healthCheckWithApplication:[XCUIApplication fb_activeApplication]]) { return FBResponseWithUnknownErrorFormat(@"Health check failed"); } return FBResponseWithOK(); diff --git a/WebDriverAgentLib/Commands/FBTouchActionCommands.m b/WebDriverAgentLib/Commands/FBTouchActionCommands.m index 64ef8eabe..3e31ddf2e 100644 --- a/WebDriverAgentLib/Commands/FBTouchActionCommands.m +++ b/WebDriverAgentLib/Commands/FBTouchActionCommands.m @@ -9,7 +9,6 @@ #import "FBTouchActionCommands.h" -#import "FBApplication.h" #import "FBRoute.h" #import "FBRouteRequest.h" #import "FBSession.h" diff --git a/WebDriverAgentLib/FBAlert.m b/WebDriverAgentLib/FBAlert.m index d692b04b2..0709e5f1f 100644 --- a/WebDriverAgentLib/FBAlert.m +++ b/WebDriverAgentLib/FBAlert.m @@ -9,12 +9,12 @@ #import "FBAlert.h" -#import "FBApplication.h" #import "FBConfiguration.h" #import "FBErrorBuilder.h" #import "FBLogger.h" #import "FBXCElementSnapshotWrapper+Helpers.h" #import "FBXCodeCompatibility.h" +#import "XCUIApplication.h" #import "XCUIApplication+FBAlert.h" #import "XCUIElement+FBClassChain.h" #import "XCUIElement+FBTyping.h" @@ -263,8 +263,8 @@ - (XCUIElement *)alertElement if (nil == self.element) { self.element = self.application.fb_alertElement; if (nil == self.element) { - FBApplication *systemApp = FBApplication.fb_systemApplication; - for (FBApplication *activeApp in FBApplication.fb_activeApplications) { + XCUIApplication *systemApp = XCUIApplication.fb_systemApplication; + for (XCUIApplication *activeApp in XCUIApplication.fb_activeApplications) { if (systemApp.processID == activeApp.processID) { self.element = activeApp.fb_alertElement; break; diff --git a/WebDriverAgentLib/FBApplication.h b/WebDriverAgentLib/FBApplication.h deleted file mode 100644 index 00adb527d..000000000 --- a/WebDriverAgentLib/FBApplication.h +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface FBApplication : XCUIApplication - -/** - Constructor used to get current active application - */ -+ (instancetype)fb_activeApplication; - -/** - Constructor used to get current active application - - @param bundleId The bundle identifier of an app, which should be selected as active by default - if it is present in the list of active applications - */ -+ (instancetype)fb_activeApplicationWithDefaultBundleId:(nullable NSString *)bundleId; - -/** - Constructor used to get the system application (e.g. Springboard on iOS) - */ -+ (instancetype)fb_systemApplication; - -/** - Retrieves the list of all currently active applications - */ -+ (NSArray *)fb_activeApplications; - -/** - Switch to system app (called Springboard on iOS) - - @param error If there is an error, upon return contains an NSError object that describes the problem. - @return YES if the operation succeeds, otherwise NO. - */ -+ (BOOL)fb_switchToSystemApplicationWithError:(NSError **)error; - -@end - -NS_ASSUME_NONNULL_END diff --git a/WebDriverAgentLib/FBApplication.m b/WebDriverAgentLib/FBApplication.m deleted file mode 100644 index fe46393fb..000000000 --- a/WebDriverAgentLib/FBApplication.m +++ /dev/null @@ -1,185 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import "FBApplication.h" - -#import "FBXCAccessibilityElement.h" -#import "FBLogger.h" -#import "FBExceptions.h" -#import "FBRunLoopSpinner.h" -#import "FBMacros.h" -#import "FBActiveAppDetectionPoint.h" -#import "FBXCodeCompatibility.h" -#import "FBXCTestDaemonsProxy.h" -#import "XCUIApplication.h" -#import "XCUIApplication+FBHelpers.h" -#import "XCUIApplicationImpl.h" -#import "XCUIApplicationProcess.h" -#import "XCUIElement.h" -#import "XCUIElementQuery.h" -#import "FBXCAXClientProxy.h" - - -static const NSTimeInterval APP_STATE_CHANGE_TIMEOUT = 5.0; - -@interface FBApplication () -@end - -@implementation FBApplication - -+ (instancetype)fb_activeApplication -{ - return [self fb_activeApplicationWithDefaultBundleId:nil]; -} - -+ (NSArray *)fb_activeApplications -{ - NSArray> *activeApplicationElements = [FBXCAXClientProxy.sharedClient activeApplications]; - NSMutableArray *result = [NSMutableArray array]; - if (activeApplicationElements.count > 0) { - for (id applicationElement in activeApplicationElements) { - FBApplication *app = [FBApplication fb_applicationWithPID:applicationElement.processIdentifier]; - if (nil != app) { - [result addObject:app]; - } - } - } - return result.count > 0 ? result.copy : @[self.class.fb_systemApplication]; -} - -+ (instancetype)fb_activeApplicationWithDefaultBundleId:(nullable NSString *)bundleId -{ - NSArray> *activeApplicationElements = [FBXCAXClientProxy.sharedClient activeApplications]; - id activeApplicationElement = nil; - id currentElement = nil; - if (nil != bundleId) { - currentElement = FBActiveAppDetectionPoint.sharedInstance.axElement; - if (nil != currentElement) { - NSArray *appInfos = [self fb_appsInfoWithAxElements:@[currentElement]]; - [FBLogger logFmt:@"Detected on-screen application: %@", appInfos.firstObject[@"bundleId"]]; - if ([[appInfos.firstObject objectForKey:@"bundleId"] isEqualToString:(id)bundleId]) { - activeApplicationElement = currentElement; - } - } - } - if (nil == activeApplicationElement && activeApplicationElements.count > 1) { - if (nil != bundleId) { - NSArray *appInfos = [self fb_appsInfoWithAxElements:activeApplicationElements]; - NSMutableArray *bundleIds = [NSMutableArray array]; - for (NSDictionary *appInfo in appInfos) { - [bundleIds addObject:(NSString *)appInfo[@"bundleId"]]; - } - [FBLogger logFmt:@"Detected system active application(s): %@", bundleIds]; - // Try to select the desired application first - for (NSUInteger appIdx = 0; appIdx < appInfos.count; appIdx++) { - if ([[[appInfos objectAtIndex:appIdx] objectForKey:@"bundleId"] isEqualToString:(id)bundleId]) { - activeApplicationElement = [activeApplicationElements objectAtIndex:appIdx]; - break; - } - } - } - // Fall back to the "normal" algorithm if the desired application is either - // not set or is not active - if (nil == activeApplicationElement) { - if (nil == currentElement) { - currentElement = FBActiveAppDetectionPoint.sharedInstance.axElement; - } - if (nil == currentElement) { - [FBLogger log:@"Cannot precisely detect the current application. Will use the system's recently active one"]; - if (nil == bundleId) { - [FBLogger log:@"Consider changing the 'defaultActiveApplication' setting to the bundle identifier of the desired application under test"]; - } - } else { - for (id appElement in activeApplicationElements) { - if (appElement.processIdentifier == currentElement.processIdentifier) { - activeApplicationElement = appElement; - break; - } - } - } - } - } - - if (nil != activeApplicationElement) { - FBApplication *application = [FBApplication fb_applicationWithPID:activeApplicationElement.processIdentifier]; - if (nil != application) { - return application; - } - [FBLogger log:@"Cannot translate the active process identifier into an application object"]; - } - - if (activeApplicationElements.count > 0) { - [FBLogger logFmt:@"Getting the most recent active application (out of %@ total items)", @(activeApplicationElements.count)]; - for (id appElement in activeApplicationElements) { - FBApplication *application = [FBApplication fb_applicationWithPID:appElement.processIdentifier]; - if (nil != application) { - return application; - } - } - } - - [FBLogger log:@"Cannot retrieve any active applications. Assuming the system application is the active one"]; - return [self fb_systemApplication]; -} - -+ (instancetype)fb_systemApplication -{ - return [self fb_applicationWithPID: - [[FBXCAXClientProxy.sharedClient systemApplication] processIdentifier]]; -} - -+ (instancetype)applicationWithPID:(pid_t)processID -{ - if ([NSProcessInfo processInfo].processIdentifier == processID) { - return nil; - } - return (FBApplication *)[FBXCAXClientProxy.sharedClient monitoredApplicationWithProcessIdentifier:processID]; -} - -- (void)launch -{ - [super launch]; - if (![self fb_waitForAppElement:APP_STATE_CHANGE_TIMEOUT]) { - [FBLogger logFmt:@"The application '%@' is not running in foreground after %.2f seconds", self.bundleID, APP_STATE_CHANGE_TIMEOUT]; - } -} - -- (void)terminate -{ - [super terminate]; - if (![self waitForState:XCUIApplicationStateNotRunning timeout:APP_STATE_CHANGE_TIMEOUT]) { - [FBLogger logFmt:@"The active application is still '%@' after %.2f seconds timeout", self.bundleID, APP_STATE_CHANGE_TIMEOUT]; - } -} - -+ (BOOL)fb_switchToSystemApplicationWithError:(NSError **)error -{ - FBApplication *systemApp = self.fb_systemApplication; - @try { - if ([systemApp fb_state] < 2) { - [systemApp launch]; - } else { - [systemApp fb_activate]; - } - } @catch (NSException *e) { - return [[[FBErrorBuilder alloc] - withDescription:nil == e ? @"Cannot open the home screen" : e.reason] - buildError:error]; - } - return [[[[FBRunLoopSpinner new] - timeout:5] - timeoutErrorMessage:@"Timeout waiting until the home screen is visible"] - spinUntilTrue:^BOOL{ - FBApplication *activeApp = self.fb_activeApplication; - return nil != activeApp && [activeApp.bundleID isEqualToString:systemApp.bundleID]; - } - error:error]; -} - -@end diff --git a/WebDriverAgentLib/Routing/FBSession.h b/WebDriverAgentLib/Routing/FBSession.h index be7f2bbba..9b73d4d16 100644 --- a/WebDriverAgentLib/Routing/FBSession.h +++ b/WebDriverAgentLib/Routing/FBSession.h @@ -9,8 +9,8 @@ #import -@class FBApplication; @class FBElementCache; +@class XCUIApplication; NS_ASSUME_NONNULL_BEGIN @@ -20,16 +20,16 @@ NS_ASSUME_NONNULL_BEGIN @interface FBSession : NSObject /*! Application tested during that session */ -@property (nonatomic, strong, readonly) FBApplication *activeApplication; +@property (nonatomic, readonly) XCUIApplication *activeApplication; /*! Session's identifier */ -@property (nonatomic, copy, readonly) NSString *identifier; +@property (nonatomic, readonly) NSString *identifier; /*! Element cache related to that session */ -@property (nonatomic, strong, readonly) FBElementCache *elementCache; +@property (nonatomic, readonly) FBElementCache *elementCache; /*! The identifier of the active application */ -@property (nonatomic, copy) NSString *defaultActiveApplication; +@property (nonatomic) NSString *defaultActiveApplication; /*! The action to apply to unexpected alerts. Either "accept"/"dismiss" or nil/empty string (by default) to do nothing */ @property (nonatomic, nullable) NSString *defaultAlertAction; @@ -57,7 +57,7 @@ NS_ASSUME_NONNULL_BEGIN @param application The application that we want to create session for @return new session */ -+ (instancetype)initWithApplication:(nullable FBApplication *)application; ++ (instancetype)initWithApplication:(nullable XCUIApplication *)application; /** Creates and saves new session for application with default alert handling behaviour @@ -66,7 +66,8 @@ NS_ASSUME_NONNULL_BEGIN @param defaultAlertAction The default reaction to on-screen alert. Either 'accept' or 'dismiss' @return new session */ -+ (instancetype)initWithApplication:(nullable FBApplication *)application defaultAlertAction:(NSString *)defaultAlertAction; ++ (instancetype)initWithApplication:(nullable XCUIApplication *)application + defaultAlertAction:(NSString *)defaultAlertAction; /** Kills application associated with that session and removes session @@ -82,12 +83,11 @@ NS_ASSUME_NONNULL_BEGIN @param arguments The optional array of application command line arguments. The arguments are going to be applied if the application was not running before. @param environment The optional dictionary of environment variables for the application, which is going to be executed. The environment variables are going to be applied if the application was not running before. @return The application instance - @throws FBApplicationMethodNotSupportedException if the method is not supported with the current XCTest SDK */ -- (FBApplication *)launchApplicationWithBundleId:(NSString *)bundleIdentifier - shouldWaitForQuiescence:(nullable NSNumber *)shouldWaitForQuiescence - arguments:(nullable NSArray *)arguments - environment:(nullable NSDictionary *)environment; +- (XCUIApplication *)launchApplicationWithBundleId:(NSString *)bundleIdentifier + shouldWaitForQuiescence:(nullable NSNumber *)shouldWaitForQuiescence + arguments:(nullable NSArray *)arguments + environment:(nullable NSDictionary *)environment; /** Activate an application with given bundle identifier in scope of current session. @@ -95,9 +95,8 @@ NS_ASSUME_NONNULL_BEGIN @param bundleIdentifier Valid bundle identifier of the application to be activated @return The application instance - @throws FBApplicationMethodNotSupportedException if the method is not supported with the current XCTest SDK */ -- (FBApplication *)activateApplicationWithBundleId:(NSString *)bundleIdentifier; +- (XCUIApplication *)activateApplicationWithBundleId:(NSString *)bundleIdentifier; /** Terminate an application with the given bundle id. The application should be previously diff --git a/WebDriverAgentLib/Routing/FBSession.m b/WebDriverAgentLib/Routing/FBSession.m index 69d0fff78..888cff8b2 100644 --- a/WebDriverAgentLib/Routing/FBSession.m +++ b/WebDriverAgentLib/Routing/FBSession.m @@ -14,7 +14,6 @@ #import "FBXCAccessibilityElement.h" #import "FBAlertsMonitor.h" -#import "FBApplication.h" #import "FBConfiguration.h" #import "FBElementCache.h" #import "FBExceptions.h" @@ -31,7 +30,7 @@ NSString *const FBDefaultApplicationAuto = @"auto"; @interface FBSession () -@property (nonatomic) NSString *testedApplicationBundleId; +@property (nullable, nonatomic) XCUIApplication *testedApplication; @property (nonatomic) BOOL isTestedApplicationExpectedToRun; @property (nonatomic) BOOL shouldAppsWaitForQuiescence; @property (nonatomic, nullable) FBAlertsMonitor *alertsMonitor; @@ -96,7 +95,7 @@ + (instancetype)sessionWithIdentifier:(NSString *)identifier return _activeSession; } -+ (instancetype)initWithApplication:(FBApplication *)application ++ (instancetype)initWithApplication:(XCUIApplication *)application { FBSession *session = [FBSession new]; session.useNativeCachingStrategy = YES; @@ -105,10 +104,10 @@ + (instancetype)initWithApplication:(FBApplication *)application session.elementsVisibilityCache = [NSMutableDictionary dictionary]; session.identifier = [[NSUUID UUID] UUIDString]; session.defaultActiveApplication = FBDefaultApplicationAuto; - session.testedApplicationBundleId = nil; + session.testedApplication = nil; session.isTestedApplicationExpectedToRun = nil != application && application.running; if (application) { - session.testedApplicationBundleId = application.bundleID; + session.testedApplication = application; session.shouldAppsWaitForQuiescence = application.fb_shouldWaitForQuiescence; } session.elementCache = [FBElementCache new]; @@ -116,7 +115,7 @@ + (instancetype)initWithApplication:(FBApplication *)application return session; } -+ (instancetype)initWithApplication:(nullable FBApplication *)application ++ (instancetype)initWithApplication:(nullable XCUIApplication *)application defaultAlertAction:(NSString *)defaultAlertAction { FBSession *session = [self.class initWithApplication:application]; @@ -138,81 +137,78 @@ - (void)kill self.alertsMonitor = nil; } - if (self.testedApplicationBundleId && [FBConfiguration shouldTerminateApp] - && ![self.testedApplicationBundleId isEqualToString:FBApplication.fb_systemApplication.bundleID]) { - FBApplication *app = [[FBApplication alloc] initWithBundleIdentifier:self.testedApplicationBundleId]; - if ([app running]) { - @try { - [app terminate]; - } @catch (NSException *e) { - [FBLogger logFmt:@"%@", e.description]; - } + if (nil != self.testedApplication + && FBConfiguration.shouldTerminateApp + && self.testedApplication.running + && ![self.testedApplication fb_isSameAppAs:XCUIApplication.fb_systemApplication]) { + @try { + [self.testedApplication terminate]; + } @catch (NSException *e) { + [FBLogger logFmt:@"%@", e.description]; } } _activeSession = nil; } -- (FBApplication *)activeApplication +- (XCUIApplication *)activeApplication { + if (nil != self.testedApplication) { + XCUIApplicationState testedAppState = self.testedApplication.state; + if (testedAppState >= XCUIApplicationStateRunningForeground) { + return (XCUIApplication *)self.testedApplication; + } + if (self.isTestedApplicationExpectedToRun && testedAppState <= XCUIApplicationStateNotRunning) { + NSString *description = [NSString stringWithFormat:@"The application under test with bundle id '%@' is not running, possibly crashed", self.testedApplication.bundleID]; + @throw [NSException exceptionWithName:FBApplicationCrashedException reason:description userInfo:nil]; + } + } + NSString *defaultBundleId = [self.defaultActiveApplication isEqualToString:FBDefaultApplicationAuto] ? nil : self.defaultActiveApplication; - FBApplication *application = [FBApplication fb_activeApplicationWithDefaultBundleId:defaultBundleId]; - FBApplication *testedApplication = nil; - if (self.testedApplicationBundleId && self.isTestedApplicationExpectedToRun) { - testedApplication = nil != application.bundleID && [application.bundleID isEqualToString:self.testedApplicationBundleId] - ? application - : [[FBApplication alloc] initWithBundleIdentifier:self.testedApplicationBundleId]; - } - if (testedApplication && !testedApplication.running) { - NSString *description = [NSString stringWithFormat:@"The application under test with bundle id '%@' is not running, possibly crashed", self.testedApplicationBundleId]; - [[NSException exceptionWithName:FBApplicationCrashedException reason:description userInfo:nil] raise]; - } - return application; + return [XCUIApplication fb_activeApplicationWithDefaultBundleId:defaultBundleId]; } -- (FBApplication *)launchApplicationWithBundleId:(NSString *)bundleIdentifier - shouldWaitForQuiescence:(nullable NSNumber *)shouldWaitForQuiescence - arguments:(nullable NSArray *)arguments - environment:(nullable NSDictionary *)environment +- (XCUIApplication *)launchApplicationWithBundleId:(NSString *)bundleIdentifier + shouldWaitForQuiescence:(nullable NSNumber *)shouldWaitForQuiescence + arguments:(nullable NSArray *)arguments + environment:(nullable NSDictionary *)environment { - FBApplication *app = [[FBApplication alloc] initWithBundleIdentifier:bundleIdentifier]; + XCUIApplication *app = [self makeApplicationWithBundleId:bundleIdentifier]; if (nil == shouldWaitForQuiescence) { // Iherit the quiescence check setting from the main app under test by default - app.fb_shouldWaitForQuiescence = nil != self.testedApplicationBundleId && self.shouldAppsWaitForQuiescence; + app.fb_shouldWaitForQuiescence = nil != self.testedApplication && self.shouldAppsWaitForQuiescence; } else { app.fb_shouldWaitForQuiescence = [shouldWaitForQuiescence boolValue]; } - if (app.fb_state < 2) { + if (!app.running) { app.launchArguments = arguments ?: @[]; app.launchEnvironment = environment ?: @{}; [app launch]; } else { - [app fb_activate]; + [app activate]; } - if (nil != self.testedApplicationBundleId - && [bundleIdentifier isEqualToString:(NSString *)self.testedApplicationBundleId]) { + if ([app fb_isSameAppAs:self.testedApplication]) { self.isTestedApplicationExpectedToRun = YES; } return app; } -- (FBApplication *)activateApplicationWithBundleId:(NSString *)bundleIdentifier +- (XCUIApplication *)activateApplicationWithBundleId:(NSString *)bundleIdentifier { - FBApplication *app = [[FBApplication alloc] initWithBundleIdentifier:bundleIdentifier]; - [app fb_activate]; + XCUIApplication *app = [self makeApplicationWithBundleId:bundleIdentifier]; + [app activate]; return app; } - (BOOL)terminateApplicationWithBundleId:(NSString *)bundleIdentifier { - FBApplication *app = [[FBApplication alloc] initWithBundleIdentifier:bundleIdentifier]; - if (nil != self.testedApplicationBundleId - && [bundleIdentifier isEqualToString:(NSString *)self.testedApplicationBundleId]) { + XCUIApplication *app = [self makeApplicationWithBundleId:bundleIdentifier]; + if ([app fb_isSameAppAs:self.testedApplication]) { self.isTestedApplicationExpectedToRun = NO; } - if (app.fb_state >= 2) { + if (app.running) { [app terminate]; return YES; } @@ -221,7 +217,14 @@ - (BOOL)terminateApplicationWithBundleId:(NSString *)bundleIdentifier - (NSUInteger)applicationStateWithBundleId:(NSString *)bundleIdentifier { - return [[FBApplication alloc] initWithBundleIdentifier:bundleIdentifier].fb_state; + return [self makeApplicationWithBundleId:bundleIdentifier].state; +} + +- (XCUIApplication *)makeApplicationWithBundleId:(NSString *)bundleIdentifier +{ + return nil != self.testedApplication && [bundleIdentifier isEqualToString:(NSString *)self.testedApplication.bundleID] + ? self.testedApplication + : [[XCUIApplication alloc] initWithBundleIdentifier:bundleIdentifier]; } @end diff --git a/WebDriverAgentLib/Utilities/FBAlertsMonitor.m b/WebDriverAgentLib/Utilities/FBAlertsMonitor.m index c2c625084..1a1b6f34c 100644 --- a/WebDriverAgentLib/Utilities/FBAlertsMonitor.m +++ b/WebDriverAgentLib/Utilities/FBAlertsMonitor.m @@ -10,9 +10,9 @@ #import "FBAlertsMonitor.h" #import "FBAlert.h" -#import "FBApplication.h" #import "FBLogger.h" #import "XCUIApplication+FBAlert.h" +#import "XCUIApplication+FBHelpers.h" static const NSTimeInterval FB_MONTORING_INTERVAL = 2.0; @@ -49,8 +49,8 @@ - (void)scheduleNextTick } dispatch_async(dispatch_get_main_queue(), ^{ - NSArray *activeApps = FBApplication.fb_activeApplications; - for (FBApplication *activeApp in activeApps) { + NSArray *activeApps = XCUIApplication.fb_activeApplications; + for (XCUIApplication *activeApp in activeApps) { XCUIElement *alertElement = nil; @try { alertElement = activeApp.fb_alertElement; diff --git a/WebDriverAgentLib/Utilities/FBKeyboard.m b/WebDriverAgentLib/Utilities/FBKeyboard.m index e1f5fdc5b..d90a68e29 100644 --- a/WebDriverAgentLib/Utilities/FBKeyboard.m +++ b/WebDriverAgentLib/Utilities/FBKeyboard.m @@ -9,8 +9,6 @@ #import "FBKeyboard.h" - -#import "FBApplication.h" #import "FBConfiguration.h" #import "FBXCTestDaemonsProxy.h" #import "FBErrorBuilder.h" @@ -25,10 +23,13 @@ @implementation FBKeyboard -+ (BOOL)waitUntilVisibleForApplication:(XCUIApplication *)app timeout:(NSTimeInterval)timeout error:(NSError **)error ++ (BOOL)waitUntilVisibleForApplication:(XCUIApplication *)app + timeout:(NSTimeInterval)timeout + error:(NSError **)error { BOOL (^isKeyboardVisible)(void) = ^BOOL(void) { - if (!app.keyboard.exists) { + XCUIElement *keyboard = app.keyboards.fb_firstMatch; + if (nil == keyboard) { return NO; } @@ -36,7 +37,7 @@ + (BOOL)waitUntilVisibleForApplication:(XCUIApplication *)app timeout:(NSTimeInt NSDictionary *bindings) { return snapshot.label.length > 0; }]; - XCUIElement *firstKey = [[app.keyboard descendantsMatchingType:XCUIElementTypeKey] + XCUIElement *firstKey = [[keyboard descendantsMatchingType:XCUIElementTypeKey] matchingPredicate:keySearchPredicate].allElementsBoundByIndex.firstObject; return firstKey.exists && firstKey.hittable; }; diff --git a/WebDriverAgentLib/Utilities/FBMjpegServer.m b/WebDriverAgentLib/Utilities/FBMjpegServer.m index 14a734c94..691e57746 100644 --- a/WebDriverAgentLib/Utilities/FBMjpegServer.m +++ b/WebDriverAgentLib/Utilities/FBMjpegServer.m @@ -13,7 +13,6 @@ @import UniformTypeIdentifiers; #import "GCDAsyncSocket.h" -#import "FBApplication.h" #import "FBConfiguration.h" #import "FBLogger.h" #import "FBScreenshot.h" diff --git a/WebDriverAgentLib/Utilities/FBPasteboard.m b/WebDriverAgentLib/Utilities/FBPasteboard.m index 6340efff3..0171b259c 100644 --- a/WebDriverAgentLib/Utilities/FBPasteboard.m +++ b/WebDriverAgentLib/Utilities/FBPasteboard.m @@ -11,9 +11,9 @@ #import #import "FBAlert.h" -#import "FBApplication.h" #import "FBErrorBuilder.h" #import "FBMacros.h" +#import "XCUIApplication+FBHelpers.h" #import "XCUIApplication+FBAlert.h" #define ALERT_TIMEOUT_SEC 30 @@ -101,7 +101,7 @@ + (nullable id)pasteboardContentForItem:(NSString *)item break; } - XCUIElement *alertElement = FBApplication.fb_systemApplication.fb_alertElement; + XCUIElement *alertElement = XCUIApplication.fb_systemApplication.fb_alertElement; if (nil != alertElement) { FBAlert *alert = [FBAlert alertWithElement:alertElement]; [alert acceptWithError:nil]; diff --git a/WebDriverAgentLib/Utilities/FBScreen.m b/WebDriverAgentLib/Utilities/FBScreen.m index e2b25855b..8ebe080d5 100644 --- a/WebDriverAgentLib/Utilities/FBScreen.m +++ b/WebDriverAgentLib/Utilities/FBScreen.m @@ -8,7 +8,6 @@ */ #import "FBScreen.h" -#import "FBApplication.h" #import "XCUIElement+FBIsVisible.h" #import "FBXCodeCompatibility.h" #import "XCUIScreen.h" @@ -22,7 +21,7 @@ + (double)scale + (CGSize)statusBarSizeForApplication:(XCUIApplication *)application { - XCUIApplication *app = FBApplication.fb_systemApplication; + XCUIApplication *app = XCUIApplication.fb_systemApplication; // Since iOS 13 the status bar is no longer part of the application, it’s part of the SpringBoard XCUIElement *mainStatusBar = app.statusBars.allElementsBoundByIndex.firstObject; if (nil == mainStatusBar) { diff --git a/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m b/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m index 7476f09bb..11becfa72 100644 --- a/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m +++ b/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m @@ -10,7 +10,6 @@ #import "FBTVNavigationTracker.h" #import "FBTVNavigationTracker-Private.h" -#import "FBApplication.h" #import "FBMathUtils.h" #import "XCUIElement+FBCaching.h" #import "XCUIElement+FBUtilities.h" @@ -69,7 +68,7 @@ - (instancetype)initWithTargetElement:(XCUIElement *)targetElement - (FBTVDirection)directionToFocusedElement { - XCUIElement *focused = FBApplication.fb_activeApplication.fb_focusedElement; + XCUIElement *focused = XCUIApplication.fb_activeApplication.fb_focusedElement; CGPoint focusedCenter = FBRectGetCenter(focused.wdFrame); FBTVNavigationItem *item = [self navigationItemWithElement:focused]; diff --git a/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h b/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h index 3922a876d..0a7dd9a0c 100644 --- a/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h +++ b/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h @@ -28,39 +28,6 @@ NSInteger FBTestmanagerdVersion(void); NS_ASSUME_NONNULL_BEGIN -/** - The exception happends if one tries to call application method, - which is not supported in the current iOS version - */ -extern NSString *const FBApplicationMethodNotSupportedException; - -@interface XCUIApplication (FBCompatibility) - -+ (nullable instancetype)fb_applicationWithPID:(pid_t)processID; - -/** - Get the state of the application. This method only returns reliable results on Xcode SDK 9+ - - @return State value as enum item. See https://developer.apple.com/documentation/xctest/xcuiapplicationstate?language=objc for more details. - */ -- (NSUInteger)fb_state; - -/** - Activate the application by restoring it from the background. - Nothing will happen if the application is already in foreground. - This method is only supported since Xcode9. - - @throws FBTimeoutException if the app is still not active after the timeout - */ -- (void)fb_activate; - -/** - Terminate the application and wait until it disappears from the list of active apps - */ -- (void)fb_terminate; - -@end - @interface XCUIElementQuery (FBCompatibility) /* Performs short-circuit UI tree traversion in iOS 11+ to get the first element matched by the query. Equals to nil if no matching elements are found */ diff --git a/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m b/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m index 4d7bb621d..b13a79e55 100644 --- a/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m +++ b/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m @@ -9,6 +9,7 @@ #import "FBXCodeCompatibility.h" +#import "FBXCAXClientProxy.h" #import "FBConfiguration.h" #import "FBErrorBuilder.h" #import "FBLogger.h" @@ -17,45 +18,6 @@ #import "FBXCTestDaemonsProxy.h" #import "XCTestManager_ManagerInterface-Protocol.h" -static const NSTimeInterval APP_STATE_CHANGE_TIMEOUT = 5.0; - -NSString *const FBApplicationMethodNotSupportedException = @"FBApplicationMethodNotSupportedException"; - -@implementation XCUIApplication (FBCompatibility) - -+ (instancetype)fb_applicationWithPID:(pid_t)processID -{ - if (0 == processID) { - return nil; - } - - return [self applicationWithPID:processID]; -} - -- (void)fb_activate -{ - [self activate]; - if (![self waitForState:XCUIApplicationStateRunningForeground timeout:APP_STATE_CHANGE_TIMEOUT / 2] || ![self fb_waitForAppElement:APP_STATE_CHANGE_TIMEOUT / 2]) { - [FBLogger logFmt:@"The application '%@' is not running in foreground after %.2f seconds", self.bundleID, APP_STATE_CHANGE_TIMEOUT]; - } -} - -- (void)fb_terminate -{ - [self terminate]; - if (![self waitForState:XCUIApplicationStateNotRunning timeout:APP_STATE_CHANGE_TIMEOUT]) { - [FBLogger logFmt:@"The active application is still '%@' after %.2f seconds timeout", self.bundleID, APP_STATE_CHANGE_TIMEOUT]; - } -} - -- (NSUInteger)fb_state -{ - return [[self valueForKey:@"state"] intValue]; -} - -@end - - @implementation XCUIElementQuery (FBCompatibility) - (XCElementSnapshot *)fb_uniqueSnapshotWithError:(NSError **)error @@ -89,7 +51,7 @@ + (BOOL)fb_supportsNonModalElementsInclusion static dispatch_once_t hasIncludingNonModalElements; static BOOL result; dispatch_once(&hasIncludingNonModalElements, ^{ - result = [FBApplication.fb_systemApplication.query respondsToSelector:@selector(includingNonModalElements)]; + result = [XCUIApplication.fb_systemApplication.query respondsToSelector:@selector(includingNonModalElements)]; }); return result; } diff --git a/WebDriverAgentLib/WebDriverAgentLib.h b/WebDriverAgentLib/WebDriverAgentLib.h index 6d9daa1f6..f14994b86 100644 --- a/WebDriverAgentLib/WebDriverAgentLib.h +++ b/WebDriverAgentLib/WebDriverAgentLib.h @@ -16,7 +16,6 @@ FOUNDATION_EXPORT double WebDriverAgentLib_VersionNumber; FOUNDATION_EXPORT const unsigned char WebDriverAgentLib_VersionString[]; #import -#import #import #import #import diff --git a/WebDriverAgentTests/IntegrationTests/FBAutoAlertsHandlerTests.m b/WebDriverAgentTests/IntegrationTests/FBAutoAlertsHandlerTests.m index 25dc39d21..c7f0b59af 100644 --- a/WebDriverAgentTests/IntegrationTests/FBAutoAlertsHandlerTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBAutoAlertsHandlerTests.m @@ -10,7 +10,6 @@ #import #import "FBIntegrationTestCase.h" -#import "FBApplication.h" #import "FBMacros.h" #import "FBSession.h" #import "FBXCodeCompatibility.h" @@ -50,7 +49,7 @@ - (void)tearDown - (void)disabled_testAutoAcceptingOfAlerts { self.session = [FBSession - initWithApplication:FBApplication.fb_activeApplication + initWithApplication:XCUIApplication.fb_activeApplication defaultAlertAction:@"accept"]; for (int i = 0; i < 2; i++) { [self.testedApplication.buttons[FBShowAlertButtonName] tap]; @@ -63,7 +62,7 @@ - (void)disabled_testAutoAcceptingOfAlerts - (void)disabled_testAutoDismissingOfAlerts { self.session = [FBSession - initWithApplication:FBApplication.fb_activeApplication + initWithApplication:XCUIApplication.fb_activeApplication defaultAlertAction:@"dismiss"]; for (int i = 0; i < 2; i++) { [self.testedApplication.buttons[FBShowAlertButtonName] tap]; diff --git a/WebDriverAgentTests/IntegrationTests/FBElementVisibilityTests.m b/WebDriverAgentTests/IntegrationTests/FBElementVisibilityTests.m index ea4fa2cee..d791e8ab5 100644 --- a/WebDriverAgentTests/IntegrationTests/FBElementVisibilityTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBElementVisibilityTests.m @@ -9,7 +9,6 @@ #import -#import "FBApplication.h" #import "FBIntegrationTestCase.h" #import "FBMacros.h" #import "FBTestMacros.h" diff --git a/WebDriverAgentTests/IntegrationTests/FBIntegrationTestCase.h b/WebDriverAgentTests/IntegrationTests/FBIntegrationTestCase.h index 1d6ee85f4..a920e167c 100644 --- a/WebDriverAgentTests/IntegrationTests/FBIntegrationTestCase.h +++ b/WebDriverAgentTests/IntegrationTests/FBIntegrationTestCase.h @@ -9,8 +9,6 @@ #import -#import "FBApplication.h" - extern NSString *const FBShowAlertButtonName; extern NSString *const FBShowSheetAlertButtonName; extern NSString *const FBShowAlertForceTouchButtonName; @@ -22,7 +20,7 @@ extern NSString *const FBTapsCountLabelIdentifier; */ @interface FBIntegrationTestCase : XCTestCase @property (nonatomic, strong, readonly) XCUIApplication *testedApplication; -@property (nonatomic, strong, readonly) FBApplication *springboard; +@property (nonatomic, strong, readonly) XCUIApplication *springboard; /** Launches application and resets side effects of testing like orientation etc. diff --git a/WebDriverAgentTests/IntegrationTests/FBIntegrationTestCase.m b/WebDriverAgentTests/IntegrationTests/FBIntegrationTestCase.m index bfcb36648..4750b79a4 100644 --- a/WebDriverAgentTests/IntegrationTests/FBIntegrationTestCase.m +++ b/WebDriverAgentTests/IntegrationTests/FBIntegrationTestCase.m @@ -10,12 +10,12 @@ #import #import "FBAlert.h" -#import "FBApplication.h" #import "FBTestMacros.h" #import "FBIntegrationTestCase.h" #import "FBConfiguration.h" #import "FBMacros.h" #import "FBRunLoopSpinner.h" +#import "XCUIApplication+FBHelpers.h" #import "XCUIDevice+FBRotation.h" #import "XCUIElement.h" #import "XCUIElement+FBIsVisible.h" @@ -30,7 +30,7 @@ @interface FBIntegrationTestCase () @property (nonatomic, strong) XCUIApplication *testedApplication; -@property (nonatomic, strong) FBApplication *springboard; +@property (nonatomic, strong) XCUIApplication *springboard; @end @implementation FBIntegrationTestCase @@ -46,7 +46,7 @@ - (void)setUp [FBConfiguration disableApplicationUIInterruptionsHandling]; [FBConfiguration disableScreenshots]; self.continueAfterFailure = NO; - self.springboard = FBApplication.fb_systemApplication; + self.springboard = XCUIApplication.fb_systemApplication; self.testedApplication = [XCUIApplication new]; } @@ -91,10 +91,10 @@ - (void)goToSpringBoardFirstPage { [[XCUIDevice sharedDevice] pressButton:XCUIDeviceButtonHome]; [self.testedApplication fb_waitUntilStable]; - FBAssertWaitTillBecomesTrue(FBApplication.fb_systemApplication.icons[@"Safari"].exists); + FBAssertWaitTillBecomesTrue(XCUIApplication.fb_systemApplication.icons[@"Safari"].exists); [[XCUIDevice sharedDevice] pressButton:XCUIDeviceButtonHome]; [self.testedApplication fb_waitUntilStable]; - FBAssertWaitTillBecomesTrue(FBApplication.fb_systemApplication.icons[@"Calendar"].firstMatch.fb_isVisible); + FBAssertWaitTillBecomesTrue(XCUIApplication.fb_systemApplication.icons[@"Calendar"].firstMatch.fb_isVisible); } - (void)goToSpringBoardExtras diff --git a/WebDriverAgentTests/IntegrationTests/FBSafariAlertTests.m b/WebDriverAgentTests/IntegrationTests/FBSafariAlertTests.m index 336ad1902..73e2de337 100644 --- a/WebDriverAgentTests/IntegrationTests/FBSafariAlertTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBSafariAlertTests.m @@ -10,7 +10,6 @@ #import #import "FBIntegrationTestCase.h" -#import "FBApplication.h" #import "FBTestMacros.h" #import "FBMacros.h" #import "FBSession.h" @@ -33,7 +32,7 @@ @implementation FBSafariAlertIntegrationTests - (void)setUp { [super setUp]; - self.session = [FBSession initWithApplication:FBApplication.fb_activeApplication]; + self.session = [FBSession initWithApplication:XCUIApplication.fb_activeApplication]; [self.session launchApplicationWithBundleId:SAFARI_BUNDLE_ID shouldWaitForQuiescence:nil arguments:nil diff --git a/WebDriverAgentTests/IntegrationTests/FBSessionIntegrationTests.m b/WebDriverAgentTests/IntegrationTests/FBSessionIntegrationTests.m index ea9fb4cfe..2df038fda 100644 --- a/WebDriverAgentTests/IntegrationTests/FBSessionIntegrationTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBSessionIntegrationTests.m @@ -10,13 +10,14 @@ #import #import "FBIntegrationTestCase.h" -#import "FBApplication.h" #import "FBExceptions.h" #import "FBMacros.h" #import "FBSession.h" #import "FBXCodeCompatibility.h" #import "FBTestMacros.h" #import "FBUnattachedAppLauncher.h" +#import "XCUIApplication+FBHelpers.h" +#import "XCUIApplication.h" @interface FBSession (Tests) @@ -35,7 +36,7 @@ - (void)setUp { [super setUp]; [self launchApplication]; - FBApplication *app = [[FBApplication alloc] initWithBundleIdentifier:self.testedApplication.bundleID]; + XCUIApplication *app = [[XCUIApplication alloc] initWithBundleIdentifier:self.testedApplication.bundleID]; self.session = [FBSession initWithApplication:app]; } @@ -47,7 +48,7 @@ - (void)tearDown - (void)testSettingsAppCanBeOpenedInScopeOfTheCurrentSession { - FBApplication *testedApp = FBApplication.fb_activeApplication; + XCUIApplication *testedApp = XCUIApplication.fb_activeApplication; [self.session launchApplicationWithBundleId:SETTINGS_BUNDLE_ID shouldWaitForQuiescence:nil arguments:nil @@ -61,7 +62,7 @@ - (void)testSettingsAppCanBeOpenedInScopeOfTheCurrentSession - (void)testSettingsAppCanBeReopenedInScopeOfTheCurrentSession { - FBApplication *systemApp = self.springboard; + XCUIApplication *systemApp = self.springboard; [self.session launchApplicationWithBundleId:SETTINGS_BUNDLE_ID shouldWaitForQuiescence:nil arguments:nil @@ -78,7 +79,7 @@ - (void)testSettingsAppCanBeReopenedInScopeOfTheCurrentSession - (void)testMainAppCanBeReactivatedInScopeOfTheCurrentSession { - FBApplication *testedApp = FBApplication.fb_activeApplication; + XCUIApplication *testedApp = XCUIApplication.fb_activeApplication; [self.session launchApplicationWithBundleId:SETTINGS_BUNDLE_ID shouldWaitForQuiescence:nil arguments:nil @@ -90,8 +91,8 @@ - (void)testMainAppCanBeReactivatedInScopeOfTheCurrentSession - (void)testMainAppCanBeRestartedInScopeOfTheCurrentSession { - FBApplication *systemApp = self.springboard; - FBApplication *testedApp = [[FBApplication alloc] initWithBundleIdentifier:self.testedApplication.bundleID]; + XCUIApplication *systemApp = self.springboard; + XCUIApplication *testedApp = [[XCUIApplication alloc] initWithBundleIdentifier:self.testedApplication.bundleID]; [self.session terminateApplicationWithBundleId:testedApp.bundleID]; FBAssertWaitTillBecomesTrue([self.session.activeApplication.bundleID isEqualToString:systemApp.bundleID]); [self.session launchApplicationWithBundleId:testedApp.bundleID @@ -105,12 +106,12 @@ - (void)testLaunchUnattachedApp { [FBUnattachedAppLauncher launchAppWithBundleId:SETTINGS_BUNDLE_ID]; [self.session kill]; - XCTAssertEqualObjects(SETTINGS_BUNDLE_ID, FBApplication.fb_activeApplication.bundleID); + XCTAssertEqualObjects(SETTINGS_BUNDLE_ID, XCUIApplication.fb_activeApplication.bundleID); } - (void)testAppWithInvalidBundleIDCannotBeStarted { - FBApplication *testedApp = [[FBApplication alloc] initWithBundleIdentifier:@"yolo"]; + XCUIApplication *testedApp = [[XCUIApplication alloc] initWithBundleIdentifier:@"yolo"]; @try { [testedApp launch]; XCTFail(@"An exception is expected to be thrown"); @@ -121,7 +122,7 @@ - (void)testAppWithInvalidBundleIDCannotBeStarted - (void)testAppWithInvalidBundleIDCannotBeActivated { - FBApplication *testedApp = [[FBApplication alloc] initWithBundleIdentifier:@"yolo"]; + XCUIApplication *testedApp = [[XCUIApplication alloc] initWithBundleIdentifier:@"yolo"]; @try { [testedApp activate]; XCTFail(@"An exception is expected to be thrown"); diff --git a/WebDriverAgentTests/IntegrationTests/FBTapTest.m b/WebDriverAgentTests/IntegrationTests/FBTapTest.m index 5b79711fc..61014d842 100644 --- a/WebDriverAgentTests/IntegrationTests/FBTapTest.m +++ b/WebDriverAgentTests/IntegrationTests/FBTapTest.m @@ -11,7 +11,6 @@ #import "FBIntegrationTestCase.h" -#import "FBApplication.h" #import "FBElementCache.h" #import "FBTestMacros.h" #import "XCUIDevice+FBRotation.h" diff --git a/WebDriverAgentTests/IntegrationTests/FBW3CMultiTouchActionsIntegrationTests.m b/WebDriverAgentTests/IntegrationTests/FBW3CMultiTouchActionsIntegrationTests.m index f25bee825..dfbbf2039 100644 --- a/WebDriverAgentTests/IntegrationTests/FBW3CMultiTouchActionsIntegrationTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBW3CMultiTouchActionsIntegrationTests.m @@ -11,7 +11,6 @@ #import "FBIntegrationTestCase.h" -#import "FBApplication.h" #import "XCUIElement.h" #import "XCUIApplication+FBTouchAction.h" #import "FBTestMacros.h" diff --git a/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m b/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m index 41ee134a1..e86f62021 100644 --- a/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m +++ b/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m @@ -11,11 +11,11 @@ #import -#import "FBApplication.h" #import "FBIntegrationTestCase.h" #import "FBElement.h" #import "FBMacros.h" #import "FBTestMacros.h" +#import "XCUIApplication.h" #import "XCUIApplication+FBHelpers.h" #import "XCUIElement+FBIsVisible.h" #import "FBXCodeCompatibility.h" @@ -34,8 +34,8 @@ - (void)setUp - (void)testQueringSpringboard { [self goToSpringBoardFirstPage]; - XCTAssertTrue(FBApplication.fb_systemApplication.icons[@"Safari"].exists); - XCTAssertTrue(FBApplication.fb_systemApplication.icons[@"Calendar"].firstMatch.exists); + XCTAssertTrue(XCUIApplication.fb_systemApplication.icons[@"Safari"].exists); + XCTAssertTrue(XCUIApplication.fb_systemApplication.icons[@"Calendar"].firstMatch.exists); } - (void)testApplicationTree @@ -58,10 +58,10 @@ - (void)testDeactivateApplication - (void)testActiveApplication { - FBApplication *systemApp = FBApplication.fb_systemApplication; - XCTAssertTrue([FBApplication fb_activeApplication].buttons[@"Alerts"].fb_isVisible); + XCUIApplication *systemApp = XCUIApplication.fb_systemApplication; + XCTAssertTrue([XCUIApplication fb_activeApplication].buttons[@"Alerts"].fb_isVisible); [self goToSpringBoardFirstPage]; - XCTAssertEqualObjects([FBApplication fb_activeApplication].bundleID, systemApp.bundleID); + XCTAssertEqualObjects([XCUIApplication fb_activeApplication].bundleID, systemApp.bundleID); XCTAssertTrue(systemApp.icons[@"Safari"].fb_isVisible); } @@ -102,14 +102,14 @@ - (void)testAccessbilityAudit } NSError *error; - NSArray *auditIssues1 = [FBApplication.fb_activeApplication fb_performAccessibilityAuditWithAuditTypes:~0UL + NSArray *auditIssues1 = [XCUIApplication.fb_activeApplication fb_performAccessibilityAuditWithAuditTypes:~0UL error:&error]; XCTAssertNotNil(auditIssues1); XCTAssertNil(error); NSMutableSet *set = [NSMutableSet new]; [set addObject:@"XCUIAccessibilityAuditTypeAll"]; - NSArray *auditIssues2 = [FBApplication.fb_activeApplication fb_performAccessibilityAuditWithAuditTypesSet:set.copy + NSArray *auditIssues2 = [XCUIApplication.fb_activeApplication fb_performAccessibilityAuditWithAuditTypesSet:set.copy error:&error]; XCTAssertEqualObjects(auditIssues1, auditIssues2); XCTAssertNil(error); diff --git a/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m b/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m index ca79b2fa4..548bd70a5 100644 --- a/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m +++ b/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m @@ -9,11 +9,12 @@ #import -#import "FBApplication.h" #import "FBIntegrationTestCase.h" #import "FBImageUtils.h" #import "FBMacros.h" #import "FBTestMacros.h" +#import "XCUIApplication.h" +#import "XCUIApplication+FBHelpers.h" #import "XCUIDevice+FBHelpers.h" #import "XCUIDevice+FBRotation.h" #import "XCUIScreen.h" @@ -101,7 +102,7 @@ - (void)testGoToHomeScreen NSError *error; XCTAssertTrue([[XCUIDevice sharedDevice] fb_goToHomescreenWithError:&error]); XCTAssertNil(error); - XCTAssertTrue([FBApplication fb_activeApplication].icons[@"Safari"].exists); + XCTAssertTrue([XCUIApplication fb_activeApplication].icons[@"Safari"].exists); } - (void)testLockUnlockScreen @@ -124,7 +125,7 @@ - (void)testUrlSchemeActivation NSError *error; XCTAssertTrue([XCUIDevice.sharedDevice fb_openUrl:@"https://apple.com" error:&error]); - FBAssertWaitTillBecomesTrue([FBApplication.fb_activeApplication.bundleID isEqualToString:@"com.apple.mobilesafari"]); + FBAssertWaitTillBecomesTrue([XCUIApplication.fb_activeApplication.bundleID isEqualToString:@"com.apple.mobilesafari"]); XCTAssertNil(error); } @@ -138,7 +139,7 @@ - (void)testUrlSchemeActivationWithApp XCTAssertTrue([XCUIDevice.sharedDevice fb_openUrl:@"https://apple.com" withApplication:@"com.apple.mobilesafari" error:&error]); - FBAssertWaitTillBecomesTrue([FBApplication.fb_activeApplication.bundleID isEqualToString:@"com.apple.mobilesafari"]); + FBAssertWaitTillBecomesTrue([XCUIApplication.fb_activeApplication.bundleID isEqualToString:@"com.apple.mobilesafari"]); XCTAssertNil(error); } diff --git a/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m b/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m index f2d6d3a60..496bd353d 100644 --- a/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m +++ b/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m @@ -10,7 +10,6 @@ #import #import "XCTest/XCUIElementTypes.h" -#import "FBApplication.h" #import "FBIntegrationTestCase.h" #import "FBTestMacros.h" #import "FBElement.h" diff --git a/WebDriverAgentTests/UnitTests/Doubles/FBApplicationDouble.h b/WebDriverAgentTests/UnitTests/Doubles/XCUIApplicationDouble.h similarity index 92% rename from WebDriverAgentTests/UnitTests/Doubles/FBApplicationDouble.h rename to WebDriverAgentTests/UnitTests/Doubles/XCUIApplicationDouble.h index d9906899a..ed25ced3f 100644 --- a/WebDriverAgentTests/UnitTests/Doubles/FBApplicationDouble.h +++ b/WebDriverAgentTests/UnitTests/Doubles/XCUIApplicationDouble.h @@ -9,7 +9,7 @@ #import -@interface FBApplicationDouble : NSObject +@interface XCUIApplicationDouble : NSObject @property (nonatomic, assign, readonly) BOOL didTerminate; @property (nonatomic, strong) NSString* bundleID; @property (nonatomic) BOOL fb_shouldWaitForQuiescence; diff --git a/WebDriverAgentTests/UnitTests/Doubles/FBApplicationDouble.m b/WebDriverAgentTests/UnitTests/Doubles/XCUIApplicationDouble.m similarity index 88% rename from WebDriverAgentTests/UnitTests/Doubles/FBApplicationDouble.m rename to WebDriverAgentTests/UnitTests/Doubles/XCUIApplicationDouble.m index d5b029a44..3f61b023c 100644 --- a/WebDriverAgentTests/UnitTests/Doubles/FBApplicationDouble.m +++ b/WebDriverAgentTests/UnitTests/Doubles/XCUIApplicationDouble.m @@ -7,13 +7,13 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import "FBApplicationDouble.h" +#import "XCUIApplicationDouble.h" -@interface FBApplicationDouble () +@interface XCUIApplicationDouble () @property (nonatomic, assign, readwrite) BOOL didTerminate; @end -@implementation FBApplicationDouble +@implementation XCUIApplicationDouble - (instancetype)init { diff --git a/WebDriverAgentTests/UnitTests/FBSessionTests.m b/WebDriverAgentTests/UnitTests/FBSessionTests.m index c7ae281cc..226e965b6 100644 --- a/WebDriverAgentTests/UnitTests/FBSessionTests.m +++ b/WebDriverAgentTests/UnitTests/FBSessionTests.m @@ -9,13 +9,13 @@ #import -#import "FBApplicationDouble.h" #import "FBSession.h" #import "FBConfiguration.h" +#import "XCUIApplicationDouble.h" @interface FBSessionTests : XCTestCase @property (nonatomic, strong) FBSession *session; -@property (nonatomic, strong) FBApplication *testedApplication; +@property (nonatomic, strong) XCUIApplication *testedApplication; @property (nonatomic) BOOL shouldTerminateAppValue; @end @@ -24,7 +24,7 @@ @implementation FBSessionTests - (void)setUp { [super setUp]; - self.testedApplication = (id)FBApplicationDouble.new; + self.testedApplication = (id)XCUIApplicationDouble.new; self.shouldTerminateAppValue = FBConfiguration.shouldTerminateApp; [FBConfiguration setShouldTerminateApp:NO]; self.session = [FBSession initWithApplication:self.testedApplication];