appium-webdriveragent 5.15.9 → 6.1.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +17 -2
  2. package/PrivateHeaders/XCTest/XCUIApplication.h +0 -1
  3. package/WebDriverAgent.xcodeproj/project.pbxproj +6 -18
  4. package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h +38 -0
  5. package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +148 -5
  6. package/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m +1 -1
  7. package/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.h +0 -1
  8. package/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.m +5 -3
  9. package/WebDriverAgentLib/Categories/XCUIElement+FBSwiping.h +14 -0
  10. package/WebDriverAgentLib/Categories/XCUIElement+FBSwiping.m +27 -10
  11. package/WebDriverAgentLib/Categories/XCUIElement+FBTVFocuse.m +2 -2
  12. package/WebDriverAgentLib/Commands/FBAlertViewCommands.m +4 -4
  13. package/WebDriverAgentLib/Commands/FBCustomCommands.m +2 -2
  14. package/WebDriverAgentLib/Commands/FBDebugCommands.m +2 -3
  15. package/WebDriverAgentLib/Commands/FBElementCommands.m +113 -89
  16. package/WebDriverAgentLib/Commands/FBFindElementCommands.m +0 -1
  17. package/WebDriverAgentLib/Commands/FBOrientationCommands.m +9 -8
  18. package/WebDriverAgentLib/Commands/FBSessionCommands.m +43 -10
  19. package/WebDriverAgentLib/Commands/FBTouchActionCommands.m +0 -1
  20. package/WebDriverAgentLib/FBAlert.m +3 -3
  21. package/WebDriverAgentLib/Routing/FBSession.h +13 -14
  22. package/WebDriverAgentLib/Routing/FBSession.m +49 -46
  23. package/WebDriverAgentLib/Utilities/FBAlertsMonitor.m +3 -3
  24. package/WebDriverAgentLib/Utilities/FBCapabilities.h +20 -0
  25. package/WebDriverAgentLib/Utilities/FBCapabilities.m +1 -0
  26. package/WebDriverAgentLib/Utilities/FBKeyboard.m +6 -5
  27. package/WebDriverAgentLib/Utilities/FBMjpegServer.m +0 -1
  28. package/WebDriverAgentLib/Utilities/FBPasteboard.m +2 -2
  29. package/WebDriverAgentLib/Utilities/FBScreen.m +1 -2
  30. package/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m +1 -2
  31. package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h +0 -33
  32. package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m +2 -40
  33. package/WebDriverAgentLib/WebDriverAgentLib.h +0 -1
  34. package/WebDriverAgentTests/IntegrationTests/FBAutoAlertsHandlerTests.m +2 -3
  35. package/WebDriverAgentTests/IntegrationTests/FBElementVisibilityTests.m +0 -1
  36. package/WebDriverAgentTests/IntegrationTests/FBIntegrationTestCase.h +1 -3
  37. package/WebDriverAgentTests/IntegrationTests/FBIntegrationTestCase.m +5 -5
  38. package/WebDriverAgentTests/IntegrationTests/FBSafariAlertTests.m +1 -2
  39. package/WebDriverAgentTests/IntegrationTests/FBSessionIntegrationTests.m +11 -10
  40. package/WebDriverAgentTests/IntegrationTests/FBTapTest.m +0 -1
  41. package/WebDriverAgentTests/IntegrationTests/FBW3CMultiTouchActionsIntegrationTests.m +0 -1
  42. package/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m +8 -8
  43. package/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m +5 -4
  44. package/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m +0 -1
  45. package/WebDriverAgentTests/UnitTests/Doubles/{FBApplicationDouble.h → XCUIApplicationDouble.h} +1 -1
  46. package/WebDriverAgentTests/UnitTests/Doubles/{FBApplicationDouble.m → XCUIApplicationDouble.m} +3 -3
  47. package/WebDriverAgentTests/UnitTests/FBSessionTests.m +3 -3
  48. package/package.json +2 -14
  49. package/WebDriverAgent.xcodeproj/project.xcworkspace/xcuserdata/kazu.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  50. package/WebDriverAgent.xcodeproj/xcuserdata/kazu.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -1342
  51. package/WebDriverAgentLib/FBApplication.h +0 -49
  52. package/WebDriverAgentLib/FBApplication.m +0 -185
@@ -9,7 +9,6 @@
9
9
 
10
10
  #import "FBElementCommands.h"
11
11
 
12
- #import "FBApplication.h"
13
12
  #import "FBConfiguration.h"
14
13
  #import "FBKeyboard.h"
15
14
  #import "FBRoute.h"
@@ -18,7 +17,6 @@
18
17
  #import "FBElementCache.h"
19
18
  #import "FBErrorBuilder.h"
20
19
  #import "FBSession.h"
21
- #import "FBApplication.h"
22
20
  #import "FBElementUtils.h"
23
21
  #import "FBMacros.h"
24
22
  #import "FBMathUtils.h"
