appium-webdriveragent 5.15.7 → 5.15.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/PrivateHeaders/XCTest/XCUIApplication.h +1 -0
- package/WebDriverAgent.xcodeproj/project.pbxproj +18 -6
- package/WebDriverAgent.xcodeproj/project.xcworkspace/xcuserdata/kazu.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/WebDriverAgent.xcodeproj/xcuserdata/kazu.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +1342 -0
- package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h +0 -38
- package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +5 -148
- package/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m +1 -1
- package/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.h +1 -0
- package/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.m +3 -5
- package/WebDriverAgentLib/Categories/XCUIElement+FBTVFocuse.m +2 -2
- package/WebDriverAgentLib/Commands/FBAlertViewCommands.m +4 -4
- package/WebDriverAgentLib/Commands/FBCustomCommands.m +2 -2
- package/WebDriverAgentLib/Commands/FBDebugCommands.m +3 -2
- package/WebDriverAgentLib/Commands/FBElementCommands.m +4 -2
- package/WebDriverAgentLib/Commands/FBFindElementCommands.m +1 -0
- package/WebDriverAgentLib/Commands/FBOrientationCommands.m +8 -9
- package/WebDriverAgentLib/Commands/FBSessionCommands.m +9 -7
- package/WebDriverAgentLib/Commands/FBTouchActionCommands.m +1 -0
- package/WebDriverAgentLib/FBAlert.m +3 -3
- package/WebDriverAgentLib/FBApplication.h +49 -0
- package/WebDriverAgentLib/FBApplication.m +185 -0
- package/WebDriverAgentLib/Routing/FBSession.h +14 -13
- package/WebDriverAgentLib/Routing/FBSession.m +46 -49
- package/WebDriverAgentLib/Utilities/FBAlertsMonitor.m +3 -3
- package/WebDriverAgentLib/Utilities/FBKeyboard.m +5 -6
- package/WebDriverAgentLib/Utilities/FBMjpegServer.m +1 -0
- package/WebDriverAgentLib/Utilities/FBPasteboard.m +2 -2
- package/WebDriverAgentLib/Utilities/FBScreen.m +2 -1
- package/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m +2 -1
- package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h +33 -0
- package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m +40 -2
- package/WebDriverAgentLib/WebDriverAgentLib.h +1 -0
- package/WebDriverAgentTests/IntegrationTests/FBAutoAlertsHandlerTests.m +3 -2
- package/WebDriverAgentTests/IntegrationTests/FBElementVisibilityTests.m +1 -0
- package/WebDriverAgentTests/IntegrationTests/FBIntegrationTestCase.h +3 -1
- package/WebDriverAgentTests/IntegrationTests/FBIntegrationTestCase.m +5 -5
- package/WebDriverAgentTests/IntegrationTests/FBSafariAlertTests.m +2 -1
- package/WebDriverAgentTests/IntegrationTests/FBSessionIntegrationTests.m +10 -11
- package/WebDriverAgentTests/IntegrationTests/FBTapTest.m +1 -0
- package/WebDriverAgentTests/IntegrationTests/FBW3CMultiTouchActionsIntegrationTests.m +1 -0
- package/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m +8 -8
- package/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m +4 -5
- package/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m +1 -0
- package/WebDriverAgentTests/UnitTests/Doubles/{XCUIApplicationDouble.h → FBApplicationDouble.h} +1 -1
- package/WebDriverAgentTests/UnitTests/Doubles/{XCUIApplicationDouble.m → FBApplicationDouble.m} +3 -3
- package/WebDriverAgentTests/UnitTests/FBSessionTests.m +3 -3
- package/build/lib/utils.d.ts +2 -2
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +7 -5
- package/build/lib/utils.js.map +1 -1
- package/lib/utils.js +7 -5
- package/package.json +1 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the BSD-style license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree. An additional grant
|
|
7
|
+
* of patent rights can be found in the PATENTS file in the same directory.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#import "FBApplication.h"
|
|
11
|
+
|
|
12
|
+
#import "FBXCAccessibilityElement.h"
|
|
13
|
+
#import "FBLogger.h"
|
|
14
|
+
#import "FBExceptions.h"
|
|
15
|
+
#import "FBRunLoopSpinner.h"
|
|
16
|
+
#import "FBMacros.h"
|
|
17
|
+
#import "FBActiveAppDetectionPoint.h"
|
|
18
|
+
#import "FBXCodeCompatibility.h"
|
|
19
|
+
#import "FBXCTestDaemonsProxy.h"
|
|
20
|
+
#import "XCUIApplication.h"
|
|
21
|
+
#import "XCUIApplication+FBHelpers.h"
|
|
22
|
+
#import "XCUIApplicationImpl.h"
|
|
23
|
+
#import "XCUIApplicationProcess.h"
|
|
24
|
+
#import "XCUIElement.h"
|
|
25
|
+
#import "XCUIElementQuery.h"
|
|
26
|
+
#import "FBXCAXClientProxy.h"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
static const NSTimeInterval APP_STATE_CHANGE_TIMEOUT = 5.0;
|
|
30
|
+
|
|
31
|
+
@interface FBApplication ()
|
|
32
|
+
@end
|
|
33
|
+
|
|
34
|
+
@implementation FBApplication
|
|
35
|
+
|
|
36
|
+
+ (instancetype)fb_activeApplication
|
|
37
|
+
{
|
|
38
|
+
return [self fb_activeApplicationWithDefaultBundleId:nil];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
+ (NSArray<FBApplication *> *)fb_activeApplications
|
|
42
|
+
{
|
|
43
|
+
NSArray<id<FBXCAccessibilityElement>> *activeApplicationElements = [FBXCAXClientProxy.sharedClient activeApplications];
|
|
44
|
+
NSMutableArray<FBApplication *> *result = [NSMutableArray array];
|
|
45
|
+
if (activeApplicationElements.count > 0) {
|
|
46
|
+
for (id<FBXCAccessibilityElement> applicationElement in activeApplicationElements) {
|
|
47
|
+
FBApplication *app = [FBApplication fb_applicationWithPID:applicationElement.processIdentifier];
|
|
48
|
+
if (nil != app) {
|
|
49
|
+
[result addObject:app];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return result.count > 0 ? result.copy : @[self.class.fb_systemApplication];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
+ (instancetype)fb_activeApplicationWithDefaultBundleId:(nullable NSString *)bundleId
|
|
57
|
+
{
|
|
58
|
+
NSArray<id<FBXCAccessibilityElement>> *activeApplicationElements = [FBXCAXClientProxy.sharedClient activeApplications];
|
|
59
|
+
id<FBXCAccessibilityElement> activeApplicationElement = nil;
|
|
60
|
+
id<FBXCAccessibilityElement> currentElement = nil;
|
|
61
|
+
if (nil != bundleId) {
|
|
62
|
+
currentElement = FBActiveAppDetectionPoint.sharedInstance.axElement;
|
|
63
|
+
if (nil != currentElement) {
|
|
64
|
+
NSArray<NSDictionary *> *appInfos = [self fb_appsInfoWithAxElements:@[currentElement]];
|
|
65
|
+
[FBLogger logFmt:@"Detected on-screen application: %@", appInfos.firstObject[@"bundleId"]];
|
|
66
|
+
if ([[appInfos.firstObject objectForKey:@"bundleId"] isEqualToString:(id)bundleId]) {
|
|
67
|
+
activeApplicationElement = currentElement;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (nil == activeApplicationElement && activeApplicationElements.count > 1) {
|
|
72
|
+
if (nil != bundleId) {
|
|
73
|
+
NSArray<NSDictionary *> *appInfos = [self fb_appsInfoWithAxElements:activeApplicationElements];
|
|
74
|
+
NSMutableArray<NSString *> *bundleIds = [NSMutableArray array];
|
|
75
|
+
for (NSDictionary *appInfo in appInfos) {
|
|
76
|
+
[bundleIds addObject:(NSString *)appInfo[@"bundleId"]];
|
|
77
|
+
}
|
|
78
|
+
[FBLogger logFmt:@"Detected system active application(s): %@", bundleIds];
|
|
79
|
+
// Try to select the desired application first
|
|
80
|
+
for (NSUInteger appIdx = 0; appIdx < appInfos.count; appIdx++) {
|
|
81
|
+
if ([[[appInfos objectAtIndex:appIdx] objectForKey:@"bundleId"] isEqualToString:(id)bundleId]) {
|
|
82
|
+
activeApplicationElement = [activeApplicationElements objectAtIndex:appIdx];
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Fall back to the "normal" algorithm if the desired application is either
|
|
88
|
+
// not set or is not active
|
|
89
|
+
if (nil == activeApplicationElement) {
|
|
90
|
+
if (nil == currentElement) {
|
|
91
|
+
currentElement = FBActiveAppDetectionPoint.sharedInstance.axElement;
|
|
92
|
+
}
|
|
93
|
+
if (nil == currentElement) {
|
|
94
|
+
[FBLogger log:@"Cannot precisely detect the current application. Will use the system's recently active one"];
|
|
95
|
+
if (nil == bundleId) {
|
|
96
|
+
[FBLogger log:@"Consider changing the 'defaultActiveApplication' setting to the bundle identifier of the desired application under test"];
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
for (id<FBXCAccessibilityElement> appElement in activeApplicationElements) {
|
|
100
|
+
if (appElement.processIdentifier == currentElement.processIdentifier) {
|
|
101
|
+
activeApplicationElement = appElement;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (nil != activeApplicationElement) {
|
|
110
|
+
FBApplication *application = [FBApplication fb_applicationWithPID:activeApplicationElement.processIdentifier];
|
|
111
|
+
if (nil != application) {
|
|
112
|
+
return application;
|
|
113
|
+
}
|
|
114
|
+
[FBLogger log:@"Cannot translate the active process identifier into an application object"];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (activeApplicationElements.count > 0) {
|
|
118
|
+
[FBLogger logFmt:@"Getting the most recent active application (out of %@ total items)", @(activeApplicationElements.count)];
|
|
119
|
+
for (id<FBXCAccessibilityElement> appElement in activeApplicationElements) {
|
|
120
|
+
FBApplication *application = [FBApplication fb_applicationWithPID:appElement.processIdentifier];
|
|
121
|
+
if (nil != application) {
|
|
122
|
+
return application;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
[FBLogger log:@"Cannot retrieve any active applications. Assuming the system application is the active one"];
|
|
128
|
+
return [self fb_systemApplication];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
+ (instancetype)fb_systemApplication
|
|
132
|
+
{
|
|
133
|
+
return [self fb_applicationWithPID:
|
|
134
|
+
[[FBXCAXClientProxy.sharedClient systemApplication] processIdentifier]];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
+ (instancetype)applicationWithPID:(pid_t)processID
|
|
138
|
+
{
|
|
139
|
+
if ([NSProcessInfo processInfo].processIdentifier == processID) {
|
|
140
|
+
return nil;
|
|
141
|
+
}
|
|
142
|
+
return (FBApplication *)[FBXCAXClientProxy.sharedClient monitoredApplicationWithProcessIdentifier:processID];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
- (void)launch
|
|
146
|
+
{
|
|
147
|
+
[super launch];
|
|
148
|
+
if (![self fb_waitForAppElement:APP_STATE_CHANGE_TIMEOUT]) {
|
|
149
|
+
[FBLogger logFmt:@"The application '%@' is not running in foreground after %.2f seconds", self.bundleID, APP_STATE_CHANGE_TIMEOUT];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
- (void)terminate
|
|
154
|
+
{
|
|
155
|
+
[super terminate];
|
|
156
|
+
if (![self waitForState:XCUIApplicationStateNotRunning timeout:APP_STATE_CHANGE_TIMEOUT]) {
|
|
157
|
+
[FBLogger logFmt:@"The active application is still '%@' after %.2f seconds timeout", self.bundleID, APP_STATE_CHANGE_TIMEOUT];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
+ (BOOL)fb_switchToSystemApplicationWithError:(NSError **)error
|
|
162
|
+
{
|
|
163
|
+
FBApplication *systemApp = self.fb_systemApplication;
|
|
164
|
+
@try {
|
|
165
|
+
if ([systemApp fb_state] < 2) {
|
|
166
|
+
[systemApp launch];
|
|
167
|
+
} else {
|
|
168
|
+
[systemApp fb_activate];
|
|
169
|
+
}
|
|
170
|
+
} @catch (NSException *e) {
|
|
171
|
+
return [[[FBErrorBuilder alloc]
|
|
172
|
+
withDescription:nil == e ? @"Cannot open the home screen" : e.reason]
|
|
173
|
+
buildError:error];
|
|
174
|
+
}
|
|
175
|
+
return [[[[FBRunLoopSpinner new]
|
|
176
|
+
timeout:5]
|
|
177
|
+
timeoutErrorMessage:@"Timeout waiting until the home screen is visible"]
|
|
178
|
+
spinUntilTrue:^BOOL{
|
|
179
|
+
FBApplication *activeApp = self.fb_activeApplication;
|
|
180
|
+
return nil != activeApp && [activeApp.bundleID isEqualToString:systemApp.bundleID];
|
|
181
|
+
}
|
|
182
|
+
error:error];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@end
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
#import <Foundation/Foundation.h>
|
|
11
11
|
|
|
12
|
+
@class FBApplication;
|
|
12
13
|
@class FBElementCache;
|
|
13
|
-
@class XCUIApplication;
|
|
14
14
|
|
|
15
15
|
NS_ASSUME_NONNULL_BEGIN
|
|
16
16
|
|
|
@@ -20,16 +20,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
20
20
|
@interface FBSession : NSObject
|
|
21
21
|
|
|
22
22
|
/*! Application tested during that session */
|
|
23
|
-
@property (nonatomic, readonly)
|
|
23
|
+
@property (nonatomic, strong, readonly) FBApplication *activeApplication;
|
|
24
24
|
|
|
25
25
|
/*! Session's identifier */
|
|
26
|
-
@property (nonatomic, readonly) NSString *identifier;
|
|
26
|
+
@property (nonatomic, copy, readonly) NSString *identifier;
|
|
27
27
|
|
|
28
28
|
/*! Element cache related to that session */
|
|
29
|
-
@property (nonatomic, readonly) FBElementCache *elementCache;
|
|
29
|
+
@property (nonatomic, strong, readonly) FBElementCache *elementCache;
|
|
30
30
|
|
|
31
31
|
/*! The identifier of the active application */
|
|
32
|
-
@property (nonatomic) NSString *defaultActiveApplication;
|
|
32
|
+
@property (nonatomic, copy) NSString *defaultActiveApplication;
|
|
33
33
|
|
|
34
34
|
/*! The action to apply to unexpected alerts. Either "accept"/"dismiss" or nil/empty string (by default) to do nothing */
|
|
35
35
|
@property (nonatomic, nullable) NSString *defaultAlertAction;
|
|
@@ -57,7 +57,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
57
57
|
@param application The application that we want to create session for
|
|
58
58
|
@return new session
|
|
59
59
|
*/
|
|
60
|
-
+ (instancetype)initWithApplication:(nullable
|
|
60
|
+
+ (instancetype)initWithApplication:(nullable FBApplication *)application;
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
Creates and saves new session for application with default alert handling behaviour
|
|
@@ -66,8 +66,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
66
66
|
@param defaultAlertAction The default reaction to on-screen alert. Either 'accept' or 'dismiss'
|
|
67
67
|
@return new session
|
|
68
68
|
*/
|
|
69
|
-
+ (instancetype)initWithApplication:(nullable
|
|
70
|
-
defaultAlertAction:(NSString *)defaultAlertAction;
|
|
69
|
+
+ (instancetype)initWithApplication:(nullable FBApplication *)application defaultAlertAction:(NSString *)defaultAlertAction;
|
|
71
70
|
|
|
72
71
|
/**
|
|
73
72
|
Kills application associated with that session and removes session
|
|
@@ -83,11 +82,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
83
82
|
@param arguments The optional array of application command line arguments. The arguments are going to be applied if the application was not running before.
|
|
84
83
|
@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.
|
|
85
84
|
@return The application instance
|
|
85
|
+
@throws FBApplicationMethodNotSupportedException if the method is not supported with the current XCTest SDK
|
|
86
86
|
*/
|
|
87
|
-
- (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
- (FBApplication *)launchApplicationWithBundleId:(NSString *)bundleIdentifier
|
|
88
|
+
shouldWaitForQuiescence:(nullable NSNumber *)shouldWaitForQuiescence
|
|
89
|
+
arguments:(nullable NSArray<NSString *> *)arguments
|
|
90
|
+
environment:(nullable NSDictionary <NSString *, NSString *> *)environment;
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
93
|
Activate an application with given bundle identifier in scope of current session.
|
|
@@ -95,8 +95,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
95
95
|
|
|
96
96
|
@param bundleIdentifier Valid bundle identifier of the application to be activated
|
|
97
97
|
@return The application instance
|
|
98
|
+
@throws FBApplicationMethodNotSupportedException if the method is not supported with the current XCTest SDK
|
|
98
99
|
*/
|
|
99
|
-
- (
|
|
100
|
+
- (FBApplication *)activateApplicationWithBundleId:(NSString *)bundleIdentifier;
|
|
100
101
|
|
|
101
102
|
/**
|
|
102
103
|
Terminate an application with the given bundle id. The application should be previously
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
#import "FBXCAccessibilityElement.h"
|
|
16
16
|
#import "FBAlertsMonitor.h"
|
|
17
|
+
#import "FBApplication.h"
|
|
17
18
|
#import "FBConfiguration.h"
|
|
18
19
|
#import "FBElementCache.h"
|
|
19
20
|
#import "FBExceptions.h"
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
NSString *const FBDefaultApplicationAuto = @"auto";
|
|
31
32
|
|
|
32
33
|
@interface FBSession ()
|
|
33
|
-
@property (
|
|
34
|
+
@property (nonatomic) NSString *testedApplicationBundleId;
|
|
34
35
|
@property (nonatomic) BOOL isTestedApplicationExpectedToRun;
|
|
35
36
|
@property (nonatomic) BOOL shouldAppsWaitForQuiescence;
|
|
36
37
|
@property (nonatomic, nullable) FBAlertsMonitor *alertsMonitor;
|
|
@@ -95,7 +96,7 @@ static FBSession *_activeSession = nil;
|
|
|
95
96
|
return _activeSession;
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
+ (instancetype)initWithApplication:(
|
|
99
|
+
+ (instancetype)initWithApplication:(FBApplication *)application
|
|
99
100
|
{
|
|
100
101
|
FBSession *session = [FBSession new];
|
|
101
102
|
session.useNativeCachingStrategy = YES;
|
|
@@ -104,10 +105,10 @@ static FBSession *_activeSession = nil;
|
|
|
104
105
|
session.elementsVisibilityCache = [NSMutableDictionary dictionary];
|
|
105
106
|
session.identifier = [[NSUUID UUID] UUIDString];
|
|
106
107
|
session.defaultActiveApplication = FBDefaultApplicationAuto;
|
|
107
|
-
session.
|
|
108
|
+
session.testedApplicationBundleId = nil;
|
|
108
109
|
session.isTestedApplicationExpectedToRun = nil != application && application.running;
|
|
109
110
|
if (application) {
|
|
110
|
-
session.
|
|
111
|
+
session.testedApplicationBundleId = application.bundleID;
|
|
111
112
|
session.shouldAppsWaitForQuiescence = application.fb_shouldWaitForQuiescence;
|
|
112
113
|
}
|
|
113
114
|
session.elementCache = [FBElementCache new];
|
|
@@ -115,7 +116,7 @@ static FBSession *_activeSession = nil;
|
|
|
115
116
|
return session;
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
+ (instancetype)initWithApplication:(nullable
|
|
119
|
+
+ (instancetype)initWithApplication:(nullable FBApplication *)application
|
|
119
120
|
defaultAlertAction:(NSString *)defaultAlertAction
|
|
120
121
|
{
|
|
121
122
|
FBSession *session = [self.class initWithApplication:application];
|
|
@@ -137,78 +138,81 @@ static FBSession *_activeSession = nil;
|
|
|
137
138
|
self.alertsMonitor = nil;
|
|
138
139
|
}
|
|
139
140
|
|
|
140
|
-
if (
|
|
141
|
-
&&
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
141
|
+
if (self.testedApplicationBundleId && [FBConfiguration shouldTerminateApp]
|
|
142
|
+
&& ![self.testedApplicationBundleId isEqualToString:FBApplication.fb_systemApplication.bundleID]) {
|
|
143
|
+
FBApplication *app = [[FBApplication alloc] initWithBundleIdentifier:self.testedApplicationBundleId];
|
|
144
|
+
if ([app running]) {
|
|
145
|
+
@try {
|
|
146
|
+
[app terminate];
|
|
147
|
+
} @catch (NSException *e) {
|
|
148
|
+
[FBLogger logFmt:@"%@", e.description];
|
|
149
|
+
}
|
|
148
150
|
}
|
|
149
151
|
}
|
|
150
152
|
|
|
151
153
|
_activeSession = nil;
|
|
152
154
|
}
|
|
153
155
|
|
|
154
|
-
- (
|
|
156
|
+
- (FBApplication *)activeApplication
|
|
155
157
|
{
|
|
156
|
-
if (nil != self.testedApplication) {
|
|
157
|
-
XCUIApplicationState testedAppState = self.testedApplication.state;
|
|
158
|
-
if (testedAppState >= XCUIApplicationStateRunningForeground) {
|
|
159
|
-
return (XCUIApplication *)self.testedApplication;
|
|
160
|
-
}
|
|
161
|
-
if (self.isTestedApplicationExpectedToRun && testedAppState <= XCUIApplicationStateNotRunning) {
|
|
162
|
-
NSString *description = [NSString stringWithFormat:@"The application under test with bundle id '%@' is not running, possibly crashed", self.testedApplication.bundleID];
|
|
163
|
-
@throw [NSException exceptionWithName:FBApplicationCrashedException reason:description userInfo:nil];
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
158
|
NSString *defaultBundleId = [self.defaultActiveApplication isEqualToString:FBDefaultApplicationAuto]
|
|
168
159
|
? nil
|
|
169
160
|
: self.defaultActiveApplication;
|
|
170
|
-
|
|
161
|
+
FBApplication *application = [FBApplication fb_activeApplicationWithDefaultBundleId:defaultBundleId];
|
|
162
|
+
FBApplication *testedApplication = nil;
|
|
163
|
+
if (self.testedApplicationBundleId && self.isTestedApplicationExpectedToRun) {
|
|
164
|
+
testedApplication = nil != application.bundleID && [application.bundleID isEqualToString:self.testedApplicationBundleId]
|
|
165
|
+
? application
|
|
166
|
+
: [[FBApplication alloc] initWithBundleIdentifier:self.testedApplicationBundleId];
|
|
167
|
+
}
|
|
168
|
+
if (testedApplication && !testedApplication.running) {
|
|
169
|
+
NSString *description = [NSString stringWithFormat:@"The application under test with bundle id '%@' is not running, possibly crashed", self.testedApplicationBundleId];
|
|
170
|
+
[[NSException exceptionWithName:FBApplicationCrashedException reason:description userInfo:nil] raise];
|
|
171
|
+
}
|
|
172
|
+
return application;
|
|
171
173
|
}
|
|
172
174
|
|
|
173
|
-
- (
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
- (FBApplication *)launchApplicationWithBundleId:(NSString *)bundleIdentifier
|
|
176
|
+
shouldWaitForQuiescence:(nullable NSNumber *)shouldWaitForQuiescence
|
|
177
|
+
arguments:(nullable NSArray<NSString *> *)arguments
|
|
178
|
+
environment:(nullable NSDictionary <NSString *, NSString *> *)environment
|
|
177
179
|
{
|
|
178
|
-
|
|
180
|
+
FBApplication *app = [[FBApplication alloc] initWithBundleIdentifier:bundleIdentifier];
|
|
179
181
|
if (nil == shouldWaitForQuiescence) {
|
|
180
182
|
// Iherit the quiescence check setting from the main app under test by default
|
|
181
|
-
app.fb_shouldWaitForQuiescence = nil != self.
|
|
183
|
+
app.fb_shouldWaitForQuiescence = nil != self.testedApplicationBundleId && self.shouldAppsWaitForQuiescence;
|
|
182
184
|
} else {
|
|
183
185
|
app.fb_shouldWaitForQuiescence = [shouldWaitForQuiescence boolValue];
|
|
184
186
|
}
|
|
185
|
-
if (
|
|
187
|
+
if (app.fb_state < 2) {
|
|
186
188
|
app.launchArguments = arguments ?: @[];
|
|
187
189
|
app.launchEnvironment = environment ?: @{};
|
|
188
190
|
[app launch];
|
|
189
191
|
} else {
|
|
190
|
-
[app
|
|
192
|
+
[app fb_activate];
|
|
191
193
|
}
|
|
192
|
-
if (
|
|
194
|
+
if (nil != self.testedApplicationBundleId
|
|
195
|
+
&& [bundleIdentifier isEqualToString:(NSString *)self.testedApplicationBundleId]) {
|
|
193
196
|
self.isTestedApplicationExpectedToRun = YES;
|
|
194
197
|
}
|
|
195
198
|
return app;
|
|
196
199
|
}
|
|
197
200
|
|
|
198
|
-
- (
|
|
201
|
+
- (FBApplication *)activateApplicationWithBundleId:(NSString *)bundleIdentifier
|
|
199
202
|
{
|
|
200
|
-
|
|
201
|
-
[app
|
|
203
|
+
FBApplication *app = [[FBApplication alloc] initWithBundleIdentifier:bundleIdentifier];
|
|
204
|
+
[app fb_activate];
|
|
202
205
|
return app;
|
|
203
206
|
}
|
|
204
207
|
|
|
205
208
|
- (BOOL)terminateApplicationWithBundleId:(NSString *)bundleIdentifier
|
|
206
209
|
{
|
|
207
|
-
|
|
208
|
-
if (
|
|
210
|
+
FBApplication *app = [[FBApplication alloc] initWithBundleIdentifier:bundleIdentifier];
|
|
211
|
+
if (nil != self.testedApplicationBundleId
|
|
212
|
+
&& [bundleIdentifier isEqualToString:(NSString *)self.testedApplicationBundleId]) {
|
|
209
213
|
self.isTestedApplicationExpectedToRun = NO;
|
|
210
214
|
}
|
|
211
|
-
if (app.
|
|
215
|
+
if (app.fb_state >= 2) {
|
|
212
216
|
[app terminate];
|
|
213
217
|
return YES;
|
|
214
218
|
}
|
|
@@ -217,14 +221,7 @@ static FBSession *_activeSession = nil;
|
|
|
217
221
|
|
|
218
222
|
- (NSUInteger)applicationStateWithBundleId:(NSString *)bundleIdentifier
|
|
219
223
|
{
|
|
220
|
-
return [
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
- (XCUIApplication *)makeApplicationWithBundleId:(NSString *)bundleIdentifier
|
|
224
|
-
{
|
|
225
|
-
return nil != self.testedApplication && [bundleIdentifier isEqualToString:(NSString *)self.testedApplication.bundleID]
|
|
226
|
-
? self.testedApplication
|
|
227
|
-
: [[XCUIApplication alloc] initWithBundleIdentifier:bundleIdentifier];
|
|
224
|
+
return [[FBApplication alloc] initWithBundleIdentifier:bundleIdentifier].fb_state;
|
|
228
225
|
}
|
|
229
226
|
|
|
230
227
|
@end
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
#import "FBAlertsMonitor.h"
|
|
11
11
|
|
|
12
12
|
#import "FBAlert.h"
|
|
13
|
+
#import "FBApplication.h"
|
|
13
14
|
#import "FBLogger.h"
|
|
14
15
|
#import "XCUIApplication+FBAlert.h"
|
|
15
|
-
#import "XCUIApplication+FBHelpers.h"
|
|
16
16
|
|
|
17
17
|
static const NSTimeInterval FB_MONTORING_INTERVAL = 2.0;
|
|
18
18
|
|
|
@@ -49,8 +49,8 @@ static const NSTimeInterval FB_MONTORING_INTERVAL = 2.0;
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
52
|
-
NSArray<
|
|
53
|
-
for (
|
|
52
|
+
NSArray<FBApplication *> *activeApps = FBApplication.fb_activeApplications;
|
|
53
|
+
for (FBApplication *activeApp in activeApps) {
|
|
54
54
|
XCUIElement *alertElement = nil;
|
|
55
55
|
@try {
|
|
56
56
|
alertElement = activeApp.fb_alertElement;
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
#import "FBKeyboard.h"
|
|
11
11
|
|
|
12
|
+
|
|
13
|
+
#import "FBApplication.h"
|
|
12
14
|
#import "FBConfiguration.h"
|
|
13
15
|
#import "FBXCTestDaemonsProxy.h"
|
|
14
16
|
#import "FBErrorBuilder.h"
|
|
@@ -23,13 +25,10 @@
|
|
|
23
25
|
|
|
24
26
|
@implementation FBKeyboard
|
|
25
27
|
|
|
26
|
-
+ (BOOL)waitUntilVisibleForApplication:(XCUIApplication *)app
|
|
27
|
-
timeout:(NSTimeInterval)timeout
|
|
28
|
-
error:(NSError **)error
|
|
28
|
+
+ (BOOL)waitUntilVisibleForApplication:(XCUIApplication *)app timeout:(NSTimeInterval)timeout error:(NSError **)error
|
|
29
29
|
{
|
|
30
30
|
BOOL (^isKeyboardVisible)(void) = ^BOOL(void) {
|
|
31
|
-
|
|
32
|
-
if (nil == keyboard) {
|
|
31
|
+
if (!app.keyboard.exists) {
|
|
33
32
|
return NO;
|
|
34
33
|
}
|
|
35
34
|
|
|
@@ -37,7 +36,7 @@
|
|
|
37
36
|
NSDictionary *bindings) {
|
|
38
37
|
return snapshot.label.length > 0;
|
|
39
38
|
}];
|
|
40
|
-
XCUIElement *firstKey = [[keyboard descendantsMatchingType:XCUIElementTypeKey]
|
|
39
|
+
XCUIElement *firstKey = [[app.keyboard descendantsMatchingType:XCUIElementTypeKey]
|
|
41
40
|
matchingPredicate:keySearchPredicate].allElementsBoundByIndex.firstObject;
|
|
42
41
|
return firstKey.exists && firstKey.hittable;
|
|
43
42
|
};
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
|
|
12
12
|
#import <mach/mach_time.h>
|
|
13
13
|
#import "FBAlert.h"
|
|
14
|
+
#import "FBApplication.h"
|
|
14
15
|
#import "FBErrorBuilder.h"
|
|
15
16
|
#import "FBMacros.h"
|
|
16
|
-
#import "XCUIApplication+FBHelpers.h"
|
|
17
17
|
#import "XCUIApplication+FBAlert.h"
|
|
18
18
|
|
|
19
19
|
#define ALERT_TIMEOUT_SEC 30
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
break;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
XCUIElement *alertElement =
|
|
104
|
+
XCUIElement *alertElement = FBApplication.fb_systemApplication.fb_alertElement;
|
|
105
105
|
if (nil != alertElement) {
|
|
106
106
|
FBAlert *alert = [FBAlert alertWithElement:alertElement];
|
|
107
107
|
[alert acceptWithError:nil];
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
#import "FBScreen.h"
|
|
11
|
+
#import "FBApplication.h"
|
|
11
12
|
#import "XCUIElement+FBIsVisible.h"
|
|
12
13
|
#import "FBXCodeCompatibility.h"
|
|
13
14
|
#import "XCUIScreen.h"
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
|
|
22
23
|
+ (CGSize)statusBarSizeForApplication:(XCUIApplication *)application
|
|
23
24
|
{
|
|
24
|
-
XCUIApplication *app =
|
|
25
|
+
XCUIApplication *app = FBApplication.fb_systemApplication;
|
|
25
26
|
// Since iOS 13 the status bar is no longer part of the application, it’s part of the SpringBoard
|
|
26
27
|
XCUIElement *mainStatusBar = app.statusBars.allElementsBoundByIndex.firstObject;
|
|
27
28
|
if (nil == mainStatusBar) {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
#import "FBTVNavigationTracker.h"
|
|
11
11
|
#import "FBTVNavigationTracker-Private.h"
|
|
12
12
|
|
|
13
|
+
#import "FBApplication.h"
|
|
13
14
|
#import "FBMathUtils.h"
|
|
14
15
|
#import "XCUIElement+FBCaching.h"
|
|
15
16
|
#import "XCUIElement+FBUtilities.h"
|
|
@@ -68,7 +69,7 @@
|
|
|
68
69
|
|
|
69
70
|
- (FBTVDirection)directionToFocusedElement
|
|
70
71
|
{
|
|
71
|
-
XCUIElement *focused =
|
|
72
|
+
XCUIElement *focused = FBApplication.fb_activeApplication.fb_focusedElement;
|
|
72
73
|
|
|
73
74
|
CGPoint focusedCenter = FBRectGetCenter(focused.wdFrame);
|
|
74
75
|
FBTVNavigationItem *item = [self navigationItemWithElement:focused];
|
|
@@ -28,6 +28,39 @@ NSInteger FBTestmanagerdVersion(void);
|
|
|
28
28
|
|
|
29
29
|
NS_ASSUME_NONNULL_BEGIN
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
The exception happends if one tries to call application method,
|
|
33
|
+
which is not supported in the current iOS version
|
|
34
|
+
*/
|
|
35
|
+
extern NSString *const FBApplicationMethodNotSupportedException;
|
|
36
|
+
|
|
37
|
+
@interface XCUIApplication (FBCompatibility)
|
|
38
|
+
|
|
39
|
+
+ (nullable instancetype)fb_applicationWithPID:(pid_t)processID;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
Get the state of the application. This method only returns reliable results on Xcode SDK 9+
|
|
43
|
+
|
|
44
|
+
@return State value as enum item. See https://developer.apple.com/documentation/xctest/xcuiapplicationstate?language=objc for more details.
|
|
45
|
+
*/
|
|
46
|
+
- (NSUInteger)fb_state;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
Activate the application by restoring it from the background.
|
|
50
|
+
Nothing will happen if the application is already in foreground.
|
|
51
|
+
This method is only supported since Xcode9.
|
|
52
|
+
|
|
53
|
+
@throws FBTimeoutException if the app is still not active after the timeout
|
|
54
|
+
*/
|
|
55
|
+
- (void)fb_activate;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
Terminate the application and wait until it disappears from the list of active apps
|
|
59
|
+
*/
|
|
60
|
+
- (void)fb_terminate;
|
|
61
|
+
|
|
62
|
+
@end
|
|
63
|
+
|
|
31
64
|
@interface XCUIElementQuery (FBCompatibility)
|
|
32
65
|
|
|
33
66
|
/* 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 */
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
|
|
10
10
|
#import "FBXCodeCompatibility.h"
|
|
11
11
|
|
|
12
|
-
#import "FBXCAXClientProxy.h"
|
|
13
12
|
#import "FBConfiguration.h"
|
|
14
13
|
#import "FBErrorBuilder.h"
|
|
15
14
|
#import "FBLogger.h"
|
|
@@ -18,6 +17,45 @@
|
|
|
18
17
|
#import "FBXCTestDaemonsProxy.h"
|
|
19
18
|
#import "XCTestManager_ManagerInterface-Protocol.h"
|
|
20
19
|
|
|
20
|
+
static const NSTimeInterval APP_STATE_CHANGE_TIMEOUT = 5.0;
|
|
21
|
+
|
|
22
|
+
NSString *const FBApplicationMethodNotSupportedException = @"FBApplicationMethodNotSupportedException";
|
|
23
|
+
|
|
24
|
+
@implementation XCUIApplication (FBCompatibility)
|
|
25
|
+
|
|
26
|
+
+ (instancetype)fb_applicationWithPID:(pid_t)processID
|
|
27
|
+
{
|
|
28
|
+
if (0 == processID) {
|
|
29
|
+
return nil;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return [self applicationWithPID:processID];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
- (void)fb_activate
|
|
36
|
+
{
|
|
37
|
+
[self activate];
|
|
38
|
+
if (![self waitForState:XCUIApplicationStateRunningForeground timeout:APP_STATE_CHANGE_TIMEOUT / 2] || ![self fb_waitForAppElement:APP_STATE_CHANGE_TIMEOUT / 2]) {
|
|
39
|
+
[FBLogger logFmt:@"The application '%@' is not running in foreground after %.2f seconds", self.bundleID, APP_STATE_CHANGE_TIMEOUT];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
- (void)fb_terminate
|
|
44
|
+
{
|
|
45
|
+
[self terminate];
|
|
46
|
+
if (![self waitForState:XCUIApplicationStateNotRunning timeout:APP_STATE_CHANGE_TIMEOUT]) {
|
|
47
|
+
[FBLogger logFmt:@"The active application is still '%@' after %.2f seconds timeout", self.bundleID, APP_STATE_CHANGE_TIMEOUT];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
- (NSUInteger)fb_state
|
|
52
|
+
{
|
|
53
|
+
return [[self valueForKey:@"state"] intValue];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@end
|
|
57
|
+
|
|
58
|
+
|
|
21
59
|
@implementation XCUIElementQuery (FBCompatibility)
|
|
22
60
|
|
|
23
61
|
- (XCElementSnapshot *)fb_uniqueSnapshotWithError:(NSError **)error
|
|
@@ -51,7 +89,7 @@
|
|
|
51
89
|
static dispatch_once_t hasIncludingNonModalElements;
|
|
52
90
|
static BOOL result;
|
|
53
91
|
dispatch_once(&hasIncludingNonModalElements, ^{
|
|
54
|
-
result = [
|
|
92
|
+
result = [FBApplication.fb_systemApplication.query respondsToSelector:@selector(includingNonModalElements)];
|
|
55
93
|
});
|
|
56
94
|
return result;
|
|
57
95
|
}
|
|
@@ -16,6 +16,7 @@ FOUNDATION_EXPORT double WebDriverAgentLib_VersionNumber;
|
|
|
16
16
|
FOUNDATION_EXPORT const unsigned char WebDriverAgentLib_VersionString[];
|
|
17
17
|
|
|
18
18
|
#import <WebDriverAgentLib/FBAlert.h>
|
|
19
|
+
#import <WebDriverAgentLib/FBApplication.h>
|
|
19
20
|
#import <WebDriverAgentLib/FBCommandHandler.h>
|
|
20
21
|
#import <WebDriverAgentLib/FBCommandStatus.h>
|
|
21
22
|
#import <WebDriverAgentLib/FBConfiguration.h>
|