appium-webdriveragent 4.10.24 → 4.12.0
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 +14 -0
- package/PrivateHeaders/XCTest/XCTRunnerDaemonSession.h +13 -0
- package/WebDriverAgent.xcodeproj/project.pbxproj +4 -0
- package/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.h +48 -2
- package/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m +43 -7
- package/WebDriverAgentLib/Commands/FBCustomCommands.m +64 -10
- package/WebDriverAgentLib/Commands/FBSessionCommands.m +9 -2
- package/WebDriverAgentLib/Routing/FBResponsePayload.m +1 -1
- package/WebDriverAgentLib/Utilities/FBClassChainQueryParser.m +34 -14
- package/WebDriverAgentLib/Utilities/FBRuntimeUtils.m +1 -1
- package/WebDriverAgentLib/Utilities/FBXCTestDaemonsProxy.h +14 -3
- package/WebDriverAgentLib/Utilities/FBXCTestDaemonsProxy.m +154 -0
- package/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m +44 -2
- package/WebDriverAgentTests/UnitTests/FBXPathTests.m +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [4.12.0](https://github.com/appium/WebDriverAgent/compare/v4.11.0...v4.12.0) (2023-02-20)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* Add support of the simulated geolocation setting ([#662](https://github.com/appium/WebDriverAgent/issues/662)) ([ebb9e60](https://github.com/appium/WebDriverAgent/commit/ebb9e60d56c0e0db9f509437ed639a3a39f6011b))
|
|
7
|
+
|
|
8
|
+
## [4.11.0](https://github.com/appium/WebDriverAgent/compare/v4.10.24...v4.11.0) (2023-02-19)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* Add openUrl handler available since Xcode 14.3 ([#661](https://github.com/appium/WebDriverAgent/issues/661)) ([bee564e](https://github.com/appium/WebDriverAgent/commit/bee564e8c6b975aff07fd1244583f0727a0f5470))
|
|
14
|
+
|
|
1
15
|
## [4.10.24](https://github.com/appium/WebDriverAgent/compare/v4.10.23...v4.10.24) (2023-02-17)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
#import <UIKit/UIKit.h>
|
|
11
11
|
|
|
12
12
|
@class NSMutableDictionary, NSXPCConnection, XCSynthesizedEventRecord;
|
|
13
|
+
#if !TARGET_OS_TV // tvOS does not provide relevant APIs
|
|
14
|
+
@class CLLocation;
|
|
15
|
+
#endif
|
|
13
16
|
@protocol XCTUIApplicationMonitor, XCTAXClient, XCTestManager_ManagerInterface;
|
|
14
17
|
|
|
15
18
|
// iOS since 10.3
|
|
@@ -67,4 +70,14 @@
|
|
|
67
70
|
- (void)_reportInvalidation;
|
|
68
71
|
- (id)initWithConnection:(id)arg1;
|
|
69
72
|
|
|
73
|
+
// Since Xcode 14.3
|
|
74
|
+
- (void)openURL:(NSURL *)arg1 usingApplication:(NSString *)arg2 completion:(void (^)(_Bool, NSError *))arg3;
|
|
75
|
+
- (void)openDefaultApplicationForURL:(NSURL *)arg1 completion:(void (^)(_Bool, NSError *))arg2;
|
|
76
|
+
#if !TARGET_OS_TV // tvOS does not provide relevant APIs
|
|
77
|
+
- (void)setSimulatedLocation:(CLLocation *)arg1 completion:(void (^)(_Bool, NSError *))arg2;
|
|
78
|
+
- (void)getSimulatedLocationWithReply:(void (^)(CLLocation *, NSError *))arg1;
|
|
79
|
+
- (void)clearSimulatedLocationWithReply:(void (^)(_Bool, NSError *))arg1;
|
|
80
|
+
@property(readonly) _Bool supportsLocationSimulation;
|
|
81
|
+
#endif
|
|
82
|
+
|
|
70
83
|
@end
|
|
@@ -3666,6 +3666,7 @@
|
|
|
3666
3666
|
"-Wno-objc-messaging-id",
|
|
3667
3667
|
"-Wno-direct-ivar-access",
|
|
3668
3668
|
"-Wno-cast-qual",
|
|
3669
|
+
"-Wno-declaration-after-statement",
|
|
3669
3670
|
);
|
|
3670
3671
|
};
|
|
3671
3672
|
name = Debug;
|
|
@@ -3728,6 +3729,7 @@
|
|
|
3728
3729
|
"-Wno-objc-messaging-id",
|
|
3729
3730
|
"-Wno-direct-ivar-access",
|
|
3730
3731
|
"-Wno-cast-qual",
|
|
3732
|
+
"-Wno-declaration-after-statement",
|
|
3731
3733
|
);
|
|
3732
3734
|
};
|
|
3733
3735
|
name = Release;
|
|
@@ -3974,6 +3976,7 @@
|
|
|
3974
3976
|
"-Wno-objc-messaging-id",
|
|
3975
3977
|
"-Wno-direct-ivar-access",
|
|
3976
3978
|
"-Wno-cast-qual",
|
|
3979
|
+
"-Wno-declaration-after-statement",
|
|
3977
3980
|
);
|
|
3978
3981
|
};
|
|
3979
3982
|
name = Debug;
|
|
@@ -4033,6 +4036,7 @@
|
|
|
4033
4036
|
"-Wno-objc-messaging-id",
|
|
4034
4037
|
"-Wno-direct-ivar-access",
|
|
4035
4038
|
"-Wno-cast-qual",
|
|
4039
|
+
"-Wno-declaration-after-statement",
|
|
4036
4040
|
);
|
|
4037
4041
|
};
|
|
4038
4042
|
name = Release;
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
#import <XCTest/XCTest.h>
|
|
11
11
|
|
|
12
|
+
#if !TARGET_OS_TV
|
|
13
|
+
#import <CoreLocation/CoreLocation.h>
|
|
14
|
+
#endif
|
|
15
|
+
|
|
12
16
|
NS_ASSUME_NONNULL_BEGIN
|
|
13
17
|
|
|
14
18
|
typedef NS_ENUM(NSUInteger, FBUIInterfaceAppearance) {
|
|
@@ -71,8 +75,9 @@ typedef NS_ENUM(NSUInteger, FBUIInterfaceAppearance) {
|
|
|
71
75
|
- (nullable NSString *)fb_wifiIPAddress;
|
|
72
76
|
|
|
73
77
|
/**
|
|
74
|
-
Opens the particular url scheme using
|
|
75
|
-
This
|
|
78
|
+
Opens the particular url scheme using the default application assigned to it.
|
|
79
|
+
This API only works since XCode 14.3/iOS 16.4
|
|
80
|
+
Older Xcode/iOS version try to use Siri fallback.
|
|
76
81
|
|
|
77
82
|
@param url The url scheme represented as a string, for example https://apple.com
|
|
78
83
|
@param error If there is an error, upon return contains an NSError object that describes the problem.
|
|
@@ -80,6 +85,17 @@ typedef NS_ENUM(NSUInteger, FBUIInterfaceAppearance) {
|
|
|
80
85
|
*/
|
|
81
86
|
- (BOOL)fb_openUrl:(NSString *)url error:(NSError **)error;
|
|
82
87
|
|
|
88
|
+
/**
|
|
89
|
+
Opens the particular url scheme using the given application
|
|
90
|
+
This API only works since XCode 14.3/iOS 16.4
|
|
91
|
+
|
|
92
|
+
@param url The url scheme represented as a string, for example https://apple.com
|
|
93
|
+
@param bundleId The bundle identifier of an application to use in order to open the given URL
|
|
94
|
+
@param error If there is an error, upon return contains an NSError object that describes the problem.
|
|
95
|
+
@return YES if the operation was successful
|
|
96
|
+
*/
|
|
97
|
+
- (BOOL)fb_openUrl:(NSString *)url withApplication:(NSString *)bundleId error:(NSError **)error;
|
|
98
|
+
|
|
83
99
|
/**
|
|
84
100
|
Presses the corresponding hardware button on the device with duration.
|
|
85
101
|
|
|
@@ -142,6 +158,36 @@ typedef NS_ENUM(NSUInteger, FBUIInterfaceAppearance) {
|
|
|
142
158
|
*/
|
|
143
159
|
- (nullable NSNumber *)fb_getAppearance;
|
|
144
160
|
|
|
161
|
+
#if !TARGET_OS_TV
|
|
162
|
+
/**
|
|
163
|
+
Allows to set a simulated geolocation coordinates.
|
|
164
|
+
Only works since Xcode 14.3/iOS 16.4
|
|
165
|
+
|
|
166
|
+
@param location The simlated location coordinates to set
|
|
167
|
+
@param error If there is an error, upon return contains an NSError object that describes the problem.
|
|
168
|
+
@return YES if the simulated location has been successfully set
|
|
169
|
+
*/
|
|
170
|
+
- (BOOL)fb_setSimulatedLocation:(CLLocation *)location error:(NSError **)error;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
Allows to get a simulated geolocation coordinates.
|
|
174
|
+
Only works since Xcode 14.3/iOS 16.4
|
|
175
|
+
|
|
176
|
+
@param error If there is an error, upon return contains an NSError object that describes the problem.
|
|
177
|
+
@return The current simulated location or nil in case of failure
|
|
178
|
+
*/
|
|
179
|
+
- (nullable CLLocation *)fb_getSimulatedLocation:(NSError **)error;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
Allows to clear a previosuly set simulated geolocation coordinates.
|
|
183
|
+
Only works since Xcode 14.3/iOS 16.4
|
|
184
|
+
|
|
185
|
+
@param error If there is an error, upon return contains an NSError object that describes the problem.
|
|
186
|
+
@return YES if the simulated location has been successfully cleared
|
|
187
|
+
*/
|
|
188
|
+
- (BOOL)fb_clearSimulatedLocation:(NSError **)error;
|
|
189
|
+
#endif
|
|
190
|
+
|
|
145
191
|
@end
|
|
146
192
|
|
|
147
193
|
NS_ASSUME_NONNULL_END
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
#import "FBScreenshot.h"
|
|
22
22
|
#import "FBXCDeviceEvent.h"
|
|
23
23
|
#import "FBXCodeCompatibility.h"
|
|
24
|
+
#import "FBXCTestDaemonsProxy.h"
|
|
24
25
|
#import "XCUIDevice.h"
|
|
25
26
|
|
|
26
27
|
static const NSTimeInterval FBHomeButtonCoolOffTime = 1.;
|
|
@@ -157,20 +158,38 @@ static bool fb_isLocked;
|
|
|
157
158
|
buildError:error];
|
|
158
159
|
}
|
|
159
160
|
|
|
161
|
+
NSError *err;
|
|
162
|
+
if ([FBXCTestDaemonsProxy openDefaultApplicationForURL:parsedUrl error:&err]) {
|
|
163
|
+
return YES;
|
|
164
|
+
}
|
|
165
|
+
if (![err.description containsString:@"does not support"]) {
|
|
166
|
+
if (error) {
|
|
167
|
+
*error = err;
|
|
168
|
+
}
|
|
169
|
+
return NO;
|
|
170
|
+
}
|
|
171
|
+
|
|
160
172
|
id siriService = [self valueForKey:@"siriService"];
|
|
161
173
|
if (nil != siriService) {
|
|
162
174
|
return [self fb_activateSiriVoiceRecognitionWithText:[NSString stringWithFormat:@"Open {%@}", url] error:error];
|
|
163
175
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
176
|
+
|
|
177
|
+
NSString *description = [NSString stringWithFormat:@"Cannot open '%@' with the default application assigned for it. Consider upgrading to Xcode 14.3+/iOS 16.4+", url];
|
|
178
|
+
return [[[FBErrorBuilder builder]
|
|
179
|
+
withDescriptionFormat:@"%@", description]
|
|
180
|
+
buildError:error];;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
- (BOOL)fb_openUrl:(NSString *)url withApplication:(NSString *)bundleId error:(NSError **)error
|
|
184
|
+
{
|
|
185
|
+
NSURL *parsedUrl = [NSURL URLWithString:url];
|
|
186
|
+
if (nil == parsedUrl) {
|
|
169
187
|
return [[[FBErrorBuilder builder]
|
|
170
|
-
withDescriptionFormat:@"
|
|
188
|
+
withDescriptionFormat:@"'%@' is not a valid URL", url]
|
|
171
189
|
buildError:error];
|
|
172
190
|
}
|
|
173
|
-
|
|
191
|
+
|
|
192
|
+
return [FBXCTestDaemonsProxy openURL:parsedUrl usingApplication:bundleId error:error];
|
|
174
193
|
}
|
|
175
194
|
|
|
176
195
|
- (BOOL)fb_activateSiriVoiceRecognitionWithText:(NSString *)text error:(NSError **)error
|
|
@@ -336,4 +355,21 @@ static bool fb_isLocked;
|
|
|
336
355
|
: nil;
|
|
337
356
|
}
|
|
338
357
|
|
|
358
|
+
#if !TARGET_OS_TV
|
|
359
|
+
- (BOOL)fb_setSimulatedLocation:(CLLocation *)location error:(NSError **)error
|
|
360
|
+
{
|
|
361
|
+
return [FBXCTestDaemonsProxy setSimulatedLocation:location error:error];
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
- (nullable CLLocation *)fb_getSimulatedLocation:(NSError **)error
|
|
365
|
+
{
|
|
366
|
+
return [FBXCTestDaemonsProxy getSimulatedLocation:error];
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
- (BOOL)fb_clearSimulatedLocation:(NSError **)error
|
|
370
|
+
{
|
|
371
|
+
return [FBXCTestDaemonsProxy clearSimulatedLocation:error];
|
|
372
|
+
}
|
|
373
|
+
#endif
|
|
374
|
+
|
|
339
375
|
@end
|
|
@@ -66,6 +66,14 @@
|
|
|
66
66
|
[[FBRoute POST:@"/wda/device/appearance"].withoutSession respondWithTarget:self action:@selector(handleSetDeviceAppearance:)],
|
|
67
67
|
[[FBRoute GET:@"/wda/device/location"] respondWithTarget:self action:@selector(handleGetLocation:)],
|
|
68
68
|
[[FBRoute GET:@"/wda/device/location"].withoutSession respondWithTarget:self action:@selector(handleGetLocation:)],
|
|
69
|
+
#if !TARGET_OS_TV // tvOS does not provide relevant APIs
|
|
70
|
+
[[FBRoute GET:@"/wda/simulatedLocation"] respondWithTarget:self action:@selector(handleGetSimulatedLocation:)],
|
|
71
|
+
[[FBRoute GET:@"/wda/simulatedLocation"].withoutSession respondWithTarget:self action:@selector(handleGetSimulatedLocation:)],
|
|
72
|
+
[[FBRoute POST:@"/wda/simulatedLocation"] respondWithTarget:self action:@selector(handleSetSimulatedLocation:)],
|
|
73
|
+
[[FBRoute POST:@"/wda/simulatedLocation"].withoutSession respondWithTarget:self action:@selector(handleSetSimulatedLocation:)],
|
|
74
|
+
[[FBRoute DELETE:@"/wda/simulatedLocation"] respondWithTarget:self action:@selector(handleClearSimulatedLocation:)],
|
|
75
|
+
[[FBRoute DELETE:@"/wda/simulatedLocation"].withoutSession respondWithTarget:self action:@selector(handleClearSimulatedLocation:)],
|
|
76
|
+
#endif
|
|
69
77
|
[[FBRoute OPTIONS:@"/*"].withoutSession respondWithTarget:self action:@selector(handlePingCommand:)],
|
|
70
78
|
];
|
|
71
79
|
}
|
|
@@ -106,9 +114,9 @@
|
|
|
106
114
|
BOOL isDismissed = [request.session.activeApplication fb_dismissKeyboardWithKeyNames:request.arguments[@"keyNames"]
|
|
107
115
|
error:&error];
|
|
108
116
|
return isDismissed
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
117
|
+
? FBResponseWithOK()
|
|
118
|
+
: FBResponseWithStatus([FBCommandStatus invalidElementStateErrorWithMessage:error.description
|
|
119
|
+
traceback:nil]);
|
|
112
120
|
}
|
|
113
121
|
|
|
114
122
|
+ (id<FBResponsePayload>)handlePingCommand:(FBRouteRequest *)request
|
|
@@ -123,12 +131,12 @@
|
|
|
123
131
|
FBSession *session = request.session;
|
|
124
132
|
CGSize statusBarSize = [FBScreen statusBarSizeForApplication:session.activeApplication];
|
|
125
133
|
return FBResponseWithObject(
|
|
126
|
-
|
|
134
|
+
@{
|
|
127
135
|
@"statusBarSize": @{@"width": @(statusBarSize.width),
|
|
128
136
|
@"height": @(statusBarSize.height),
|
|
129
|
-
|
|
137
|
+
},
|
|
130
138
|
@"scale": @([FBScreen scale]),
|
|
131
|
-
|
|
139
|
+
});
|
|
132
140
|
}
|
|
133
141
|
|
|
134
142
|
+ (id<FBResponsePayload>)handleLock:(FBRouteRequest *)request
|
|
@@ -325,7 +333,7 @@
|
|
|
325
333
|
CLAuthorizationStatus authStatus;
|
|
326
334
|
if ([locationManager respondsToSelector:@selector(authorizationStatus)]) {
|
|
327
335
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[locationManager class]
|
|
328
|
-
|
|
336
|
+
instanceMethodSignatureForSelector:@selector(authorizationStatus)]];
|
|
329
337
|
[invocation setSelector:@selector(authorizationStatus)];
|
|
330
338
|
[invocation setTarget:locationManager];
|
|
331
339
|
[invocation invoke];
|
|
@@ -379,8 +387,8 @@
|
|
|
379
387
|
}
|
|
380
388
|
|
|
381
389
|
FBUIInterfaceAppearance appearance = [name isEqualToString:@"light"]
|
|
382
|
-
|
|
383
|
-
|
|
390
|
+
? FBUIInterfaceAppearanceLight
|
|
391
|
+
: FBUIInterfaceAppearanceDark;
|
|
384
392
|
NSError *error;
|
|
385
393
|
if (![XCUIDevice.sharedDevice fb_setAppearance:appearance error:&error]) {
|
|
386
394
|
return FBResponseWithStatus([FBCommandStatus unknownErrorWithMessage:error.description
|
|
@@ -397,7 +405,7 @@
|
|
|
397
405
|
NSString *currentLocale = [[NSLocale autoupdatingCurrentLocale] localeIdentifier];
|
|
398
406
|
|
|
399
407
|
NSMutableDictionary *deviceInfo = [NSMutableDictionary dictionaryWithDictionary:
|
|
400
|
-
|
|
408
|
+
@{
|
|
401
409
|
@"currentLocale": currentLocale,
|
|
402
410
|
@"timeZone": self.timeZone,
|
|
403
411
|
@"name": UIDevice.currentDevice.name,
|
|
@@ -490,4 +498,50 @@
|
|
|
490
498
|
return [localTimeZone name];
|
|
491
499
|
}
|
|
492
500
|
|
|
501
|
+
#if !TARGET_OS_TV // tvOS does not provide relevant APIs
|
|
502
|
+
+ (id<FBResponsePayload>)handleGetSimulatedLocation:(FBRouteRequest *)request
|
|
503
|
+
{
|
|
504
|
+
NSError *error;
|
|
505
|
+
CLLocation *location = [XCUIDevice.sharedDevice fb_getSimulatedLocation:&error];
|
|
506
|
+
if (nil == location) {
|
|
507
|
+
return FBResponseWithStatus([FBCommandStatus unknownErrorWithMessage:error.description
|
|
508
|
+
traceback:nil]);
|
|
509
|
+
}
|
|
510
|
+
return FBResponseWithObject(@{
|
|
511
|
+
@"latitude": @(location.coordinate.latitude),
|
|
512
|
+
@"longiture": @(location.coordinate.longitude),
|
|
513
|
+
@"altitude": @(location.altitude),
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
+ (id<FBResponsePayload>)handleSetSimulatedLocation:(FBRouteRequest *)request
|
|
518
|
+
{
|
|
519
|
+
NSNumber *longitude = request.arguments[@"longitude"];
|
|
520
|
+
NSNumber *latitude = request.arguments[@"latitude"];
|
|
521
|
+
|
|
522
|
+
if (nil == longitude || nil == latitude) {
|
|
523
|
+
return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:@"Both latitude and longitude must be provided"
|
|
524
|
+
traceback:nil]);
|
|
525
|
+
}
|
|
526
|
+
NSError *error;
|
|
527
|
+
CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude.doubleValue
|
|
528
|
+
longitude:longitude.doubleValue];
|
|
529
|
+
if (![XCUIDevice.sharedDevice fb_setSimulatedLocation:location error:&error]) {
|
|
530
|
+
return FBResponseWithStatus([FBCommandStatus unknownErrorWithMessage:error.description
|
|
531
|
+
traceback:nil]);
|
|
532
|
+
}
|
|
533
|
+
return FBResponseWithOK();
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
+ (id<FBResponsePayload>)handleClearSimulatedLocation:(FBRouteRequest *)request
|
|
537
|
+
{
|
|
538
|
+
NSError *error;
|
|
539
|
+
if (![XCUIDevice.sharedDevice fb_clearSimulatedLocation:&error]) {
|
|
540
|
+
return FBResponseWithStatus([FBCommandStatus unknownErrorWithMessage:error.description
|
|
541
|
+
traceback:nil]);
|
|
542
|
+
}
|
|
543
|
+
return FBResponseWithOK();
|
|
544
|
+
}
|
|
545
|
+
#endif
|
|
546
|
+
|
|
493
547
|
@end
|
|
@@ -66,9 +66,16 @@
|
|
|
66
66
|
if (!urlString) {
|
|
67
67
|
return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:@"URL is required" traceback:nil]);
|
|
68
68
|
}
|
|
69
|
+
NSString* bundleId = request.arguments[@"bundleId"];
|
|
69
70
|
NSError *error;
|
|
70
|
-
if (
|
|
71
|
-
|
|
71
|
+
if (nil == bundleId) {
|
|
72
|
+
if (![XCUIDevice.sharedDevice fb_openUrl:urlString error:&error]) {
|
|
73
|
+
return FBResponseWithUnknownError(error);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
if (![XCUIDevice.sharedDevice fb_openUrl:urlString withApplication:bundleId error:&error]) {
|
|
77
|
+
return FBResponseWithUnknownError(error);
|
|
78
|
+
}
|
|
72
79
|
}
|
|
73
80
|
return FBResponseWithOK();
|
|
74
81
|
}
|
|
@@ -502,7 +502,9 @@ static NSNumberFormatter *numberFormatter = nil;
|
|
|
502
502
|
return [[FBErrorBuilder.builder withDescription:fullDescription] build];
|
|
503
503
|
}
|
|
504
504
|
|
|
505
|
-
+ (nullable FBClassChain*)compiledQueryWithTokenizedQuery:(NSArray<FBBaseClassChainToken *> *)tokenizedQuery
|
|
505
|
+
+ (nullable FBClassChain*)compiledQueryWithTokenizedQuery:(NSArray<FBBaseClassChainToken *> *)tokenizedQuery
|
|
506
|
+
originalQuery:(NSString *)originalQuery
|
|
507
|
+
error:(NSError **)error
|
|
506
508
|
{
|
|
507
509
|
NSMutableArray *result = [NSMutableArray array];
|
|
508
510
|
XCUIElementType chainElementType = XCUIElementTypeAny;
|
|
@@ -514,8 +516,10 @@ static NSNumberFormatter *numberFormatter = nil;
|
|
|
514
516
|
for (FBBaseClassChainToken *token in tokenizedQuery) {
|
|
515
517
|
if ([token isKindOfClass:FBClassNameToken.class]) {
|
|
516
518
|
if (isTypeSet) {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
+
if (error) {
|
|
520
|
+
NSString *description = [NSString stringWithFormat:@"Unexpected token '%@'. The type name can be set only once.", token.asString];
|
|
521
|
+
*error = [self.class compilationErrorWithQuery:originalQuery description:description];
|
|
522
|
+
}
|
|
519
523
|
return nil;
|
|
520
524
|
}
|
|
521
525
|
@try {
|
|
@@ -523,16 +527,20 @@ static NSNumberFormatter *numberFormatter = nil;
|
|
|
523
527
|
isTypeSet = YES;
|
|
524
528
|
} @catch (NSException *e) {
|
|
525
529
|
if ([e.name isEqualToString:FBInvalidArgumentException]) {
|
|
526
|
-
|
|
527
|
-
|
|
530
|
+
if (error) {
|
|
531
|
+
NSString *description = [NSString stringWithFormat:@"'%@' class name is unknown to WDA", token.asString];
|
|
532
|
+
*error = [self.class compilationErrorWithQuery:originalQuery description:description];
|
|
533
|
+
}
|
|
528
534
|
return nil;
|
|
529
535
|
}
|
|
530
536
|
@throw e;
|
|
531
537
|
}
|
|
532
538
|
} else if ([token isKindOfClass:FBStarToken.class]) {
|
|
533
539
|
if (isTypeSet) {
|
|
534
|
-
|
|
535
|
-
|
|
540
|
+
if (error) {
|
|
541
|
+
NSString *description = [NSString stringWithFormat:@"Unexpected token '%@'. The type name can be set only once.", token.asString];
|
|
542
|
+
*error = [self.class compilationErrorWithQuery:originalQuery description:description];
|
|
543
|
+
}
|
|
536
544
|
return nil;
|
|
537
545
|
}
|
|
538
546
|
chainElementType = XCUIElementTypeAny;
|
|
@@ -540,7 +548,9 @@ static NSNumberFormatter *numberFormatter = nil;
|
|
|
540
548
|
} else if ([token isKindOfClass:FBDescendantMarkerToken.class]) {
|
|
541
549
|
if (isDescendantSet) {
|
|
542
550
|
NSString *description = [NSString stringWithFormat:@"Unexpected token '%@'. Descendant markers cannot be duplicated.", token.asString];
|
|
543
|
-
|
|
551
|
+
if (error) {
|
|
552
|
+
*error = [self.class compilationErrorWithQuery:originalQuery description:description];
|
|
553
|
+
}
|
|
544
554
|
return nil;
|
|
545
555
|
}
|
|
546
556
|
isTypeSet = NO;
|
|
@@ -550,12 +560,16 @@ static NSNumberFormatter *numberFormatter = nil;
|
|
|
550
560
|
} else if ([token isKindOfClass:FBAbstractPredicateToken.class]) {
|
|
551
561
|
if (isPositionSet) {
|
|
552
562
|
NSString *description = [NSString stringWithFormat:@"Predicate value '%@' must be set before position value.", token.asString];
|
|
553
|
-
|
|
563
|
+
if (error) {
|
|
564
|
+
*error = [self.class compilationErrorWithQuery:originalQuery description:description];
|
|
565
|
+
}
|
|
554
566
|
return nil;
|
|
555
567
|
}
|
|
556
568
|
if (!((FBAbstractPredicateToken *)token).isParsingCompleted) {
|
|
557
569
|
NSString *description = [NSString stringWithFormat:@"Cannot find the end of '%@' predicate value.", token.asString];
|
|
558
|
-
|
|
570
|
+
if (error) {
|
|
571
|
+
*error = [self.class compilationErrorWithQuery:originalQuery description:description];
|
|
572
|
+
}
|
|
559
573
|
return nil;
|
|
560
574
|
}
|
|
561
575
|
NSPredicate *value = [NSPredicate fb_snapshotBlockPredicateWithPredicate:[NSPredicate predicateWithFormat:token.asString]];
|
|
@@ -567,13 +581,17 @@ static NSNumberFormatter *numberFormatter = nil;
|
|
|
567
581
|
} else if ([token isKindOfClass:FBNumberToken.class]) {
|
|
568
582
|
if (isPositionSet) {
|
|
569
583
|
NSString *description = [NSString stringWithFormat:@"Position value '%@' is expected to be set only once.", token.asString];
|
|
570
|
-
|
|
584
|
+
if (error) {
|
|
585
|
+
*error = [self.class compilationErrorWithQuery:originalQuery description:description];
|
|
586
|
+
}
|
|
571
587
|
return nil;
|
|
572
588
|
}
|
|
573
589
|
NSNumber *position = [numberFormatter numberFromString:token.asString];
|
|
574
590
|
if (nil == position || 0 == position.intValue) {
|
|
575
591
|
NSString *description = [NSString stringWithFormat:@"Position value '%@' is expected to be a valid integer number not equal to zero.", token.asString];
|
|
576
|
-
|
|
592
|
+
if (error) {
|
|
593
|
+
*error = [self.class compilationErrorWithQuery:originalQuery description:description];
|
|
594
|
+
}
|
|
577
595
|
return nil;
|
|
578
596
|
}
|
|
579
597
|
chainElementPosition = position;
|
|
@@ -602,8 +620,10 @@ static NSNumberFormatter *numberFormatter = nil;
|
|
|
602
620
|
if (isTypeSet) {
|
|
603
621
|
[result addObject:[[FBClassChainItem alloc] initWithType:chainElementType position:chainElementPosition predicates:predicates.copy isDescendant:YES]];
|
|
604
622
|
} else {
|
|
605
|
-
|
|
606
|
-
|
|
623
|
+
if (error) {
|
|
624
|
+
NSString *description = @"Descendants lookup modifier '**/' should be followed with the actual element type";
|
|
625
|
+
*error = [self.class compilationErrorWithQuery:originalQuery description:description];
|
|
626
|
+
}
|
|
607
627
|
return nil;
|
|
608
628
|
}
|
|
609
629
|
} else {
|
|
@@ -47,7 +47,7 @@ void *FBRetrieveSymbolFromBinary(const char *binary, const char *name)
|
|
|
47
47
|
|
|
48
48
|
static NSString *sdkVersion = nil;
|
|
49
49
|
static dispatch_once_t onceSdkVersionToken;
|
|
50
|
-
NSString * _Nullable FBSDKVersion()
|
|
50
|
+
NSString * _Nullable FBSDKVersion(void)
|
|
51
51
|
{
|
|
52
52
|
dispatch_once(&onceSdkVersionToken, ^{
|
|
53
53
|
NSString *sdkName = [[NSBundle mainBundle] infoDictionary][@"DTSDKName"];
|
|
@@ -8,15 +8,17 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
#import <XCTest/XCTest.h>
|
|
11
|
+
|
|
12
|
+
#if !TARGET_OS_TV
|
|
13
|
+
#import <CoreLocation/CoreLocation.h>
|
|
14
|
+
#endif
|
|
15
|
+
|
|
11
16
|
#import "XCSynthesizedEventRecord.h"
|
|
12
17
|
|
|
13
18
|
NS_ASSUME_NONNULL_BEGIN
|
|
14
19
|
|
|
15
20
|
@protocol XCTestManager_ManagerInterface;
|
|
16
21
|
|
|
17
|
-
/**
|
|
18
|
-
Temporary class used to abstract interactions with TestManager daemon between Xcode 8.2.1 and Xcode 8.3-beta
|
|
19
|
-
*/
|
|
20
22
|
@interface FBXCTestDaemonsProxy : NSObject
|
|
21
23
|
|
|
22
24
|
+ (id<XCTestManager_ManagerInterface>)testRunnerProxy;
|
|
@@ -28,6 +30,15 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
28
30
|
+ (BOOL)synthesizeEventWithRecord:(XCSynthesizedEventRecord *)record
|
|
29
31
|
error:(NSError *__autoreleasing*)error;
|
|
30
32
|
|
|
33
|
+
+ (BOOL)openURL:(NSURL *)url usingApplication:(NSString *)bundleId error:(NSError **)error;
|
|
34
|
+
+ (BOOL)openDefaultApplicationForURL:(NSURL *)url error:(NSError **)error;
|
|
35
|
+
|
|
36
|
+
#if !TARGET_OS_TV
|
|
37
|
+
+ (BOOL)setSimulatedLocation:(CLLocation *)location error:(NSError **)error;
|
|
38
|
+
+ (nullable CLLocation *)getSimulatedLocation:(NSError **)error;
|
|
39
|
+
+ (BOOL)clearSimulatedLocation:(NSError **)error;
|
|
40
|
+
#endif
|
|
41
|
+
|
|
31
42
|
@end
|
|
32
43
|
|
|
33
44
|
NS_ASSUME_NONNULL_END
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
#import <objc/runtime.h>
|
|
13
13
|
|
|
14
14
|
#import "FBConfiguration.h"
|
|
15
|
+
#import "FBErrorBuilder.h"
|
|
15
16
|
#import "FBLogger.h"
|
|
16
17
|
#import "FBRunLoopSpinner.h"
|
|
17
18
|
#import "XCTestDriver.h"
|
|
@@ -96,4 +97,157 @@ static dispatch_once_t onceTestRunnerDaemonClass;
|
|
|
96
97
|
return didSucceed;
|
|
97
98
|
}
|
|
98
99
|
|
|
100
|
+
+ (BOOL)openURL:(NSURL *)url usingApplication:(NSString *)bundleId error:(NSError *__autoreleasing*)error
|
|
101
|
+
{
|
|
102
|
+
XCTRunnerDaemonSession *session = [FBXCTRunnerDaemonSessionClass sharedSession];
|
|
103
|
+
if (![session respondsToSelector:@selector(openURL:usingApplication:completion:)]) {
|
|
104
|
+
if (error) {
|
|
105
|
+
[[[FBErrorBuilder builder]
|
|
106
|
+
withDescriptionFormat:@"The current Xcode SDK does not support opening of URLs with given application"]
|
|
107
|
+
buildError:error];
|
|
108
|
+
}
|
|
109
|
+
return NO;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
__block BOOL didSucceed = NO;
|
|
113
|
+
[FBRunLoopSpinner spinUntilCompletion:^(void(^completion)(void)){
|
|
114
|
+
[session openURL:url usingApplication:bundleId completion:^(bool result, NSError *invokeError) {
|
|
115
|
+
if (error) {
|
|
116
|
+
*error = invokeError;
|
|
117
|
+
}
|
|
118
|
+
didSucceed = invokeError == nil && result;
|
|
119
|
+
completion();
|
|
120
|
+
}];
|
|
121
|
+
}];
|
|
122
|
+
return didSucceed;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
+ (BOOL)openDefaultApplicationForURL:(NSURL *)url error:(NSError *__autoreleasing*)error
|
|
126
|
+
{
|
|
127
|
+
XCTRunnerDaemonSession *session = [FBXCTRunnerDaemonSessionClass sharedSession];
|
|
128
|
+
if (![session respondsToSelector:@selector(openDefaultApplicationForURL:completion:)]) {
|
|
129
|
+
if (error) {
|
|
130
|
+
[[[FBErrorBuilder builder]
|
|
131
|
+
withDescriptionFormat:@"The current Xcode SDK does not support opening of URLs. Consider upgrading to Xcode 14.3+/iOS 16.4+"]
|
|
132
|
+
buildError:error];
|
|
133
|
+
}
|
|
134
|
+
return NO;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
__block BOOL didSucceed = NO;
|
|
138
|
+
[FBRunLoopSpinner spinUntilCompletion:^(void(^completion)(void)){
|
|
139
|
+
[session openDefaultApplicationForURL:url completion:^(bool result, NSError *invokeError) {
|
|
140
|
+
if (error) {
|
|
141
|
+
*error = invokeError;
|
|
142
|
+
}
|
|
143
|
+
didSucceed = invokeError == nil && result;
|
|
144
|
+
completion();
|
|
145
|
+
}];
|
|
146
|
+
}];
|
|
147
|
+
return didSucceed;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
#if !TARGET_OS_TV
|
|
151
|
+
+ (BOOL)setSimulatedLocation:(CLLocation *)location error:(NSError *__autoreleasing*)error
|
|
152
|
+
{
|
|
153
|
+
XCTRunnerDaemonSession *session = [FBXCTRunnerDaemonSessionClass sharedSession];
|
|
154
|
+
if (![session respondsToSelector:@selector(setSimulatedLocation:completion:)]) {
|
|
155
|
+
if (error) {
|
|
156
|
+
[[[FBErrorBuilder builder]
|
|
157
|
+
withDescriptionFormat:@"The current Xcode SDK does not support location simulation. Consider upgrading to Xcode 14.3+/iOS 16.4+"]
|
|
158
|
+
buildError:error];
|
|
159
|
+
}
|
|
160
|
+
return NO;
|
|
161
|
+
}
|
|
162
|
+
if (![session supportsLocationSimulation]) {
|
|
163
|
+
if (error) {
|
|
164
|
+
[[[FBErrorBuilder builder]
|
|
165
|
+
withDescriptionFormat:@"Your device does not support location simulation"]
|
|
166
|
+
buildError:error];
|
|
167
|
+
}
|
|
168
|
+
return NO;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
__block BOOL didSucceed = NO;
|
|
172
|
+
[FBRunLoopSpinner spinUntilCompletion:^(void(^completion)(void)){
|
|
173
|
+
[session setSimulatedLocation:location completion:^(bool result, NSError *invokeError) {
|
|
174
|
+
if (error) {
|
|
175
|
+
*error = invokeError;
|
|
176
|
+
}
|
|
177
|
+
didSucceed = invokeError == nil && result;
|
|
178
|
+
completion();
|
|
179
|
+
}];
|
|
180
|
+
}];
|
|
181
|
+
return didSucceed;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
+ (nullable CLLocation *)getSimulatedLocation:(NSError *__autoreleasing*)error;
|
|
185
|
+
{
|
|
186
|
+
XCTRunnerDaemonSession *session = [FBXCTRunnerDaemonSessionClass sharedSession];
|
|
187
|
+
if (![session respondsToSelector:@selector(getSimulatedLocationWithReply:)]) {
|
|
188
|
+
if (error) {
|
|
189
|
+
[[[FBErrorBuilder builder]
|
|
190
|
+
withDescriptionFormat:@"The current Xcode SDK does not support location simulation. Consider upgrading to Xcode 14.3+/iOS 16.4+"]
|
|
191
|
+
buildError:error];
|
|
192
|
+
}
|
|
193
|
+
return nil;
|
|
194
|
+
}
|
|
195
|
+
if (![session supportsLocationSimulation]) {
|
|
196
|
+
if (error) {
|
|
197
|
+
[[[FBErrorBuilder builder]
|
|
198
|
+
withDescriptionFormat:@"Your device does not support location simulation"]
|
|
199
|
+
buildError:error];
|
|
200
|
+
}
|
|
201
|
+
return nil;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
__block CLLocation *location = nil;
|
|
205
|
+
[FBRunLoopSpinner spinUntilCompletion:^(void(^completion)(void)){
|
|
206
|
+
[session getSimulatedLocationWithReply:^(CLLocation *reply, NSError *invokeError) {
|
|
207
|
+
if (error) {
|
|
208
|
+
*error = invokeError;
|
|
209
|
+
}
|
|
210
|
+
if (nil == invokeError) {
|
|
211
|
+
location = reply;
|
|
212
|
+
}
|
|
213
|
+
completion();
|
|
214
|
+
}];
|
|
215
|
+
}];
|
|
216
|
+
return location;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
+ (BOOL)clearSimulatedLocation:(NSError *__autoreleasing*)error
|
|
220
|
+
{
|
|
221
|
+
XCTRunnerDaemonSession *session = [FBXCTRunnerDaemonSessionClass sharedSession];
|
|
222
|
+
if (![session respondsToSelector:@selector(clearSimulatedLocationWithReply:)]) {
|
|
223
|
+
if (error) {
|
|
224
|
+
[[[FBErrorBuilder builder]
|
|
225
|
+
withDescriptionFormat:@"The current Xcode SDK does not support location simulation. Consider upgrading to Xcode 14.3+/iOS 16.4+"]
|
|
226
|
+
buildError:error];
|
|
227
|
+
}
|
|
228
|
+
return NO;
|
|
229
|
+
}
|
|
230
|
+
if (![session supportsLocationSimulation]) {
|
|
231
|
+
if (error) {
|
|
232
|
+
[[[FBErrorBuilder builder]
|
|
233
|
+
withDescriptionFormat:@"Your device does not support location simulation"]
|
|
234
|
+
buildError:error];
|
|
235
|
+
}
|
|
236
|
+
return NO;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
__block BOOL didSucceed = NO;
|
|
240
|
+
[FBRunLoopSpinner spinUntilCompletion:^(void(^completion)(void)){
|
|
241
|
+
[session clearSimulatedLocationWithReply:^(bool result, NSError *invokeError) {
|
|
242
|
+
if (error) {
|
|
243
|
+
*error = invokeError;
|
|
244
|
+
}
|
|
245
|
+
didSucceed = invokeError == nil && result;
|
|
246
|
+
completion();
|
|
247
|
+
}];
|
|
248
|
+
}];
|
|
249
|
+
return didSucceed;
|
|
250
|
+
}
|
|
251
|
+
#endif
|
|
252
|
+
|
|
99
253
|
@end
|
|
@@ -118,15 +118,57 @@
|
|
|
118
118
|
XCTAssertNil(error);
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
- (void)
|
|
121
|
+
- (void)testUrlSchemeActivation
|
|
122
122
|
{
|
|
123
|
-
|
|
123
|
+
if (SYSTEM_VERSION_LESS_THAN(@"16.4")) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
124
127
|
NSError *error;
|
|
125
128
|
XCTAssertTrue([XCUIDevice.sharedDevice fb_openUrl:@"https://apple.com" error:&error]);
|
|
126
129
|
FBAssertWaitTillBecomesTrue([FBApplication.fb_activeApplication.bundleID isEqualToString:@"com.apple.mobilesafari"]);
|
|
127
130
|
XCTAssertNil(error);
|
|
128
131
|
}
|
|
129
132
|
|
|
133
|
+
- (void)testUrlSchemeActivationWithApp
|
|
134
|
+
{
|
|
135
|
+
if (SYSTEM_VERSION_LESS_THAN(@"16.4")) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
NSError *error;
|
|
140
|
+
XCTAssertTrue([XCUIDevice.sharedDevice fb_openUrl:@"https://apple.com"
|
|
141
|
+
withApplication:@"com.apple.mobilesafari"
|
|
142
|
+
error:&error]);
|
|
143
|
+
FBAssertWaitTillBecomesTrue([FBApplication.fb_activeApplication.bundleID isEqualToString:@"com.apple.mobilesafari"]);
|
|
144
|
+
XCTAssertNil(error);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#if !TARGET_OS_TV
|
|
148
|
+
- (void)testSimulatedLocationSetup
|
|
149
|
+
{
|
|
150
|
+
if (SYSTEM_VERSION_LESS_THAN(@"16.4")) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
CLLocation *simulatedLocation = [[CLLocation alloc] initWithLatitude:50 longitude:50];
|
|
155
|
+
NSError *error;
|
|
156
|
+
XCTAssertTrue([XCUIDevice.sharedDevice fb_setSimulatedLocation:simulatedLocation error:&error]);
|
|
157
|
+
XCTAssertNil(error);
|
|
158
|
+
CLLocation *currentLocation = [XCUIDevice.sharedDevice fb_getSimulatedLocation:&error];
|
|
159
|
+
XCTAssertNil(error);
|
|
160
|
+
XCTAssertNotNil(currentLocation);
|
|
161
|
+
XCTAssertEqualWithAccuracy(simulatedLocation.coordinate.latitude, currentLocation.coordinate.latitude, 0.1);
|
|
162
|
+
XCTAssertEqualWithAccuracy(simulatedLocation.coordinate.longitude, currentLocation.coordinate.longitude, 0.1);
|
|
163
|
+
XCTAssertTrue([XCUIDevice.sharedDevice fb_clearSimulatedLocation:&error]);
|
|
164
|
+
XCTAssertNil(error);
|
|
165
|
+
currentLocation = [XCUIDevice.sharedDevice fb_getSimulatedLocation:&error];
|
|
166
|
+
XCTAssertNil(error);
|
|
167
|
+
XCTAssertNotEqualWithAccuracy(simulatedLocation.coordinate.latitude, currentLocation.coordinate.latitude, 0.1);
|
|
168
|
+
XCTAssertNotEqualWithAccuracy(simulatedLocation.coordinate.longitude, currentLocation.coordinate.longitude, 0.1);
|
|
169
|
+
}
|
|
170
|
+
#endif
|
|
171
|
+
|
|
130
172
|
- (void)testPressingUnsupportedButton
|
|
131
173
|
{
|
|
132
174
|
NSError *error;
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
xmlTextWriterPtr writer = xmlNewTextWriterDoc(&doc, 0);
|
|
30
30
|
NSMutableDictionary *elementStore = [NSMutableDictionary dictionary];
|
|
31
31
|
int buffersize;
|
|
32
|
-
xmlChar *xmlbuff;
|
|
32
|
+
xmlChar *xmlbuff = NULL;
|
|
33
33
|
int rc = xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);
|
|
34
34
|
if (rc >= 0) {
|
|
35
35
|
rc = [FBXPath xmlRepresentationWithRootElement:element
|