@@ -76,24 +74,46 @@
76
74
  [[FBRoute POST:@"/wda/element/:uuid/focuse"] respondWithTarget:self action:@selector(handleFocuse:)],
77
75
  #else
78
76
  [[FBRoute POST:@"/wda/element/:uuid/swipe"] respondWithTarget:self action:@selector(handleSwipe:)],
77
+ [[FBRoute POST:@"/wda/swipe"] respondWithTarget:self action:@selector(handleSwipe:)],
78
+
79
79
  [[FBRoute POST:@"/wda/element/:uuid/pinch"] respondWithTarget:self action:@selector(handlePinch:)],
80
+ [[FBRoute POST:@"/wda/pinch"] respondWithTarget:self action:@selector(handlePinch:)],
81
+
80
82
  [[FBRoute POST:@"/wda/element/:uuid/rotate"] respondWithTarget:self action:@selector(handleRotate:)],
83
+ [[FBRoute POST:@"/wda/rotate"] respondWithTarget:self action:@selector(handleRotate:)],
84
+
81
85
  [[FBRoute POST:@"/wda/element/:uuid/doubleTap"] respondWithTarget:self action:@selector(handleDoubleTap:)],
86
+ [[FBRoute POST:@"/wda/doubleTap"] respondWithTarget:self action:@selector(handleDoubleTap:)],
87
+
82
88
  [[FBRoute POST:@"/wda/element/:uuid/twoFingerTap"] respondWithTarget:self action:@selector(handleTwoFingerTap:)],
83
- [[FBRoute POST:@"/wda/element/:uuid/tapWithNumberOfTaps"] respondWithTarget:self action:@selector(handleTapWithNumberOfTaps:)],
89
+ [[FBRoute POST:@"/wda/twoFingerTap"] respondWithTarget:self action:@selector(handleTwoFingerTap:)],
90
+
91
+ [[FBRoute POST:@"/wda/element/:uuid/tapWithNumberOfTaps"] respondWithTarget:self
92
+ action:@selector(handleTapWithNumberOfTaps:)],
93
+ [[FBRoute POST:@"/wda/tapWithNumberOfTaps"] respondWithTarget:self
94
+ action:@selector(handleTapWithNumberOfTaps:)],
95
+
84
96
  [[FBRoute POST:@"/wda/element/:uuid/touchAndHold"] respondWithTarget:self action:@selector(handleTouchAndHold:)],
97
+ [[FBRoute POST:@"/wda/touchAndHold"] respondWithTarget:self action:@selector(handleTouchAndHold:)],
98
+
85
99
  [[FBRoute POST:@"/wda/element/:uuid/scroll"] respondWithTarget:self action:@selector(handleScroll:)],
100
+ [[FBRoute POST:@"/wda/scroll"] respondWithTarget:self action:@selector(handleScroll:)],
101
+
86
102
  [[FBRoute POST:@"/wda/element/:uuid/scrollTo"] respondWithTarget:self action:@selector(handleScrollTo:)],
103
+
87
104
  [[FBRoute POST:@"/wda/element/:uuid/dragfromtoforduration"] respondWithTarget:self action:@selector(handleDrag:)],
105
+ [[FBRoute POST:@"/wda/dragfromtoforduration"] respondWithTarget:self action:@selector(handleDrag:)],
106
+
88
107
  [[FBRoute POST:@"/wda/element/:uuid/pressAndDragWithVelocity"] respondWithTarget:self action:@selector(handlePressAndDragWithVelocity:)],
89
- [[FBRoute POST:@"/wda/element/:uuid/forceTouch"] respondWithTarget:self action:@selector(handleForceTouch:)],
90
- [[FBRoute POST:@"/wda/dragfromtoforduration"] respondWithTarget:self action:@selector(handleDragCoordinate:)],
91
108
  [[FBRoute POST:@"/wda/pressAndDragWithVelocity"] respondWithTarget:self action:@selector(handlePressAndDragCoordinateWithVelocity:)],
92
- [[FBRoute POST:@"/wda/tap/:uuid"] respondWithTarget:self action:@selector(handleTap:)],
93
- [[FBRoute POST:@"/wda/touchAndHold"] respondWithTarget:self action:@selector(handleTouchAndHoldCoordinate:)],
94
- [[FBRoute POST:@"/wda/doubleTap"] respondWithTarget:self action:@selector(handleDoubleTapCoordinate:)],
95
- [[FBRoute POST:@"/wda/pickerwheel/:uuid/select"] respondWithTarget:self action:@selector(handleWheelSelect:)],
109
+
110
+ [[FBRoute POST:@"/wda/element/:uuid/forceTouch"] respondWithTarget:self action:@selector(handleForceTouch:)],
96
111
  [[FBRoute POST:@"/wda/forceTouch"] respondWithTarget:self action:@selector(handleForceTouch:)],
