appium-webdriveragent 4.4.3 → 4.6.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 (35) hide show
  1. package/PrivateHeaders/XCTest/XCUICoordinate.h +2 -0
  2. package/PrivateHeaders/XCTest/XCUIDevice.h +2 -0
  3. package/PrivateHeaders/XCTest/XCUIElement.h +2 -0
  4. package/README.md +1 -0
  5. package/Scripts/build-webdriveragent.js +1 -1
  6. package/Scripts/fetch-prebuilt-wda.js +1 -1
  7. package/WebDriverAgent.xcodeproj/project.xcworkspace/xcuserdata/elf.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  8. package/WebDriverAgent.xcodeproj/xcuserdata/elf.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +91 -0
  9. package/WebDriverAgent.xcodeproj/xcuserdata/elf.xcuserdatad/xcschemes/xcschememanagement.plist +59 -0
  10. package/WebDriverAgentLib/Categories/XCUIElement+FBForceTouch.h +13 -13
  11. package/WebDriverAgentLib/Categories/XCUIElement+FBForceTouch.m +34 -45
  12. package/WebDriverAgentLib/Commands/FBElementCommands.m +47 -40
  13. package/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m +22 -5
  14. package/WebDriverAgentRunner-Runner.app.zip +0 -0
  15. package/WebDriverAgentTests/IntegrationTests/FBAppiumTouchActionsIntegrationTests.m +1 -29
  16. package/WebDriverAgentTests/IntegrationTests/FBElementScreenshotTests.m +1 -16
  17. package/WebDriverAgentTests/IntegrationTests/FBForceTouchTests.m +16 -5
  18. package/WebDriverAgentTests/IntegrationTests/FBPasteboardTests.m +8 -2
  19. package/WebDriverAgentTests/IntegrationTests/FBW3CTouchActionsIntegrationTests.m +35 -4
  20. package/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m +17 -6
  21. package/build/index.js +1 -1
  22. package/build/lib/check-dependencies.js +2 -2
  23. package/build/lib/constants.js +1 -1
  24. package/build/lib/logger.js +2 -2
  25. package/build/lib/no-session-proxy.js +3 -3
  26. package/build/lib/utils.js +2 -2
  27. package/build/lib/webdriveragent.js +4 -4
  28. package/build/lib/xcodebuild.js +2 -2
  29. package/lib/check-dependencies.js +1 -1
  30. package/lib/logger.js +1 -1
  31. package/lib/no-session-proxy.js +1 -1
  32. package/lib/utils.js +1 -1
  33. package/lib/webdriveragent.js +2 -2
  34. package/lib/xcodebuild.js +1 -1
  35. package/package.json +5 -3
@@ -31,6 +31,8 @@
31
31
  - (void)pressForDuration:(double)arg1;
32
32
  - (void)doubleTap;
33
33
  - (void)tap;
34
+ - (void)pressWithPressure:(double)arg1 duration:(double)arg2;
35
+ - (void)forcePress;
34
36
 
35
37
  @end
36
38
  #endif
@@ -24,5 +24,7 @@
24
24
  - (void)pressLockButton;
25
25
  - (void)holdHomeButtonForDuration:(double)arg1;
26
26
  - (void)_silentPressButton:(long long)arg1;
27
+ // Since Xcode 11
28
+ - (_Bool)supportsPressureInteraction;
27
29
 
28
30
  @end
@@ -43,6 +43,8 @@
43
43
  - (id)_highestNonWindowAncestorOfElement:(id)arg1 notSharedWithElement:(id)arg2;
44
44
  - (id)_pointsInFrame:(CGRect)arg1 numberOfTouches:(unsigned long long)arg2;
45
45
  - (CGPoint)_hitPointByAttemptingToScrollToVisibleSnapshot:(id)arg1;
46
+ // Since 11.3
47
+ - (void)pressWithPressure:(double)arg1 duration:(double)arg2;
46
48
  - (void)forcePress;
47
49
  - (void)tapWithNumberOfTaps:(unsigned long long)arg1 numberOfTouches:(unsigned long long)arg2;
48
50
  - (void)twoFingerTap;
package/README.md CHANGED
@@ -51,3 +51,4 @@ projects has been integrated directly in the WebDriverAgent source tree.
51
51
  You can find the source files and their licenses in the `WebDriverAgentLib/Vendor` directory.
52
52
 
53
53
  Have fun!
54
+
@@ -1,7 +1,7 @@
1
1
  const path = require('path');
2
2
  const os = require('os');
3
3
  const { asyncify } = require('asyncbox');
