appium-webdriveragent 4.11.0 → 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 CHANGED
@@ -1,3 +1,10 @@
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
+
1
8
  ## [4.11.0](https://github.com/appium/WebDriverAgent/compare/v4.10.24...v4.11.0) (2023-02-19)
2
9
 
3
10
 
@@ -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
@@ -70,5 +73,11 @@
70
73
  // Since Xcode 14.3
71
74
  - (void)openURL:(NSURL *)arg1 usingApplication:(NSString *)arg2 completion:(void (^)(_Bool, NSError *))arg3;
72
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
73
82
 
74
83
  @end
@@ -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) {
@@ -154,6 +158,36 @@ typedef NS_ENUM(NSUInteger, FBUIInterfaceAppearance) {
154
158
  */
155
159
  - (nullable NSNumber *)fb_getAppearance;
156
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
+
157
191
  @end
158
192
 
159
193
  NS_ASSUME_NONNULL_END
@@ -355,4 +355,21 @@ static bool fb_isLocked;
355
355
  : nil;
356
356
  }
357
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
+
358
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
- ? FBResponseWithOK()
110
- : FBResponseWithStatus([FBCommandStatus invalidElementStateErrorWithMessage:error.description
111
- traceback:nil]);
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
- instanceMethodSignatureForSelector:@selector(authorizationStatus)]];
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
- ? FBUIInterfaceAppearanceLight
383
- : FBUIInterfaceAppearanceDark;
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
@@ -8,6 +8,11 @@
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
@@ -28,6 +33,12 @@ NS_ASSUME_NONNULL_BEGIN
28
33
  + (BOOL)openURL:(NSURL *)url usingApplication:(NSString *)bundleId error:(NSError **)error;
29
34
  + (BOOL)openDefaultApplicationForURL:(NSURL *)url error:(NSError **)error;
30
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
@@ -147,4 +147,107 @@ static dispatch_once_t onceTestRunnerDaemonClass;
147
147
  return didSucceed;
148
148
  }
149
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
+
150
253
  @end
@@ -144,6 +144,31 @@
144
144
  XCTAssertNil(error);
145
145
  }
146
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
+
147
172
  - (void)testPressingUnsupportedButton
148
173
  {
149
174
  NSError *error;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-webdriveragent",
3
- "version": "4.11.0",
3
+ "version": "4.12.0",
4
4
  "description": "Package bundling WebDriverAgent",
5
5
  "main": "./build/index.js",
6
6
  "scripts": {