112
+
113
+ [[FBRoute POST:@"/wda/element/:uuid/tap"] respondWithTarget:self action:@selector(handleTap:)],
114
+ [[FBRoute POST:@"/wda/tap"] respondWithTarget:self action:@selector(handleTap:)],
115
+
116
+ [[FBRoute POST:@"/wda/pickerwheel/:uuid/select"] respondWithTarget:self action:@selector(handleWheelSelect:)],
97
117
  #endif
98
118
  [[FBRoute POST:@"/wda/keys"] respondWithTarget:self action:@selector(handleKeys:)],
99
119
  ];
@@ -287,38 +307,30 @@
287
307
  #else
288
308
  + (id<FBResponsePayload>)handleDoubleTap:(FBRouteRequest *)request
289
309
  {
290
- FBElementCache *elementCache = request.session.elementCache;
291
- XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
292
- [element doubleTap];
293
- return FBResponseWithOK();
294
- }
295
-
296
- + (id<FBResponsePayload>)handleDoubleTapCoordinate:(FBRouteRequest *)request
297
- {
298
- CGVector offset = CGVectorMake([request.arguments[@"x"] doubleValue],
299
- [request.arguments[@"y"] doubleValue]);
300
- XCUICoordinate *doubleTapCoordinate = [self.class gestureCoordinateWithOffset:offset
301
- element:request.session.activeApplication];
302
- [doubleTapCoordinate doubleTap];
310
+ NSError *error;
311
+ id target = [self targetWithXyCoordinatesFromRequest:request error:&error];
312
+ if (nil == target) {
313
+ return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:error.localizedDescription
314
+ traceback:nil]);
315
+ }
316
+ [target doubleTap];
303
317
  return FBResponseWithOK();
304
318
  }
305
319
 
306
320
  + (id<FBResponsePayload>)handleTwoFingerTap:(FBRouteRequest *)request
307
321
  {
308
- FBElementCache *elementCache = request.session.elementCache;
309
- XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
322
+ XCUIElement *element = [self targetFromRequest:request];
310
323
  [element twoFingerTap];
311
324
  return FBResponseWithOK();
312
325
  }
313
326
 
314
327
  + (id<FBResponsePayload>)handleTapWithNumberOfTaps:(FBRouteRequest *)request
315
328
  {
316
- FBElementCache *elementCache = request.session.elementCache;
317
329
  if (nil == request.arguments[@"numberOfTaps"] || nil == request.arguments[@"numberOfTouches"]) {
318
330
  return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:@"Both 'numberOfTaps' and 'numberOfTouches' arguments must be provided"
319
331
  traceback:nil]);
320
332
  }
321
- XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
333
+ XCUIElement *element = [self targetFromRequest:request];
322
334
  [element tapWithNumberOfTaps:[request.arguments[@"numberOfTaps"] integerValue]
323
335
  numberOfTouches:[request.arguments[@"numberOfTouches"] integerValue]];
324
336
  return FBResponseWithOK();
@@ -326,26 +338,20 @@
326
338
 
327
339
  + (id<FBResponsePayload>)handleTouchAndHold:(FBRouteRequest *)request
328
340
  {
329
- FBElementCache *elementCache = request.session.elementCache;
330
- XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
331
- [element pressForDuration:[request.arguments[@"duration"] doubleValue]];
332
- return FBResponseWithOK();
333
- }
334
-
335
- + (id<FBResponsePayload>)handleTouchAndHoldCoordinate:(FBRouteRequest *)request
336
- {
337
- CGVector offset = CGVectorMake([request.arguments[@"x"] doubleValue],
338
- [request.arguments[@"y"] doubleValue]);
339
- XCUICoordinate *pressCoordinate = [self.class gestureCoordinateWithOffset:offset
340
- element:request.session.activeApplication];
341
- [pressCoordinate pressForDuration:[request.arguments[@"duration"] doubleValue]];
341
+ NSError *error;
342
+ id target = [self targetWithXyCoordinatesFromRequest:request error:&error];
343
+ if (nil == target) {
344
+ return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:error.localizedDescription
345
+ traceback:nil]);
346
+ }
347
+ [target pressForDuration:[request.arguments[@"duration"] doubleValue]];
342
348
  return FBResponseWithOK();
343
349
  }
344
350
 
345
351
  + (id<FBResponsePayload>)handlePressAndDragWithVelocity:(FBRouteRequest *)request
346
352
  {
347
353
  FBElementCache *elementCache = request.session.elementCache;
348
- XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
354
+ XCUIElement *element = [self targetFromRequest:request];
349
355
  if (![element respondsToSelector:@selector(pressForDuration:thenDragToElement:withVelocity:thenHoldForDuration:)]) {
350
356
  return FBResponseWithStatus([FBCommandStatus unsupportedOperationErrorWithMessage:@"This method is only supported in Xcode 12 and above"
351
357
  traceback:nil]);
@@ -381,8 +387,7 @@
381
387
 
382
388
  + (id<FBResponsePayload>)handleScroll:(FBRouteRequest *)request
383
389
  {
384
- FBElementCache *elementCache = request.session.elementCache;
385
- XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
390
+ XCUIElement *element = [self targetFromRequest:request];
386
391
  // Using presence of arguments as a way to convey control flow seems like a pretty bad idea but it's
387
392
  // what ios-driver did and sadly, we must copy them.
388
393
  NSString *const name = request.arguments[@"name"];
@@ -442,33 +447,18 @@
442
447
  traceback:nil]);
443
448
  }