4
- const { logger, fs, mkdirp, zip } = require('@appium/support');
4
+ const { logger, fs, mkdirp, zip } = require('appium/support');
5
5
  const { exec } = require('teen_process');
6
6
  const xcode = require('appium-xcode');
7
7
 
@@ -1,7 +1,7 @@
1
1
  const path = require('path');
2
2
  const axios = require('axios');
3
3
  const { asyncify } = require('asyncbox');
4
- const { logger, fs, mkdirp, net } = require('@appium/support');
4
+ const { logger, fs, mkdirp, net } = require('appium/support');
5
5
  const _ = require('lodash');
6
6
  const B = require('bluebird');
7
7
 
@@ -0,0 +1,91 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Bucket
3
+ uuid = "2F0174F2-ED3F-4D11-9A17-7C590053D796"
4
+ type = "1"
5
+ version = "2.0">
6
+ <Breakpoints>
7
+ <BreakpointProxy
8
+ BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
9
+ <BreakpointContent
10
+ uuid = "471ECA8C-2C53-4C59-88DB-1C1CB3D61601"
11
+ shouldBeEnabled = "No"
12
+ ignoreCount = "0"
13
+ continueAfterRunningActions = "No"
14
+ breakpointStackSelectionBehavior = "1"
15
+ scope = "1"
16
+ stopOnStyle = "0">
17
+ </BreakpointContent>
18
+ </BreakpointProxy>
19
+ <BreakpointProxy
20
+ BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
21
+ <BreakpointContent
22
+ uuid = "C2E06865-6A52-4686-9771-279AF13ABF8A"
23
+ shouldBeEnabled = "Yes"
24
+ ignoreCount = "0"
25
+ continueAfterRunningActions = "No"
26
+ filePath = "WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m"
27
+ timestampString = "0"
28
+ startingColumnNumber = "9223372036854775807"
29
+ endingColumnNumber = "9223372036854775807"
30
+ startingLineNumber = "264"
31
+ endingLineNumber = "264">
32
+ </BreakpointContent>
33
+ </BreakpointProxy>
34
+ <BreakpointProxy
35
+ BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
36
+ <BreakpointContent
37
+ uuid = "54216FE6-E240-47F1-88D3-D450CF0AF44E"
38
+ shouldBeEnabled = "Yes"
39
+ ignoreCount = "0"
40
+ continueAfterRunningActions = "No"
41
+ filePath = "WebDriverAgentLib/Categories/XCUIElement+FBResolve.m"
42
+ startingColumnNumber = "9223372036854775807"
43
+ endingColumnNumber = "9223372036854775807"
44
+ startingLineNumber = "37"
45
+ endingLineNumber = "37"
46
+ landmarkName = "-fb_stableInstance"
47
+ landmarkType = "7">
48
+ <Locations>
49
+ <Location
50
+ uuid = "54216FE6-E240-47F1-88D3-D450CF0AF44E - b09f4ce1ce926e6"
51
+ shouldBeEnabled = "Yes"
52
+ ignoreCount = "0"
53
+ continueAfterRunningActions = "No"
54
+ symbolName = "-[XCUIElement(FBResolve) fb_stableInstance]"
55
+ moduleName = "WebDriverAgentLib"
56
+ usesParentBreakpointCondition = "Yes"
57
+ urlString = "file:///Users/elf/code/WebDriverAgent/WebDriverAgentLib/Categories/XCUIElement+FBResolve.m"
58
+ startingColumnNumber = "9223372036854775807"
59
+ endingColumnNumber = "9223372036854775807"
60
+ startingLineNumber = "37"
61
+ endingLineNumber = "37"
62
+ offsetFromSymbolStart = "19">
63
+ </Location>
64
+ <Location
65
+ shouldBeEnabled = "Yes"
66
+ ignoreCount = "0"
67
+ continueAfterRunningActions = "No"
68
+ usesParentBreakpointCondition = "Yes"
69
+ offsetFromSymbolStart = "0">
70
+ </Location>
71
+ </Locations>
72
+ </BreakpointContent>
73
+ </BreakpointProxy>
74
+ <BreakpointProxy
75
+ BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
76
+ <BreakpointContent
77
+ uuid = "D3009B57-42BC-4905-99BC-70232544FAFB"
78
+ shouldBeEnabled = "Yes"
79
+ ignoreCount = "0"
80
+ continueAfterRunningActions = "No"
81
+ filePath = "WebDriverAgentTests/IntegrationTests/FBAlertTests.m"
82
+ startingColumnNumber = "5"
83
+ endingColumnNumber = "64"
84
+ startingLineNumber = "32"
85
+ endingLineNumber = "32"
86
+ landmarkName = "-setUp"
87
+ landmarkType = "7">
88
+ </BreakpointContent>
89
+ </BreakpointProxy>
90
+ </Breakpoints>
91
+ </Bucket>
@@ -0,0 +1,59 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>IntegrationApp.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>0</integer>
11
+ </dict>
12
+ <key>IntegrationTests_1.xcscheme_^#shared#^_</key>
13
+ <dict>
14
+ <key>orderHint</key>
15
+ <integer>1</integer>
16
+ </dict>
17
+ <key>IntegrationTests_2.xcscheme_^#shared#^_</key>
18
+ <dict>
19
+ <key>orderHint</key>
20
+ <integer>2</integer>
21
+ </dict>
22
+ <key>IntegrationTests_3.xcscheme_^#shared#^_</key>
23
+ <dict>
24
+ <key>orderHint</key>
25
+ <integer>3</integer>
26
+ </dict>
27
+ <key>WebDriverAgentLib copy.xcscheme_^#shared#^_</key>
28
+ <dict>
29
+ <key>orderHint</key>
30
+ <integer>9</integer>
31
+ </dict>
32
+ <key>WebDriverAgentLib.xcscheme_^#shared#^_</key>
33
+ <dict>
34
+ <key>orderHint</key>
35
+ <integer>4</integer>
36
+ </dict>
37
+ <key>WebDriverAgentLib_tvOS.xcscheme_^#shared#^_</key>
38
+ <dict>
39
+ <key>orderHint</key>
40
+ <integer>5</integer>
41
+ </dict>
42
+ <key>WebDriverAgentRunner-nodebug.xcscheme_^#shared#^_</key>
43
+ <dict>
44
+ <key>orderHint</key>
45
+ <integer>7</integer>
46
+ </dict>
47
+ <key>WebDriverAgentRunner.xcscheme_^#shared#^_</key>
48
+ <dict>
49
+ <key>orderHint</key>
50
+ <integer>6</integer>
51
+ </dict>
52
+ <key>WebDriverAgentRunner_tvOS.xcscheme_^#shared#^_</key>
53
+ <dict>
54
+ <key>orderHint</key>
55
+ <integer>8</integer>
56
+ </dict>
57
+ </dict>
58
+ </dict>
59
+ </plist>
@@ -11,29 +11,29 @@
11
11
 