444
449
 
445
- + (id<FBResponsePayload>)handleDragCoordinate:(FBRouteRequest *)request
446
- {
447
- FBSession *session = request.session;
448
- CGVector startOffset = CGVectorMake([request.arguments[@"fromX"] doubleValue],
449
- [request.arguments[@"fromY"] doubleValue]);
450
- XCUICoordinate *startCoordinate = [self.class gestureCoordinateWithOffset:startOffset
451
- element:session.activeApplication];
452
- CGVector endOffset = CGVectorMake([request.arguments[@"toX"] doubleValue],
453
- [request.arguments[@"toY"] doubleValue]);
454
- XCUICoordinate *endCoordinate = [self.class gestureCoordinateWithOffset:endOffset
455
- element:session.activeApplication];
456
- NSTimeInterval duration = [request.arguments[@"duration"] doubleValue];
457
- [startCoordinate pressForDuration:duration thenDragToCoordinate:endCoordinate];
458
- return FBResponseWithOK();
459
- }
460
-
461
450
  + (id<FBResponsePayload>)handleDrag:(FBRouteRequest *)request
462
451
  {
463
- FBSession *session = request.session;
464
- FBElementCache *elementCache = session.elementCache;
465
- XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
452
+ NSString *elementUdid = (NSString *)request.parameters[@"uuid"];
453
+ XCUIElement *target = nil == elementUdid
454
+ ? request.session.activeApplication
455
+ : [request.session.elementCache elementForUUID:elementUdid];
466
456
  CGVector startOffset = CGVectorMake([request.arguments[@"fromX"] doubleValue],
467
457
  [request.arguments[@"fromY"] doubleValue]);
468
- XCUICoordinate *startCoordinate = [self.class gestureCoordinateWithOffset:startOffset element:element];
458
+ XCUICoordinate *startCoordinate = [self.class gestureCoordinateWithOffset:startOffset element:target];
469
459
  CGVector endOffset = CGVectorMake([request.arguments[@"toX"] doubleValue],
470
460
  [request.arguments[@"toY"] doubleValue]);
471
- XCUICoordinate *endCoordinate = [self.class gestureCoordinateWithOffset:endOffset element:element];
461
+ XCUICoordinate *endCoordinate = [self.class gestureCoordinateWithOffset:endOffset element:target];
472
462
  NSTimeInterval duration = [request.arguments[@"duration"] doubleValue];
473
463
  [startCoordinate pressForDuration:duration thenDragToCoordinate:endCoordinate];
474
464
  return FBResponseWithOK();
@@ -476,39 +466,41 @@
476
466
 
477
467
  + (id<FBResponsePayload>)handleSwipe:(FBRouteRequest *)request
478
468
  {
479
- FBElementCache *elementCache = request.session.elementCache;
480
- XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
481
469
  NSString *const direction = request.arguments[@"direction"];
482
470
  if (!direction) {
483
471
  return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:@"Missing 'direction' parameter" traceback:nil]);
484
472
  }
485
473
  NSArray<NSString *> *supportedDirections = @[@"up", @"down", @"left", @"right"];
486
474
  if (![supportedDirections containsObject:direction.lowercaseString]) {
487
- return FBResponseWithStatus([FBCommandStatus
488
- invalidArgumentErrorWithMessage:[NSString stringWithFormat: @"Unsupported swipe direction '%@'. Only the following directions are supported: %@", direction, supportedDirections]
489
- traceback:nil]);
475
+ NSString *message = [NSString stringWithFormat:@"Unsupported swipe direction '%@'. Only the following directions are supported: %@", direction, supportedDirections];
476
+ return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:message
477
+ traceback:nil]);
490
478
  }
491
- [element fb_swipeWithDirection:direction.lowercaseString velocity:request.arguments[@"velocity"]];
479
+ NSError *error;
480
+ id target = [self targetWithXyCoordinatesFromRequest:request error:&error];
481
+ if (nil == target) {
482
+ return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:error.localizedDescription
483
+ traceback:nil]);
484
+ }
485
+ [target fb_swipeWithDirection:direction velocity:request.arguments[@"velocity"]];
492
486
  return FBResponseWithOK();
493
487
  }
494
488
 
495
489
  + (id<FBResponsePayload>)handleTap:(FBRouteRequest *)request