12
12
  NS_ASSUME_NONNULL_BEGIN
13
13
 
14
- @interface XCUIElement (FBForceTouch)
14
+ #if !TARGET_OS_TV
15
15
 
16
- /**
17
- Waits for element to become stable (not move) and performs sync force touch on element
18
-
19
- @param error If there is an error, upon return contains an NSError object that describes the problem.
20
- @param pressure The pressure of the force touch – valid values are [0, touch.maximumPossibleForce]
21
- @param duration The duration of the gesture in float seconds
22
- @return YES if the operation succeeds, otherwise NO.
23
- */
24
- - (BOOL)fb_forceTouchWithPressure:(double)pressure duration:(double)duration error:(NSError **)error;
16
+ @interface XCUIElement (FBForceTouch)
25
17
 
26
18
  /**
27
- Waits for element to become stable (not move) and performs sync force touch on element
19
+ Performs force touch on element
28
20
 
29
- @param relativeCoordinate hit point coordinate relative to the current element position
21
+ @param relativeCoordinate hit point coordinate relative to the current element position.
22
+ nil value means to use the default element hit point
30
23
  @param pressure The pressure of the force touch – valid values are [0, touch.maximumPossibleForce]
24
+ nil value would use the default pressure value
31
25
  @param duration The duration of the gesture in float seconds
26
+ nil value would use the default duration value
32
27
  @param error If there is an error, upon return contains an NSError object that describes the problem.
33
28
  @return YES if the operation succeeds, otherwise NO.
34
29
  */
35
- - (BOOL)fb_forceTouchCoordinate:(CGPoint)relativeCoordinate pressure:(double)pressure duration:(double)duration error:(NSError **)error;
30
+ - (BOOL)fb_forceTouchCoordinate:(nullable NSValue *)relativeCoordinate
31
+ pressure:(nullable NSNumber *)pressure
32
+ duration:(nullable NSNumber *)duration
33
+ error:(NSError **)error;
36
34
 
37
35
  @end
38
36
 
37
+ #endif
38
+
39
39
  NS_ASSUME_NONNULL_END
@@ -9,56 +9,45 @@
9
9
 
10
10
  #import "XCUIElement+FBForceTouch.h"
11
11
 
12
- #import "XCUIApplication+FBTouchAction.h"
12
+ #if !TARGET_OS_TV
13
+
14
+ #import "FBErrorBuilder.h"
15
+ #import "XCUICoordinate.h"
16
+ #import "XCUIDevice.h"
13
17
 
14
18
  @implementation XCUIElement (FBForceTouch)
15
19
 
16
- - (BOOL)fb_forceTouchWithPressure:(double)pressure duration:(double)duration error:(NSError **)error
20
+ - (BOOL)fb_forceTouchCoordinate:(NSValue *)relativeCoordinate
21
+ pressure:(NSNumber *)pressure
22
+ duration:(NSNumber *)duration
23
+ error:(NSError **)error
17
24
  {
18
- NSArray<NSDictionary<NSString *, id> *> *gesture =
19
- @[@{
20
- @"action": @"press",
21
- @"options": @{
22
- @"element": self,
23
- @"pressure": @(pressure)
24
- }
25
- },
26
- @{
27
- @"action": @"wait",
28
- @"options": @{
29
- @"ms": @(duration * 1000)
30
- }
31
- },
32
- @{
33
- @"action": @"release"
34
- }
35
- ];
36
- return [self.application fb_performAppiumTouchActions:gesture elementCache:nil error:error];
37
- }
25
+ if (![XCUIDevice sharedDevice].supportsPressureInteraction) {
26
+ return [[[FBErrorBuilder builder]
27
+ withDescriptionFormat:@"Force press is not supported on this device"]
28
+ buildError:error];
29
+ }
38
30
 
39
- - (BOOL)fb_forceTouchCoordinate:(CGPoint)relativeCoordinate pressure:(double)pressure duration:(double)duration error:(NSError **)error
40
- {
41
- NSArray<NSDictionary<NSString *, id> *> *gesture =
42
- @[@{
43
- @"action": @"press",
44
- @"options": @{
45
- @"element": self,
46
- @"x": @(relativeCoordinate.x),
47
- @"y": @(relativeCoordinate.y),
48
- @"pressure": @(pressure)
49
- }
50
- },
51
- @{
52
- @"action": @"wait",
53
- @"options": @{
54
- @"ms": @(duration * 1000)
55
- }
56
- },
57
- @{
58
- @"action": @"release"
59
- }
60
- ];
61
- return [self.application fb_performAppiumTouchActions:gesture elementCache:nil error:error];
31
+ if (nil == relativeCoordinate) {
32
+ if (nil == pressure || nil == duration) {
33
+ [self forcePress];
34
+ } else {
35
+ [self pressWithPressure:[pressure doubleValue] duration:[duration doubleValue]];
36
+ }
37
+ } else {
38
+ CGSize size = self.frame.size;
39
+ CGVector offset = CGVectorMake(size.width > 0 ? relativeCoordinate.CGPointValue.x / size.width : 0,
40
+ size.height > 0 ? relativeCoordinate.CGPointValue.y / size.height : 0);
41
+ XCUICoordinate *hitPoint = [self coordinateWithNormalizedOffset:offset];
42
+ if (nil == pressure || nil == duration) {
43
+ [hitPoint forcePress];
44
+ } else {
45
+ [hitPoint pressWithPressure:[pressure doubleValue] duration:[duration doubleValue]];
46
+ }
47
+ }
48
+ return YES;
62
49
  }
63
50
 
64
51
  @end
52
+
53
+ #endif
@@ -85,14 +85,15 @@
85
85
  [[FBRoute POST:@"/wda/element/:uuid/touchAndHold"] respondWithTarget:self action:@selector(handleTouchAndHold:)],
86
86
  [[FBRoute POST:@"/wda/element/:uuid/scroll"] respondWithTarget:self action:@selector(handleScroll:)],
87
87
  [[FBRoute POST:@"/wda/element/:uuid/dragfromtoforduration"] respondWithTarget:self action:@selector(handleDrag:)],
88
+ [[FBRoute POST:@"/wda/element/:uuid/forceTouch"] respondWithTarget:self action:@selector(handleForceTouch:)],
88
89
  [[FBRoute POST:@"/wda/dragfromtoforduration"] respondWithTarget:self action:@selector(handleDragCoordinate:)],
89
90
  [[FBRoute POST:@"/wda/tap/:uuid"] respondWithTarget:self action:@selector(handleTap:)],
90
91
  [[FBRoute POST:@"/wda/touchAndHold"] respondWithTarget:self action:@selector(handleTouchAndHoldCoordinate:)],