496
490
  {
497
- FBElementCache *elementCache = request.session.elementCache;
498
- CGVector offset = CGVectorMake([request.arguments[@"x"] doubleValue],
499
- [request.arguments[@"y"] doubleValue]);
500
- XCUIElement *element = [elementCache hasElementWithUUID:request.parameters[@"uuid"]]
501
- ? [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]
502
- : request.session.activeApplication;
503
- XCUICoordinate *tapCoordinate = [self.class gestureCoordinateWithOffset:offset element:element];
504
- [tapCoordinate tap];
491
+ NSError *error;
492
+ id target = [self targetWithXyCoordinatesFromRequest:request error:&error];
493
+ if (nil == target) {
494
+ return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:error.localizedDescription
495
+ traceback:nil]);
496
+ }
497
+ [target tap];
505
498
  return FBResponseWithOK();
506
499
  }
507
500
 
508
501
  + (id<FBResponsePayload>)handlePinch:(FBRouteRequest *)request
509
502
  {
510
- FBElementCache *elementCache = request.session.elementCache;
511
- XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
503
+ XCUIElement *element = [self targetFromRequest:request];
512
504
  CGFloat scale = (CGFloat)[request.arguments[@"scale"] doubleValue];
513
505
  CGFloat velocity = (CGFloat)[request.arguments[@"velocity"] doubleValue];
514
506
  [element pinchWithScale:scale velocity:velocity];
@@ -517,8 +509,7 @@
517
509
 
518
510
  + (id<FBResponsePayload>)handleRotate:(FBRouteRequest *)request
519
511
  {
520
- FBElementCache *elementCache = request.session.elementCache;
521
- XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
512
+ XCUIElement *element = [self targetFromRequest:request];
522
513
  CGFloat rotation = (CGFloat)[request.arguments[@"rotation"] doubleValue];
523
514
  CGFloat velocity = (CGFloat)[request.arguments[@"velocity"] doubleValue];
524
515
  [element rotate:rotation withVelocity:velocity];
@@ -527,13 +518,7 @@
527
518
 
528
519
  + (id<FBResponsePayload>)handleForceTouch:(FBRouteRequest *)request
529
520
  {
530
- XCUIElement *element = nil;
531
- if (nil == request.parameters[@"uuid"]) {
532
- element = [FBApplication fb_activeApplication];
533
- } else {
534
- FBElementCache *elementCache = request.session.elementCache;
535
- element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
536
- }
521
+ XCUIElement *element = [self targetFromRequest:request];
537
522
  NSNumber *pressure = request.arguments[@"pressure"];
538
523
  NSNumber *duration = request.arguments[@"duration"];
539
524
  NSNumber *x = request.arguments[@"x"];
@@ -567,7 +552,7 @@
567
552
 
568
553
  + (id<FBResponsePayload>)handleGetWindowSize:(FBRouteRequest *)request
569
554
  {
570
- XCUIApplication *app = request.session.activeApplication ?: FBApplication.fb_activeApplication;
555
+ XCUIApplication *app = request.session.activeApplication ?: XCUIApplication.fb_activeApplication;
571
556
 
572
557
  #if TARGET_OS_TV
573
558
  CGSize screenSize = app.frame.size;
@@ -675,6 +660,45 @@ static const NSInteger DEFAULT_MAX_PICKER_ATTEMPTS = 25;
675
660
  return [[element coordinateWithNormalizedOffset:CGVectorMake(0, 0)] coordinateWithOffset:offset];
676
661
  }
677
662
 
663
+ /**
664
+ Returns either coordinates or the target element for the given request that expects 'x' and 'y' coordannates
665
+
666
+ @param request HTTP request object
667
+ @param error Error instance if any
668
+ @return Either XCUICoordinate or XCUIElement instance. nil if the input data is invalid
669
+ */
670
+ + (nullable id)targetWithXyCoordinatesFromRequest:(FBRouteRequest *)request error:(NSError **)error
671
+ {
672
+ NSNumber *x = request.arguments[@"x"];
673
+ NSNumber *y = request.arguments[@"y"];
674
+ if (nil == x && nil == y) {
675
+ return [self targetFromRequest:request];
676
+ }
677
+ if ((nil == x && nil != y) || (nil != x && nil == y)) {
678
+ [[[FBErrorBuilder alloc]
679
+ withDescription:@"Both x and y coordinates must be provided"]
680
+ buildError:error];
681
+ return nil;
682
+ }
683
+ return [self gestureCoordinateWithOffset:CGVectorMake(x.doubleValue, y.doubleValue)
684
+ element:[self targetFromRequest:request]];
685
+ }
686
+
687
+ /**
688
+ Returns the target element for the given request
689
+
690
+ @param request HTTP request object
691
+ @return Matching XCUIElement instance
692
+ */
693
+ + (XCUIElement *)targetFromRequest:(FBRouteRequest *)request
694
+ {
695
+ FBElementCache *elementCache = request.session.elementCache;
696
+ NSString *elementUuid = (NSString *)request.parameters[@"uuid"];
697
+ return nil == elementUuid
698
+ ? request.session.activeApplication
699
+ : [elementCache elementForUUID:elementUuid];
700
+ }
701
+
678
702
  #endif
679
703
 
680
704
  @end
@@ -10,7 +10,6 @@
10
10
  #import "FBFindElementCommands.h"
11
11
 
12
12
  #import "FBAlert.h"
13
- #import "FBApplication.h"
14
13
  #import "FBConfiguration.h"
15
14
  #import "FBElementCache.h"
16
15
  #import "FBExceptions.h"
@@ -12,7 +12,8 @@
12
12
  #import "FBRouteRequest.h"
13
13
  #import "FBMacros.h"
14
14
  #import "FBSession.h"
15
- #import "FBApplication.h"
15
+ #import "XCUIApplication.h"
16
+ #import "XCUIApplication+FBHelpers.h"
16
17
  #import "XCUIDevice.h"
17
18
 
18
19
  extern const struct FBWDOrientationValues {
@@ -55,14 +56,14 @@ const struct FBWDOrientationValues FBWDOrientationValues = {
55
56
 
56
57
  + (id<FBResponsePayload>)handleGetOrientation:(FBRouteRequest *)request
57
58
  {
58
- FBApplication *application = request.session.activeApplication ?: FBApplication.fb_activeApplication;
59
+ XCUIApplication *application = request.session.activeApplication ?: XCUIApplication.fb_activeApplication;
59
60
  NSString *orientation = [self.class interfaceOrientationForApplication:application];
60
61
  return FBResponseWithObject([[self _wdOrientationsMapping] objectForKey:orientation]);
61
62
  }
62
63
 
63
64
  + (id<FBResponsePayload>)handleSetOrientation:(FBRouteRequest *)request
64
65
  {
65
- FBApplication *application = request.session.activeApplication ?: FBApplication.fb_activeApplication;
66
+ XCUIApplication *application = request.session.activeApplication ?: XCUIApplication.fb_activeApplication;
66
67
  if ([self.class setDeviceOrientation:request.arguments[@"orientation"] forApplication:application]) {
67
68
  return FBResponseWithOK();
68
69
  }
@@ -73,7 +74,7 @@ const struct FBWDOrientationValues FBWDOrientationValues = {
73
74
  + (id<FBResponsePayload>)handleGetRotation:(FBRouteRequest *)request
74
75
  {
75
76
  XCUIDevice *device = [XCUIDevice sharedDevice];
76
- FBApplication *application = request.session.activeApplication ?: FBApplication.fb_activeApplication;
77
+ XCUIApplication *application = request.session.activeApplication ?: XCUIApplication.fb_activeApplication;
77
78
  UIInterfaceOrientation orientation = application.interfaceOrientation;
78
79
  return FBResponseWithObject(device.fb_rotationMapping[@(orientation)]);
79
80
  }
@@ -101,7 +102,7 @@ const struct FBWDOrientationValues FBWDOrientationValues = {
101
102
  traceback:nil]);
102
103
  }
103
104
 
104
- FBApplication *application = request.session.activeApplication ?: FBApplication.fb_activeApplication;
105
+ XCUIApplication *application = request.session.activeApplication ?: XCUIApplication.fb_activeApplication;
105
106
  if (![self.class setDeviceRotation:request.arguments forApplication:application]) {
106
107
  NSString *errMessage = [
107
108
  NSString stringWithFormat:@"The current rotation cannot be set to %@. Make sure the %@ application supports it",
@@ -116,7 +117,7 @@ const struct FBWDOrientationValues FBWDOrientationValues = {
116
117
 
117
118
  #pragma mark - Helpers
118
119
 
119
- + (NSString *)interfaceOrientationForApplication:(FBApplication *)application
120
+ + (NSString *)interfaceOrientationForApplication:(XCUIApplication *)application
120
121
  {
121
122
  NSNumber *orientation = @(application.interfaceOrientation);
122
123
  NSSet *keys = [[self _orientationsMapping] keysOfEntriesPassingTest:^BOOL(id key, NSNumber *obj, BOOL *stop) {
@@ -128,12 +129,12 @@ const struct FBWDOrientationValues FBWDOrientationValues = {
128
129
  return keys.anyObject;
129
130
  }
130
131
 
131
- + (BOOL)setDeviceRotation:(NSDictionary *)rotationObj forApplication:(FBApplication *)application
132
+ + (BOOL)setDeviceRotation:(NSDictionary *)rotationObj forApplication:(XCUIApplication *)application
132
133
  {
133
134
  return [[XCUIDevice sharedDevice] fb_setDeviceRotation:rotationObj];
134
135
  }
135
136
 
136
- + (BOOL)setDeviceOrientation:(NSString *)orientation forApplication:(FBApplication *)application
137
+ + (BOOL)setDeviceOrientation:(NSString *)orientation forApplication:(XCUIApplication *)application
137
138
  {
138
139
  NSNumber *orientationValue = [[self _orientationsMapping] objectForKey:[orientation uppercaseString]];
139
140
  if (orientationValue == nil) {
@@ -9,7 +9,6 @@
9
9
 
10
10
  #import "FBSessionCommands.h"
11
11
 
12
- #import "FBApplication.h"
13
12
  #import "FBCapabilities.h"
14
13
  #import "FBConfiguration.h"
15
14
  #import "FBLogger.h"
@@ -17,7 +16,6 @@
17
16
  #import "FBRouteRequest.h"
18
17
  #import "FBSession.h"
19
18
  #import "FBSettings.h"
20
- #import "FBApplication.h"
21
19
  #import "FBRuntimeUtils.h"
22
20
  #import "FBActiveAppDetectionPoint.h"
23
21
  #import "FBXCodeCompatibility.h"
@@ -138,28 +136,63 @@
138
136
  }
139
137
 
140
138
  NSString *bundleID = capabilities[FB_CAP_BUNDLE_ID];
141
- FBApplication *app = nil;
139
+ NSString *initialUrl = capabilities[FB_CAP_INITIAL_URL];
140
+ XCUIApplication *app = nil;
141
+ BOOL didOpenInitialUrl = NO;
142
142
  if (bundleID != nil) {
143
- app = [[FBApplication alloc] initWithBundleIdentifier:bundleID];
143
+ app = [[XCUIApplication alloc] initWithBundleIdentifier:bundleID];
144
144
  BOOL forceAppLaunch = YES;
145
145
  if (nil != capabilities[FB_CAP_FORCE_APP_LAUNCH]) {
146
146
  forceAppLaunch = [capabilities[FB_CAP_FORCE_APP_LAUNCH] boolValue];
147
147
  }
148
- NSUInteger appState = [app fb_state];
149
- BOOL isAppRunning = appState >= 2;
148
+ XCUIApplicationState appState = app.state;
149
+ BOOL isAppRunning = appState >= XCUIApplicationStateRunningBackground;
150
150
  if (!isAppRunning || (isAppRunning && forceAppLaunch)) {
151
151
  app.fb_shouldWaitForQuiescence = nil == capabilities[FB_CAP_SHOULD_WAIT_FOR_QUIESCENCE]
152
152
  || [capabilities[FB_CAP_SHOULD_WAIT_FOR_QUIESCENCE] boolValue];
153
153
  app.launchArguments = (NSArray<NSString *> *)capabilities[FB_CAP_ARGUMENTS] ?: @[];
154
154
  app.launchEnvironment = (NSDictionary <NSString *, NSString *> *)capabilities[FB_CAP_ENVIRNOMENT] ?: @{};
155
- [app launch];
155
+ if (nil != initialUrl) {
156
+ NSError *openError;
157
+ didOpenInitialUrl = [XCUIDevice.sharedDevice fb_openUrl:initialUrl
158
+ withApplication:bundleID
159
+ error:&openError];
160
+ if (!didOpenInitialUrl) {
161
+ NSString *errorMsg = [NSString stringWithFormat:@"Cannot open the URL %@ in %@ application. Original error: %@",
162
+ initialUrl, bundleID, openError.description];
163
+ return FBResponseWithStatus([FBCommandStatus sessionNotCreatedError:errorMsg traceback:nil]);
164
+ }
165
+ } else {
166
+ [app launch];
167
+ }
156
168
  if (![app running]) {
157
169
  NSString *errorMsg = [NSString stringWithFormat:@"Cannot launch %@ application. Make sure the correct bundle identifier has been provided in capabilities and check the device log for possible crash report occurrences", bundleID];
158
170
  return FBResponseWithStatus([FBCommandStatus sessionNotCreatedError:errorMsg
159
171
  traceback:nil]);
160
172
  }
161
- } else if (appState < 4 && !forceAppLaunch) {
162
- [app fb_activate];
173
+ } else if (appState == XCUIApplicationStateRunningBackground && !forceAppLaunch) {
174
+ if (nil != initialUrl) {
175
+ NSError *openError;
176
+ didOpenInitialUrl = [XCUIDevice.sharedDevice fb_openUrl:initialUrl
177
+ withApplication:bundleID
178
+ error:&openError];
179
+ if (!didOpenInitialUrl) {
180
+ NSString *errorMsg = [NSString stringWithFormat:@"Cannot open the URL %@ in %@ application. Original error: %@",
181
+ initialUrl, bundleID, openError.description];
182
+ return FBResponseWithStatus([FBCommandStatus sessionNotCreatedError:errorMsg traceback:nil]);
183
+ }
184
+ } else {
185
+ [app activate];
186
+ }
187
+ }
188
+ }
189
+
190
+ if (nil != initialUrl && nil == bundleID) {
191
+ NSError *openError;
192
+ if (![XCUIDevice.sharedDevice fb_openUrl:initialUrl error:&openError]) {
193
+ NSString *errorMsg = [NSString stringWithFormat:@"Cannot open the URL %@. Original error: %@",
194
+ initialUrl, openError.description];
195
+ return FBResponseWithStatus([FBCommandStatus sessionNotCreatedError:errorMsg traceback:nil]);
163
196
  }
164
197
  }
165
198
 
@@ -265,7 +298,7 @@
265
298
 
266
299
  + (id<FBResponsePayload>)handleGetHealthCheck:(FBRouteRequest *)request
267
300
  {
268
- if (![[XCUIDevice sharedDevice] fb_healthCheckWithApplication:[FBApplication fb_activeApplication]]) {
301
+ if (![[XCUIDevice sharedDevice] fb_healthCheckWithApplication:[XCUIApplication fb_activeApplication]]) {
269
302
  return FBResponseWithUnknownErrorFormat(@"Health check failed");
270
303
  }
271
304
  return FBResponseWithOK();
@@ -9,7 +9,6 @@
9
9
 
10
10
  #import "FBTouchActionCommands.h"
11
11
 
12
- #import "FBApplication.h"
13
12
  #import "FBRoute.h"
14
13
  #import "FBRouteRequest.h"
15
14
  #import "FBSession.h"
@@ -9,12 +9,12 @@
9
9
 
10
10
  #import "FBAlert.h"
11
11
 
12
- #import "FBApplication.h"
13
12
  #import "FBConfiguration.h"
14
13
  #import "FBErrorBuilder.h"
15
14
  #import "FBLogger.h"
16
15
  #import "FBXCElementSnapshotWrapper+Helpers.h"
17
16
  #import "FBXCodeCompatibility.h"
17
+ #import "XCUIApplication.h"
18
18
  #import "XCUIApplication+FBAlert.h"
19
19
  #import "XCUIElement+FBClassChain.h"
20
20
  #import "XCUIElement+FBTyping.h"
@@ -263,8 +263,8 @@
263
263
  if (nil == self.element) {
264
264
  self.element = self.application.fb_alertElement;
265
265
  if (nil == self.element) {
266
- FBApplication *systemApp = FBApplication.fb_systemApplication;
267
- for (FBApplication *activeApp in FBApplication.fb_activeApplications) {
266
+ XCUIApplication *systemApp = XCUIApplication.fb_systemApplication;
267
+ for (XCUIApplication *activeApp in XCUIApplication.fb_activeApplications) {
268
268
  if (systemApp.processID == activeApp.processID) {
269
269
  self.element = activeApp.fb_alertElement;
270
270
  break;
@@ -9,8 +9,8 @@
9
9
 
10
10
  #import <Foundation/Foundation.h>
11
11
 
12
- @class FBApplication;
13
12
  @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, strong, readonly) FBApplication *activeApplication;
23
+ @property (nonatomic, readonly) XCUIApplication *activeApplication;
24
24
 
25
25
  /*! Session's identifier */
26
- @property (nonatomic, copy, readonly) NSString *identifier;
26
+ @property (nonatomic, readonly) NSString *identifier;
27
27
 
28
28
  /*! Element cache related to that session */
29
- @property (nonatomic, strong, readonly) FBElementCache *elementCache;
29
+ @property (nonatomic, readonly) FBElementCache *elementCache;
30
30
 
31
31
  /*! The identifier of the active application */
32
- @property (nonatomic, copy) NSString *defaultActiveApplication;
32
+ @property (nonatomic) 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 FBApplication *)application;
60
+ + (instancetype)initWithApplication:(nullable XCUIApplication *)application;
61
61
 
62
62
  /**
63
63
  Creates and saves new session for application with default alert handling behaviour
@@ -66,7 +66,8 @@ 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 FBApplication *)application defaultAlertAction:(NSString *)defaultAlertAction;
69
+ + (instancetype)initWithApplication:(nullable XCUIApplication *)application
70
+ defaultAlertAction:(NSString *)defaultAlertAction;
70
71
 
71
72
  /**
72
73
  Kills application associated with that session and removes session
@@ -82,12 +83,11 @@ NS_ASSUME_NONNULL_BEGIN
82
83
  @param arguments The optional array of application command line arguments. The arguments are going to be applied if the application was not running before.
83
84
  @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.
84
85
  @return The application instance
85
- @throws FBApplicationMethodNotSupportedException if the method is not supported with the current XCTest SDK
86
86
  */
87
- - (FBApplication *)launchApplicationWithBundleId:(NSString *)bundleIdentifier
88
- shouldWaitForQuiescence:(nullable NSNumber *)shouldWaitForQuiescence
89
- arguments:(nullable NSArray<NSString *> *)arguments
90
- environment:(nullable NSDictionary <NSString *, NSString *> *)environment;
87
+ - (XCUIApplication *)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,9 +95,8 @@ 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
99
98
  */
100
- - (FBApplication *)activateApplicationWithBundleId:(NSString *)bundleIdentifier;
99
+ - (XCUIApplication *)activateApplicationWithBundleId:(NSString *)bundleIdentifier;
101
100
 
102
101
  /**
103
102
  Terminate an application with the given bundle id. The application should be previously