91
92
  [[FBRoute POST:@"/wda/doubleTap"] respondWithTarget:self action:@selector(handleDoubleTapCoordinate:)],
92
93
  [[FBRoute POST:@"/wda/pickerwheel/:uuid/select"] respondWithTarget:self action:@selector(handleWheelSelect:)],
94
+ [[FBRoute POST:@"/wda/forceTouch"] respondWithTarget:self action:@selector(handleForceTouch:)],
93
95
  #endif
94
96
  [[FBRoute POST:@"/wda/keys"] respondWithTarget:self action:@selector(handleKeys:)],
95
- [[FBRoute POST:@"/wda/element/:uuid/forceTouch"] respondWithTarget:self action:@selector(handleForceTouch:)],
96
97
  ];
97
98
  }
98
99
 
@@ -291,7 +292,8 @@
291
292
  + (id<FBResponsePayload>)handleDoubleTapCoordinate:(FBRouteRequest *)request
292
293
  {
293
294
  CGPoint doubleTapPoint = CGPointMake((CGFloat)[request.arguments[@"x"] doubleValue], (CGFloat)[request.arguments[@"y"] doubleValue]);
294
- XCUICoordinate *doubleTapCoordinate = [self.class gestureCoordinateWithCoordinate:doubleTapPoint application:request.session.activeApplication shouldApplyOrientationWorkaround:isSDKVersionLessThan(@"11.0")];
295
+ XCUICoordinate *doubleTapCoordinate = [self.class gestureCoordinateWithCoordinate:doubleTapPoint
296
+ application:request.session.activeApplication];
295
297
  [doubleTapCoordinate doubleTap];
296
298
  return FBResponseWithOK();
297
299
  }
@@ -328,7 +330,8 @@
328
330
  + (id<FBResponsePayload>)handleTouchAndHoldCoordinate:(FBRouteRequest *)request
329
331
  {
330
332
  CGPoint touchPoint = CGPointMake((CGFloat)[request.arguments[@"x"] doubleValue], (CGFloat)[request.arguments[@"y"] doubleValue]);
331
- XCUICoordinate *pressCoordinate = [self.class gestureCoordinateWithCoordinate:touchPoint application:request.session.activeApplication shouldApplyOrientationWorkaround:isSDKVersionLessThan(@"11.0")];
333
+ XCUICoordinate *pressCoordinate = [self.class gestureCoordinateWithCoordinate:touchPoint
334
+ application:request.session.activeApplication];
332
335
  [pressCoordinate pressForDuration:[request.arguments[@"duration"] doubleValue]];
333
336
  return FBResponseWithOK();
334
337
  }
@@ -386,8 +389,10 @@
386
389
  CGPoint startPoint = CGPointMake((CGFloat)[request.arguments[@"fromX"] doubleValue], (CGFloat)[request.arguments[@"fromY"] doubleValue]);
387
390
  CGPoint endPoint = CGPointMake((CGFloat)[request.arguments[@"toX"] doubleValue], (CGFloat)[request.arguments[@"toY"] doubleValue]);
388
391
  NSTimeInterval duration = [request.arguments[@"duration"] doubleValue];
389
- XCUICoordinate *endCoordinate = [self.class gestureCoordinateWithCoordinate:endPoint application:session.activeApplication shouldApplyOrientationWorkaround:isSDKVersionLessThan(@"11.0")];
390
- XCUICoordinate *startCoordinate = [self.class gestureCoordinateWithCoordinate:startPoint application:session.activeApplication shouldApplyOrientationWorkaround:isSDKVersionLessThan(@"11.0")];
392
+ XCUICoordinate *endCoordinate = [self.class gestureCoordinateWithCoordinate:endPoint
393
+ application:session.activeApplication];
394
+ XCUICoordinate *startCoordinate = [self.class gestureCoordinateWithCoordinate:startPoint
395
+ application:session.activeApplication];
391
396
  [startCoordinate pressForDuration:duration thenDragToCoordinate:endCoordinate];
392
397
  return FBResponseWithOK();
393
398
  }
@@ -401,9 +406,10 @@
401
406
  CGPoint startPoint = CGPointMake((CGFloat)(frame.origin.x + [request.arguments[@"fromX"] doubleValue]), (CGFloat)(frame.origin.y + [request.arguments[@"fromY"] doubleValue]));
402
407
  CGPoint endPoint = CGPointMake((CGFloat)(frame.origin.x + [request.arguments[@"toX"] doubleValue]), (CGFloat)(frame.origin.y + [request.arguments[@"toY"] doubleValue]));
403
408
  NSTimeInterval duration = [request.arguments[@"duration"] doubleValue];
404
- BOOL shouldApplyOrientationWorkaround = isSDKVersionGreaterThanOrEqualTo(@"10.0") && isSDKVersionLessThan(@"11.0");
405
- XCUICoordinate *endCoordinate = [self.class gestureCoordinateWithCoordinate:endPoint application:session.activeApplication shouldApplyOrientationWorkaround:shouldApplyOrientationWorkaround];
406
- XCUICoordinate *startCoordinate = [self.class gestureCoordinateWithCoordinate:startPoint application:session.activeApplication shouldApplyOrientationWorkaround:shouldApplyOrientationWorkaround];
409
+ XCUICoordinate *endCoordinate = [self.class gestureCoordinateWithCoordinate:endPoint
410
+ application:session.activeApplication];
411
+ XCUICoordinate *startCoordinate = [self.class gestureCoordinateWithCoordinate:startPoint
412
+ application:session.activeApplication];
407
413
  [startCoordinate pressForDuration:duration thenDragToCoordinate:endCoordinate];
408
414
  return FBResponseWithOK();
409
415
  }
@@ -439,8 +445,7 @@
439
445
  }
440
446
  } else {
441
447
  XCUICoordinate *tapCoordinate = [self.class gestureCoordinateWithCoordinate:tapPoint
442
- application:request.session.activeApplication
443
- shouldApplyOrientationWorkaround:isSDKVersionLessThan(@"11.0")];
448
+ application:request.session.activeApplication];
444
449
  [tapCoordinate tap];
445
450
  }
446
451
  return FBResponseWithOK();
@@ -465,27 +470,34 @@
465
470
  [element rotate:rotation withVelocity:velocity];
466
471
  return FBResponseWithOK();
467
472
  }
468
- #endif
469
473
 
470
474
  + (id<FBResponsePayload>)handleForceTouch:(FBRouteRequest *)request
471
475
  {
472
- FBElementCache *elementCache = request.session.elementCache;
473
- XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
474
- double pressure = [request.arguments[@"pressure"] doubleValue];
475
- double duration = [request.arguments[@"duration"] doubleValue];
476
- NSError *error;
477
- if (nil != request.arguments[@"x"] && nil != request.arguments[@"y"]) {
478
- CGPoint forceTouchPoint = CGPointMake((CGFloat)[request.arguments[@"x"] doubleValue], (CGFloat)[request.arguments[@"y"] doubleValue]);
479
- if (![element fb_forceTouchCoordinate:forceTouchPoint pressure:pressure duration:duration error:&error]) {
480
- return FBResponseWithStatus([FBCommandStatus invalidElementStateErrorWithMessage:error.description traceback:nil]);
481
- }
476
+ XCUIElement *element = nil;
477
+ if (nil == request.parameters[@"uuid"]) {
478
+ element = [FBApplication fb_activeApplication];
482
479
  } else {
483
- if (![element fb_forceTouchWithPressure:pressure duration:duration error:&error]) {
484
- return FBResponseWithStatus([FBCommandStatus invalidElementStateErrorWithMessage:error.description traceback:nil]);
485
- }
480
+ FBElementCache *elementCache = request.session.elementCache;
481
+ element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
486
482
  }
487
- return FBResponseWithOK();
483
+ NSNumber *pressure = request.arguments[@"pressure"];
484
+ NSNumber *duration = request.arguments[@"duration"];
485
+ NSNumber *x = request.arguments[@"x"];
486
+ NSNumber *y = request.arguments[@"y"];
487
+ NSValue *hitPoint = (nil == x || nil == y)
488
+ ? nil
489
+ : [NSValue valueWithCGPoint:CGPointMake((CGFloat)[x doubleValue], (CGFloat)[y doubleValue])];
490
+ NSError *error;
491
+ BOOL didSucceed = [element fb_forceTouchCoordinate:hitPoint
492
+ pressure:pressure
493
+ duration:duration
494
+ error:&error];
495
+ return didSucceed
496
+ ? FBResponseWithOK()
497
+ : FBResponseWithStatus([FBCommandStatus invalidElementStateErrorWithMessage:error.description
498
+ traceback:nil]);
488
499
  }
500
+ #endif
489
501
 
490
502
  + (id<FBResponsePayload>)handleKeys:(FBRouteRequest *)request
491
503
  {
@@ -574,7 +586,8 @@ static const CGFloat DEFAULT_OFFSET = (CGFloat)0.2;
574
586
  return FBResponseWithStatus([FBCommandStatus elementNotVisibleErrorWithMessage:@"Can't scroll to element that does not exist" traceback:[NSString stringWithFormat:@"%@", NSThread.callStackSymbols]]);
575
587
  }
576
588
  if (![element fb_scrollToVisibleWithError:&error]) {
577
- return FBResponseWithStatus([FBCommandStatus invalidElementStateErrorWithMessage:error.description traceback:[NSString stringWithFormat:@"%@", NSThread.callStackSymbols]]);
589
+ return FBResponseWithStatus([FBCommandStatus invalidElementStateErrorWithMessage:error.description
590
+ traceback:[NSString stringWithFormat:@"%@", NSThread.callStackSymbols]]);
578
591
  }
579
592
  return FBResponseWithOK();
580
593
  }
@@ -584,21 +597,12 @@ static const CGFloat DEFAULT_OFFSET = (CGFloat)0.2;
584
597
 
585
598
  @param coordinate absolute screen coordinates
586
599
  @param application the instance of current application under test
587
- @shouldApplyOrientationWorkaround whether to apply orientation workaround. This is to
588
- handle XCTest bug where it does not translate screen coordinates for elements if
589
- screen orientation is different from the default one (which is portrait).
590
- Different iOS version have different behavior, for example iOS 9.3 returns correct
591
- coordinates for elements in landscape, but iOS 10.0+ returns inverted coordinates as if
592
- the current screen orientation would be portrait.
593
600
  @return translated gesture coordinates ready to be passed to XCUICoordinate methods
594
601
  */
595
- + (XCUICoordinate *)gestureCoordinateWithCoordinate:(CGPoint)coordinate application:(XCUIApplication *)application shouldApplyOrientationWorkaround:(BOOL)shouldApplyOrientationWorkaround
602
+ + (XCUICoordinate *)gestureCoordinateWithCoordinate:(CGPoint)coordinate
603
+ application:(XCUIApplication *)application
596
604
  {
597
605
  CGPoint point = coordinate;
598
- if (shouldApplyOrientationWorkaround) {
599
- point = FBInvertPointForApplication(coordinate, application.frame.size, application.interfaceOrientation);
600
- }
601
-
602
606
  /**
603
607
  If SDK >= 11, the tap coordinate based on application is not correct when
604
608
  the application orientation is landscape and
@@ -632,10 +636,13 @@ static const CGFloat DEFAULT_OFFSET = (CGFloat)0.2;
632
636
  @param element the element in the current application under test
633
637
  @return translated gesture coordinates ready to be passed to XCUICoordinate methods
634
638
  */
635
- + (XCUICoordinate *)gestureCoordinateWithCoordinate:(CGPoint)coordinate element:(XCUIElement *)element
639
+ + (XCUICoordinate *)gestureCoordinateWithCoordinate:(CGPoint)coordinate
640
+ element:(XCUIElement *)element
636
641
  {
637
- XCUICoordinate *appCoordinate = [[XCUICoordinate alloc] initWithElement:element normalizedOffset:CGVectorMake(0, 0)];
638
- return [[XCUICoordinate alloc] initWithCoordinate:appCoordinate pointsOffset:CGVectorMake(coordinate.x, coordinate.y)];
642
+ XCUICoordinate *appCoordinate = [[XCUICoordinate alloc] initWithElement:element
643
+ normalizedOffset:CGVectorMake(0, 0)];
644
+ return [[XCUICoordinate alloc] initWithCoordinate:appCoordinate
645
+ pointsOffset:CGVectorMake(coordinate.x, coordinate.y)];
639
646
  }
640
647
  #endif
641
648
 
@@ -21,6 +21,7 @@
21
21
  #import "FBXCTestDaemonsProxy.h"
22
22
  #import "XCElementSnapshot+FBHelpers.h"
23
23
  #import "XCUIApplication+FBHelpers.h"
24
+ #import "XCUIDevice.h"
24
25
  #import "XCUIElement+FBCaching.h"
25
26
  #import "XCUIElement+FBIsVisible.h"
26
27
  #import "XCUIElement+FBUtilities.h"
@@ -218,12 +219,28 @@ static NSString *const FB_KEY_ACTIONS = @"actions";
218
219
  return @[];
219
220
  }
220
221
  }
221
- XCPointerEventPath *result = [[XCPointerEventPath alloc] initForTouchAtPoint:self.atPosition offset:FBMillisToSeconds(self.offset)];
222
- if (nil != self.pressure && nil != result.pointerEvents.lastObject) {
223
- XCPointerEvent *pointerEvent = (XCPointerEvent *)result.pointerEvents.lastObject;
224
- pointerEvent.pressure = self.pressure.doubleValue;
222
+ if (nil == self.pressure) {
223
+ XCPointerEventPath *result = [[XCPointerEventPath alloc] initForTouchAtPoint:self.atPosition
224
+ offset:FBMillisToSeconds(self.offset)];
225
+ return @[result];
225
226
  }
226
- return @[result];
227
+
228
+ if (nil == eventPath) {
229
+ NSString *description = [NSString stringWithFormat:@"'%@' action with pressure must be preceeded with at least one '%@' action without this option", self.class.actionName, self.class.actionName];
230
+ if (error) {
231
+ *error = [[FBErrorBuilder.builder withDescription:description] build];
232
+ }
233
+ return nil;
234
+ }
235
+ if (![XCUIDevice sharedDevice].supportsPressureInteraction) {
236
+ if (error) {
237
+ *error = [[FBErrorBuilder.builder withDescription:@"This device does not support force press interactions"] build];
238
+ }
239
+ return nil;
240
+ }
241
+ [eventPath pressDownWithPressure:self.pressure.doubleValue
242
+ atOffset:FBMillisToSeconds(self.offset)];
243
+ return @[];
227
244
  }
228
245
 
229
246
  @end
Binary file
@@ -214,6 +214,7 @@
214
214
  [self verifyGesture:gesture orientation:UIDeviceOrientationLandscapeLeft];
215
215
  }
216
216
 
217
+ // TODO: UIDeviceOrientationLandscapeRight is not so good in iOS 16? (Especially simulators)
217
218
  - (void)testPress
218
219
  {
219
220
  if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"15.0")) {
@@ -284,35 +285,6 @@
284
285
  [self verifyGesture:gesture orientation:orientation];
285
286
  }
286
287
 
287
- - (void)testForcePress
288
- {
289
- if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"15.0")) {
290
- // Does not work on iOS 15.
291
- return;
292
- }
293
- NSArray<NSDictionary<NSString *, id> *> *gesture =
294
- @[@{
295
- @"action": @"press",
296
- @"options": @{
297
- @"ELEMENT": self.testedApplication.buttons[FBShowAlertForceTouchButtonName],
298
- @"x": @1,
299
- @"y": @1,
300
- @"pressure": @1
301
- }
302
- },
303
- @{
304
- @"action": @"wait",
305
- @"options": @{
306
- @"ms": @300
307
- }
308
- },
309
- @{
310
- @"action": @"release"
311
- }
312
- ];
313
- [self verifyGesture:gesture orientation:UIDeviceOrientationPortrait];
314
- }
315
-
316
288
  @end
317
289
 
318
290
 
@@ -9,6 +9,7 @@
9
9
 
10
10
  #import <XCTest/XCTest.h>
11
11
 
12
+ #import "FBMacros.h"
12
13
  #import "FBIntegrationTestCase.h"
13
14
  #import "XCUIDevice+FBRotation.h"
14
15
  #import "XCUIElement+FBUtilities.h"
@@ -41,27 +42,11 @@
41
42
  XCUIElement *button = self.testedApplication.buttons[FBShowAlertButtonName];
42
43
  NSError *error = nil;
43
44
  NSData *screenshotData = [button fb_screenshotWithError:&error];
44
- if (nil == screenshotData && [error.description containsString:@"available since Xcode9"]) {
45
- return;
46
- }
47
45
  XCTAssertNotNil(screenshotData);
48
46
  XCTAssertNil(error);
49
47
  UIImage *image = [UIImage imageWithData:screenshotData];
50
48
  XCTAssertNotNil(image);
51
49
  XCTAssertTrue(image.size.width > image.size.height);
52
-
53
- XCUIScreen *mainScreen = XCUIScreen.mainScreen;
54
- // Note about iPadOS 15.0 environment.
55
- // The 'button.screenshot.image' (by XCTest) had a white image while 'image' had
56
- // expected FBShowAlertButtonName area image by WebDriverAgent.
57
- // It seems the native XCTest element screenshot has an issue on iPadOS.
58
- UIImage *buttonScreenshot = button.screenshot.image;
59
- XCTAssertEqualWithAccuracy(buttonScreenshot.size.height * mainScreen.scale,
60
- image.size.height,
61
- FLT_EPSILON);
62
- XCTAssertEqualWithAccuracy(buttonScreenshot.size.width * mainScreen.scale,
63
- image.size.width,
64
- FLT_EPSILON);
65
50
  }
66
51
 
67
52
  @end