appium-webdriveragent 5.0.0 → 5.1.1
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 +19 -0
- package/WebDriverAgent.xcodeproj/project.pbxproj +0 -20
- package/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m +0 -12
- package/WebDriverAgentLib/Categories/XCUIElement+FBPickerWheel.m +1 -15
- package/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m +7 -37
- package/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h +0 -7
- package/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +0 -49
- package/WebDriverAgentLib/Commands/FBElementCommands.m +37 -19
- package/WebDriverAgentLib/FBApplication.h +10 -0
- package/WebDriverAgentLib/FBApplication.m +36 -0
- package/WebDriverAgentLib/Routing/FBExceptionHandler.m +2 -1
- package/WebDriverAgentLib/Routing/FBExceptions.h +3 -0
- package/WebDriverAgentLib/Routing/FBExceptions.m +1 -0
- package/WebDriverAgentLib/Utilities/FBAppiumActionsSynthesizer.m +23 -15
- package/WebDriverAgentLib/Utilities/FBBaseActionsSynthesizer.h +4 -13
- package/WebDriverAgentLib/Utilities/FBBaseActionsSynthesizer.m +36 -56
- package/WebDriverAgentLib/Utilities/FBMathUtils.h +0 -6
- package/WebDriverAgentLib/Utilities/FBMathUtils.m +0 -29
- package/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m +23 -29
- package/WebDriverAgentLib/Utilities/FBXCTestDaemonsProxy.h +0 -4
- package/WebDriverAgentLib/Utilities/FBXCTestDaemonsProxy.m +0 -12
- package/WebDriverAgentTests/IntegrationTests/FBAppiumTouchActionsIntegrationTests.m +0 -16
- package/WebDriverAgentTests/IntegrationTests/FBSessionIntegrationTests.m +29 -0
- package/WebDriverAgentTests/IntegrationTests/FBW3CTouchActionsIntegrationTests.m +0 -19
- package/WebDriverAgentTests/UnitTests/FBMathUtilsTests.m +0 -12
- package/package.json +1 -1
- package/WebDriverAgentLib/Categories/XCUICoordinate+FBFix.h +0 -18
- package/WebDriverAgentLib/Categories/XCUICoordinate+FBFix.m +0 -46
- package/WebDriverAgentTests/IntegrationTests/FBElementScreenshotTests.m +0 -52
- package/WebDriverAgentTests/UnitTests/XCUICoordinateFix.m +0 -63
|
@@ -80,7 +80,7 @@ static const double FB_LONG_TAP_DURATION_MS = 600.0;
|
|
|
80
80
|
|
|
81
81
|
- (nullable instancetype)initWithActionItem:(NSDictionary<NSString *, id> *)item
|
|
82
82
|
application:(XCUIApplication *)application
|
|
83
|
-
atPosition:(nullable
|
|
83
|
+
atPosition:(nullable XCUICoordinate *)atPosition
|
|
84
84
|
offset:(double)offset
|
|
85
85
|
error:(NSError **)error
|
|
86
86
|
{
|
|
@@ -90,14 +90,14 @@ static const double FB_LONG_TAP_DURATION_MS = 600.0;
|
|
|
90
90
|
self.application = application;
|
|
91
91
|
self.offset = offset;
|
|
92
92
|
id options = [item objectForKey:FB_OPTIONS_KEY];
|
|
93
|
-
if (atPosition) {
|
|
94
|
-
self.atPosition =
|
|
93
|
+
if (nil != atPosition) {
|
|
94
|
+
self.atPosition = (id) atPosition;
|
|
95
95
|
} else {
|
|
96
|
-
|
|
96
|
+
XCUICoordinate *result = [self coordinatesWithOptions:options error:error];
|
|
97
97
|
if (nil == result) {
|
|
98
98
|
return nil;
|
|
99
99
|
}
|
|
100
|
-
self.atPosition =
|
|
100
|
+
self.atPosition = result;
|
|
101
101
|
}
|
|
102
102
|
self.duration = [self durationWithOptions:options];
|
|
103
103
|
if (self.duration < 0) {
|
|
@@ -124,7 +124,8 @@ static const double FB_LONG_TAP_DURATION_MS = 600.0;
|
|
|
124
124
|
0.0;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
- (nullable
|
|
127
|
+
- (nullable XCUICoordinate *)coordinatesWithOptions:(nullable NSDictionary<NSString *, id> *)options
|
|
128
|
+
error:(NSError **)error
|
|
128
129
|
{
|
|
129
130
|
if (![options isKindOfClass:NSDictionary.class]) {
|
|
130
131
|
NSString *description = [NSString stringWithFormat:@"'%@' key is mandatory for '%@' action", FB_OPTIONS_KEY, self.class.actionName];
|
|
@@ -169,7 +170,7 @@ static const double FB_LONG_TAP_DURATION_MS = 600.0;
|
|
|
169
170
|
NSTimeInterval currentOffset = FBMillisToSeconds(self.offset);
|
|
170
171
|
NSMutableArray<XCPointerEventPath *> *result = [NSMutableArray array];
|
|
171
172
|
XCPointerEventPath *currentPath = [[XCPointerEventPath alloc]
|
|
172
|
-
initForTouchAtPoint:self.atPosition
|
|
173
|
+
initForTouchAtPoint:self.atPosition.screenPoint
|
|
173
174
|
offset:currentOffset];
|
|
174
175
|
[result addObject:currentPath];
|
|
175
176
|
currentOffset += FBMillisToSeconds(FB_TAP_DURATION_MS);
|
|
@@ -180,7 +181,8 @@ static const double FB_LONG_TAP_DURATION_MS = 600.0;
|
|
|
180
181
|
NSNumber *tapCount = [options objectForKey:FB_OPTION_COUNT] ?: @1;
|
|
181
182
|
for (NSInteger times = 1; times < tapCount.integerValue; ++times) {
|
|
182
183
|
currentOffset += FBMillisToSeconds(FB_INTERTAP_MIN_DURATION_MS);
|
|
183
|
-
XCPointerEventPath *nextPath = [[XCPointerEventPath alloc] initForTouchAtPoint:self.atPosition
|
|
184
|
+
XCPointerEventPath *nextPath = [[XCPointerEventPath alloc] initForTouchAtPoint:self.atPosition.screenPoint
|
|
185
|
+
offset:currentOffset];
|
|
184
186
|
[result addObject:nextPath];
|
|
185
187
|
currentOffset += FBMillisToSeconds(FB_TAP_DURATION_MS);
|
|
186
188
|
[nextPath liftUpAtOffset:currentOffset];
|
|
@@ -204,7 +206,7 @@ static const double FB_LONG_TAP_DURATION_MS = 600.0;
|
|
|
204
206
|
|
|
205
207
|
- (nullable instancetype)initWithActionItem:(NSDictionary<NSString *, id> *)item
|
|
206
208
|
application:(XCUIApplication *)application
|
|
207
|
-
atPosition:(nullable
|
|
209
|
+
atPosition:(nullable XCUICoordinate *)atPosition
|
|
208
210
|
offset:(double)offset
|
|
209
211
|
error:(NSError **)error
|
|
210
212
|
{
|
|
@@ -239,7 +241,7 @@ static const double FB_LONG_TAP_DURATION_MS = 600.0;
|
|
|
239
241
|
error:(NSError **)error
|
|
240
242
|
{
|
|
241
243
|
XCPointerEventPath *result = [[XCPointerEventPath alloc]
|
|
242
|
-
initForTouchAtPoint:self.atPosition
|
|
244
|
+
initForTouchAtPoint:self.atPosition.screenPoint
|
|
243
245
|
offset:FBMillisToSeconds(self.offset)];
|
|
244
246
|
if (nil != self.pressure && nil != result.pointerEvents.lastObject) {
|
|
245
247
|
XCPointerEvent *pointerEvent = (XCPointerEvent *)result.pointerEvents.lastObject;
|
|
@@ -272,7 +274,7 @@ static const double FB_LONG_TAP_DURATION_MS = 600.0;
|
|
|
272
274
|
currentItemIndex:(NSUInteger)currentItemIndex
|
|
273
275
|
error:(NSError **)error
|
|
274
276
|
{
|
|
275
|
-
return @[[[XCPointerEventPath alloc] initForTouchAtPoint:self.atPosition
|
|
277
|
+
return @[[[XCPointerEventPath alloc] initForTouchAtPoint:self.atPosition.screenPoint
|
|
276
278
|
offset:FBMillisToSeconds(self.offset)]];
|
|
277
279
|
}
|
|
278
280
|
|
|
@@ -312,7 +314,8 @@ static const double FB_LONG_TAP_DURATION_MS = 600.0;
|
|
|
312
314
|
}
|
|
313
315
|
}
|
|
314
316
|
NSTimeInterval currentOffset = FBMillisToSeconds(self.offset + self.duration);
|
|
315
|
-
XCPointerEventPath *result = [[XCPointerEventPath alloc] initForTouchAtPoint:self.atPosition
|
|
317
|
+
XCPointerEventPath *result = [[XCPointerEventPath alloc] initForTouchAtPoint:self.atPosition.screenPoint
|
|
318
|
+
offset:currentOffset];
|
|
316
319
|
if (currentItemIndex == allItems.count - 1) {
|
|
317
320
|
[result liftUpAtOffset:currentOffset];
|
|
318
321
|
}
|
|
@@ -353,7 +356,8 @@ static const double FB_LONG_TAP_DURATION_MS = 600.0;
|
|
|
353
356
|
return nil;
|
|
354
357
|
}
|
|
355
358
|
|
|
356
|
-
[eventPath moveToPoint:self.atPosition
|
|
359
|
+
[eventPath moveToPoint:self.atPosition.screenPoint
|
|
360
|
+
atOffset:FBMillisToSeconds(self.offset)];
|
|
357
361
|
return @[];
|
|
358
362
|
}
|
|
359
363
|
|
|
@@ -509,7 +513,11 @@ static const double FB_LONG_TAP_DURATION_MS = 600.0;
|
|
|
509
513
|
return nil;
|
|
510
514
|
}
|
|
511
515
|
FBAppiumGestureItem *lastItem = [chain.items lastObject];
|
|
512
|
-
gestureItem = [[gestureItemClass alloc] initWithActionItem:actionItem
|
|
516
|
+
gestureItem = [[gestureItemClass alloc] initWithActionItem:actionItem
|
|
517
|
+
application:self.application
|
|
518
|
+
atPosition:lastItem.atPosition
|
|
519
|
+
offset:chain.durationOffset
|
|
520
|
+
error:error];
|
|
513
521
|
}
|
|
514
522
|
if (nil == gestureItem) {
|
|
515
523
|
return nil;
|
|
@@ -527,7 +535,7 @@ static const double FB_LONG_TAP_DURATION_MS = 600.0;
|
|
|
527
535
|
BOOL isMultiTouch = [self.actions.firstObject isKindOfClass:NSArray.class];
|
|
528
536
|
eventRecord = [[XCSynthesizedEventRecord alloc]
|
|
529
537
|
initWithName:(isMultiTouch ? @"Multi-Finger Touch Action" : @"Single-Finger Touch Action")
|
|
530
|
-
interfaceOrientation:
|
|
538
|
+
interfaceOrientation:self.application.interfaceOrientation];
|
|
531
539
|
for (NSArray<NSDictionary<NSString *, id> *> *action in (isMultiTouch ? self.actions : @[self.actions])) {
|
|
532
540
|
NSArray<NSDictionary<NSString *, id> *> *preprocessedAction = [self preprocessAction:action];
|
|
533
541
|
NSArray<XCPointerEventPath *> *eventPaths = [self eventPathsWithAction:preprocessedAction error:error];
|
|
@@ -51,19 +51,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
51
51
|
@interface FBBaseGestureItem : FBBaseActionItem
|
|
52
52
|
|
|
53
53
|
/*! Absolute position on the screen where the gesure should be performed */
|
|
54
|
-
@property (nonatomic)
|
|
54
|
+
@property (nonatomic) XCUICoordinate *atPosition;
|
|
55
55
|
/*! Gesture duration in milliseconds */
|
|
56
56
|
@property (nonatomic) double duration;
|
|
57
57
|
|
|
58
|
-
/**
|
|
59
|
-
Returns fixed hit point coordinates for the case when XCTest fails to transform element snaapshot properly on screen rotation.
|
|
60
|
-
|
|
61
|
-
@param hitPoint The initial hitpoint coordinates
|
|
62
|
-
@param snapshot Element's snapshot instance
|
|
63
|
-
@return The fixed hit point coordinates, if there is a need to fix them, or the unchanged hit point value
|
|
64
|
-
*/
|
|
65
|
-
- (CGPoint)fixedHitPointWith:(CGPoint)hitPoint forSnapshot:(id<FBXCElementSnapshot>)snapshot;
|
|
66
|
-
|
|
67
58
|
/**
|
|
68
59
|
Calculate absolute gesture position on the screen based on provided element and positionOffset values.
|
|
69
60
|
|
|
@@ -72,9 +63,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
72
63
|
@param error If there is an error, upon return contains an NSError object that describes the problem
|
|
73
64
|
@return Adbsolute gesture position on the screen or nil if the calculation fails (for example, the element is invisible)
|
|
74
65
|
*/
|
|
75
|
-
- (nullable
|
|
76
|
-
|
|
77
|
-
|
|
66
|
+
- (nullable XCUICoordinate *)hitpointWithElement:(nullable XCUIElement *)element
|
|
67
|
+
positionOffset:(nullable NSValue *)positionOffset
|
|
68
|
+
error:(NSError **)error;
|
|
78
69
|
|
|
79
70
|
@end
|
|
80
71
|
|
|
@@ -31,7 +31,10 @@
|
|
|
31
31
|
return nil;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
- (NSArray<XCPointerEventPath *> *)addToEventPath:(XCPointerEventPath *)eventPath
|
|
34
|
+
- (NSArray<XCPointerEventPath *> *)addToEventPath:(XCPointerEventPath *)eventPath
|
|
35
|
+
allItems:(NSArray *)allItems
|
|
36
|
+
currentItemIndex:(NSUInteger)currentItemIndex
|
|
37
|
+
error:(NSError **)error
|
|
35
38
|
{
|
|
36
39
|
@throw [[FBErrorBuilder.builder withDescription:@"Override this method in subclasses"] build];
|
|
37
40
|
return nil;
|
|
@@ -41,66 +44,40 @@
|
|
|
41
44
|
|
|
42
45
|
@implementation FBBaseGestureItem
|
|
43
46
|
|
|
44
|
-
- (
|
|
47
|
+
- (nullable XCUICoordinate *)hitpointWithElement:(nullable XCUIElement *)element
|
|
48
|
+
positionOffset:(nullable NSValue *)positionOffset
|
|
49
|
+
error:(NSError **)error
|
|
45
50
|
{
|
|
46
|
-
UIInterfaceOrientation interfaceOrientation = self.application.interfaceOrientation;
|
|
47
|
-
if (interfaceOrientation == UIInterfaceOrientationPortrait) {
|
|
48
|
-
// There is no need to recalculate anything for portrait orientation
|
|
49
|
-
return hitPoint;
|
|
50
|
-
}
|
|
51
|
-
// For Xcode11+ it is always necessary to adjust the tap point coordinates
|
|
52
|
-
return FBInvertPointForApplication(hitPoint, self.application.frame.size, interfaceOrientation);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
- (nullable NSValue *)hitpointWithElement:(nullable XCUIElement *)element positionOffset:(nullable NSValue *)positionOffset error:(NSError **)error
|
|
56
|
-
{
|
|
57
|
-
CGPoint hitPoint;
|
|
58
51
|
if (nil == element) {
|
|
52
|
+
CGVector offset = CGVectorMake(positionOffset.CGPointValue.x, positionOffset.CGPointValue.y);
|
|
59
53
|
// Only absolute offset is defined
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
// The offset relative to the element is defined
|
|
69
|
-
|
|
70
|
-
id<FBXCElementSnapshot> snapshot = element.fb_isResolvedFromCache.boolValue
|
|
71
|
-
? element.lastSnapshot
|
|
72
|
-
: element.fb_takeSnapshot;
|
|
73
|
-
if (nil == positionOffset) {
|
|
74
|
-
NSValue *hitPointValue = [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_hitPoint;
|
|
75
|
-
if (nil != hitPointValue) {
|
|
76
|
-
// short circuit element hitpoint
|
|
77
|
-
return hitPointValue;
|
|
78
|
-
}
|
|
79
|
-
[FBLogger logFmt:@"Will use the frame of '%@' for hit point calculation instead", element.debugDescription];
|
|
80
|
-
}
|
|
81
|
-
CGRect visibleFrame = snapshot.visibleFrame;
|
|
82
|
-
CGRect frame = CGRectIsEmpty(visibleFrame) ? element.frame : visibleFrame;
|
|
83
|
-
if (CGRectIsEmpty(frame)) {
|
|
84
|
-
[FBLogger log:self.application.fb_descriptionRepresentation];
|
|
85
|
-
NSString *description = [NSString stringWithFormat:@"The element '%@' is not visible on the screen and thus is not interactable", element.description];
|
|
86
|
-
if (error) {
|
|
87
|
-
*error = [[FBErrorBuilder.builder withDescription:description] build];
|
|
88
|
-
}
|
|
89
|
-
return nil;
|
|
54
|
+
return [[self.application coordinateWithNormalizedOffset:CGVectorMake(0, 0)] coordinateWithOffset:offset];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// The offset relative to the element is defined
|
|
58
|
+
if (nil == positionOffset) {
|
|
59
|
+
if (element.hittable) {
|
|
60
|
+
// short circuit element hitpoint
|
|
61
|
+
return element.hitPointCoordinate;
|
|
90
62
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// TODO: Shall we throw an exception if hitPoint is out of the element frame?
|
|
63
|
+
[FBLogger logFmt:@"Will use the frame of '%@' for hit point calculation instead", element.debugDescription];
|
|
64
|
+
}
|
|
65
|
+
if (CGRectIsEmpty(element.frame)) {
|
|
66
|
+
[FBLogger log:self.application.fb_descriptionRepresentation];
|
|
67
|
+
NSString *description = [NSString stringWithFormat:@"The element '%@' is not visible on the screen and thus is not interactable",
|
|
68
|
+
element.description];
|
|
69
|
+
if (error) {
|
|
70
|
+
*error = [[FBErrorBuilder.builder withDescription:description] build];
|
|
100
71
|
}
|
|
101
|
-
|
|
72
|
+
return nil;
|
|
73
|
+
}
|
|
74
|
+
if (nil == positionOffset) {
|
|
75
|
+
return [element coordinateWithNormalizedOffset:CGVectorMake(0.5, 0.5)];
|
|
102
76
|
}
|
|
103
|
-
|
|
77
|
+
|
|
78
|
+
CGVector offset = CGVectorMake(positionOffset.CGPointValue.x, positionOffset.CGPointValue.y);
|
|
79
|
+
// TODO: Shall we throw an exception if hitPoint is out of the element frame?
|
|
80
|
+
return [[element coordinateWithNormalizedOffset:CGVectorMake(0, 0)] coordinateWithOffset:offset];
|
|
104
81
|
}
|
|
105
82
|
|
|
106
83
|
@end
|
|
@@ -161,7 +138,10 @@
|
|
|
161
138
|
|
|
162
139
|
@implementation FBBaseActionsSynthesizer
|
|
163
140
|
|
|
164
|
-
- (instancetype)initWithActions:(NSArray *)actions
|
|
141
|
+
- (instancetype)initWithActions:(NSArray *)actions
|
|
142
|
+
forApplication:(XCUIApplication *)application
|
|
143
|
+
elementCache:(nullable FBElementCache *)elementCache
|
|
144
|
+
error:(NSError **)error
|
|
165
145
|
{
|
|
166
146
|
self = [super init];
|
|
167
147
|
if (self) {
|
|
@@ -32,12 +32,6 @@ BOOL FBSizeFuzzyEqualToSize(CGSize size1, CGSize size2, CGFloat threshold);
|
|
|
32
32
|
BOOL FBRectFuzzyEqualToRect(CGRect rect1, CGRect rect2, CGFloat threshold);
|
|
33
33
|
|
|
34
34
|
#if !TARGET_OS_TV
|
|
35
|
-
/*! Inverts point if necessary to match location on screen */
|
|
36
|
-
CGPoint FBInvertPointForApplication(CGPoint point, CGSize screenSize, UIInterfaceOrientation orientation);
|
|
37
|
-
|
|
38
|
-
/*! Inverts offset if necessary to match screen orientation */
|
|
39
|
-
CGPoint FBInvertOffsetForOrientation(CGPoint offset, UIInterfaceOrientation orientation);
|
|
40
|
-
|
|
41
35
|
/*! Inverts size if necessary to match current screen orientation */
|
|
42
36
|
CGSize FBAdjustDimensionsForApplication(CGSize actualSize, UIInterfaceOrientation orientation);
|
|
43
37
|
#endif
|
|
@@ -46,35 +46,6 @@ BOOL FBRectFuzzyEqualToRect(CGRect rect1, CGRect rect2, CGFloat threshold)
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
#if !TARGET_OS_TV
|
|
49
|
-
CGPoint FBInvertPointForApplication(CGPoint point, CGSize screenSize, UIInterfaceOrientation orientation)
|
|
50
|
-
{
|
|
51
|
-
switch (orientation) {
|
|
52
|
-
case UIInterfaceOrientationUnknown:
|
|
53
|
-
case UIInterfaceOrientationPortrait:
|
|
54
|
-
return point;
|
|
55
|
-
case UIInterfaceOrientationPortraitUpsideDown:
|
|
56
|
-
return CGPointMake(screenSize.width - point.x, screenSize.height - point.y);
|
|
57
|
-
case UIInterfaceOrientationLandscapeLeft:
|
|
58
|
-
return CGPointMake(point.y, MAX(screenSize.width, screenSize.height) - point.x);
|
|
59
|
-
case UIInterfaceOrientationLandscapeRight:
|
|
60
|
-
return CGPointMake(MIN(screenSize.width, screenSize.height) - point.y, point.x);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
CGPoint FBInvertOffsetForOrientation(CGPoint offset, UIInterfaceOrientation orientation)
|
|
65
|
-
{
|
|
66
|
-
switch (orientation) {
|
|
67
|
-
case UIInterfaceOrientationUnknown:
|
|
68
|
-
case UIInterfaceOrientationPortrait:
|
|
69
|
-
return offset;
|
|
70
|
-
case UIInterfaceOrientationPortraitUpsideDown:
|
|
71
|
-
return CGPointMake(-offset.x, -offset.y);
|
|
72
|
-
case UIInterfaceOrientationLandscapeLeft:
|
|
73
|
-
return CGPointMake(offset.y, -offset.x);
|
|
74
|
-
case UIInterfaceOrientationLandscapeRight:
|
|
75
|
-
return CGPointMake(-offset.y, offset.x);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
49
|
|
|
79
50
|
CGSize FBAdjustDimensionsForApplication(CGSize actualSize, UIInterfaceOrientation orientation)
|
|
80
51
|
{
|
|
@@ -133,16 +133,16 @@ static NSString *const FB_KEY_ACTIONS = @"actions";
|
|
|
133
133
|
return nil;
|
|
134
134
|
}
|
|
135
135
|
self.duration = durationObj.doubleValue;
|
|
136
|
-
|
|
136
|
+
XCUICoordinate *position = [self positionWithError:error];
|
|
137
137
|
if (nil == position) {
|
|
138
138
|
return nil;
|
|
139
139
|
}
|
|
140
|
-
self.atPosition =
|
|
140
|
+
self.atPosition = position;
|
|
141
141
|
}
|
|
142
142
|
return self;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
- (nullable
|
|
145
|
+
- (nullable XCUICoordinate *)positionWithError:(NSError **)error
|
|
146
146
|
{
|
|
147
147
|
if (nil == self.previousItem) {
|
|
148
148
|
NSString *errorDescription = [NSString stringWithFormat:@"The '%@' action item must be preceded by %@ item", self.actionItem, FB_ACTION_ITEM_TYPE_POINTER_MOVE];
|
|
@@ -151,39 +151,32 @@ static NSString *const FB_KEY_ACTIONS = @"actions";
|
|
|
151
151
|
}
|
|
152
152
|
return nil;
|
|
153
153
|
}
|
|
154
|
-
return
|
|
154
|
+
return self.previousItem.atPosition;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
- (nullable
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
- (nullable XCUICoordinate *)hitpointWithElement:(nullable XCUIElement *)element
|
|
158
|
+
positionOffset:(nullable NSValue *)positionOffset
|
|
159
|
+
error:(NSError **)error
|
|
160
160
|
{
|
|
161
161
|
if (nil == element || nil == positionOffset) {
|
|
162
162
|
return [super hitpointWithElement:element positionOffset:positionOffset error:error];
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
// An offset relative to the element is defined
|
|
166
|
-
|
|
167
|
-
? element.lastSnapshot
|
|
168
|
-
: element.fb_takeSnapshot;
|
|
169
|
-
CGRect frame = snapshot.frame;
|
|
170
|
-
if (CGRectIsEmpty(frame)) {
|
|
166
|
+
if (CGRectIsEmpty(element.frame)) {
|
|
171
167
|
[FBLogger log:self.application.fb_descriptionRepresentation];
|
|
172
|
-
NSString *description = [NSString stringWithFormat:@"The element '%@' is not visible on the screen and thus is not interactable",
|
|
168
|
+
NSString *description = [NSString stringWithFormat:@"The element '%@' is not visible on the screen and thus is not interactable",
|
|
169
|
+
element.description];
|
|
173
170
|
if (error) {
|
|
174
171
|
*error = [[FBErrorBuilder.builder withDescription:description] build];
|
|
175
172
|
}
|
|
176
173
|
return nil;
|
|
177
174
|
}
|
|
178
|
-
|
|
179
|
-
frame = CGRectIsEmpty(visibleFrame) ? frame : visibleFrame;
|
|
175
|
+
|
|
180
176
|
// W3C standard requires that relative element coordinates start at the center of the element's rectangle
|
|
181
|
-
|
|
182
|
-
CGPoint offsetValue = [positionOffset CGPointValue];
|
|
183
|
-
hitPoint = CGPointMake(hitPoint.x + offsetValue.x, hitPoint.y + offsetValue.y);
|
|
177
|
+
CGVector offset = CGVectorMake(positionOffset.CGPointValue.x, positionOffset.CGPointValue.y);
|
|
184
178
|
// TODO: Shall we throw an exception if hitPoint is out of the element frame?
|
|
185
|
-
|
|
186
|
-
return [NSValue valueWithCGPoint:hitPoint];
|
|
179
|
+
return [[element coordinateWithNormalizedOffset:CGVectorMake(0.5, 0.5)] coordinateWithOffset:offset];
|
|
187
180
|
}
|
|
188
181
|
|
|
189
182
|
@end
|
|
@@ -220,7 +213,7 @@ static NSString *const FB_KEY_ACTIONS = @"actions";
|
|
|
220
213
|
}
|
|
221
214
|
}
|
|
222
215
|
if (nil == self.pressure) {
|
|
223
|
-
XCPointerEventPath *result = [[XCPointerEventPath alloc] initForTouchAtPoint:self.atPosition
|
|
216
|
+
XCPointerEventPath *result = [[XCPointerEventPath alloc] initForTouchAtPoint:self.atPosition.screenPoint
|
|
224
217
|
offset:FBMillisToSeconds(self.offset)];
|
|
225
218
|
return @[result];
|
|
226
219
|
}
|
|
@@ -247,7 +240,7 @@ static NSString *const FB_KEY_ACTIONS = @"actions";
|
|
|
247
240
|
|
|
248
241
|
@implementation FBPointerMoveItem
|
|
249
242
|
|
|
250
|
-
- (nullable
|
|
243
|
+
- (nullable XCUICoordinate *)positionWithError:(NSError **)error
|
|
251
244
|
{
|
|
252
245
|
static NSArray<NSString *> *supportedOriginTypes;
|
|
253
246
|
static dispatch_once_t onceToken;
|
|
@@ -295,10 +288,9 @@ static NSString *const FB_KEY_ACTIONS = @"actions";
|
|
|
295
288
|
}
|
|
296
289
|
return nil;
|
|
297
290
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
return [NSValue valueWithCGPoint:CGPointMake(recentPosition.x + offsetRelativeToRecentPosition.x, recentPosition.y + offsetRelativeToRecentPosition.y)];
|
|
291
|
+
XCUICoordinate *recentPosition = self.previousItem.atPosition;
|
|
292
|
+
CGVector offsetRelativeToRecentPosition = (nil == x && nil == y) ? CGVectorMake(0, 0) : CGVectorMake(x.floatValue, y.floatValue);
|
|
293
|
+
return [recentPosition coordinateWithOffset:offsetRelativeToRecentPosition];
|
|
302
294
|
}
|
|
303
295
|
|
|
304
296
|
+ (NSString *)actionName
|
|
@@ -312,9 +304,11 @@ static NSString *const FB_KEY_ACTIONS = @"actions";
|
|
|
312
304
|
error:(NSError **)error
|
|
313
305
|
{
|
|
314
306
|
if (nil == eventPath) {
|
|
315
|
-
return @[[[XCPointerEventPath alloc] initForTouchAtPoint:self.atPosition
|
|
307
|
+
return @[[[XCPointerEventPath alloc] initForTouchAtPoint:self.atPosition.screenPoint
|
|
308
|
+
offset:FBMillisToSeconds(self.offset + self.duration)]];
|
|
316
309
|
}
|
|
317
|
-
[eventPath moveToPoint:self.atPosition
|
|
310
|
+
[eventPath moveToPoint:self.atPosition.screenPoint
|
|
311
|
+
atOffset:FBMillisToSeconds(self.offset + self.duration)];
|
|
318
312
|
return @[];
|
|
319
313
|
}
|
|
320
314
|
|
|
@@ -888,7 +882,7 @@ static NSString *const FB_KEY_ACTIONS = @"actions";
|
|
|
888
882
|
{
|
|
889
883
|
XCSynthesizedEventRecord *eventRecord = [[XCSynthesizedEventRecord alloc]
|
|
890
884
|
initWithName:@"W3C Touch Action"
|
|
891
|
-
interfaceOrientation:
|
|
885
|
+
interfaceOrientation:self.application.interfaceOrientation];
|
|
892
886
|
NSMutableDictionary<NSString *, NSDictionary<NSString *, id> *> *actionsMapping = [NSMutableDictionary new];
|
|
893
887
|
NSMutableArray<NSString *> *actionIds = [NSMutableArray new];
|
|
894
888
|
for (NSDictionary<NSString *, id> *action in self.actions) {
|
|
@@ -23,10 +23,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
23
23
|
|
|
24
24
|
+ (id<XCTestManager_ManagerInterface>)testRunnerProxy;
|
|
25
25
|
|
|
26
|
-
#if !TARGET_OS_TV
|
|
27
|
-
+ (UIInterfaceOrientation)orientationWithApplication:(XCUIApplication *)application;
|
|
28
|
-
#endif
|
|
29
|
-
|
|
30
26
|
+ (BOOL)synthesizeEventWithRecord:(XCSynthesizedEventRecord *)record
|
|
31
27
|
error:(NSError *__autoreleasing*)error;
|
|
32
28
|
|
|
@@ -30,7 +30,6 @@ static dispatch_once_t onceTestRunnerDaemonClass;
|
|
|
30
30
|
|
|
31
31
|
+ (void)load
|
|
32
32
|
{
|
|
33
|
-
// XCTRunnerDaemonSession class is only available since Xcode 8.3
|
|
34
33
|
dispatch_once(&onceTestRunnerDaemonClass, ^{
|
|
35
34
|
FBXCTRunnerDaemonSessionClass = objc_lookUpClass("XCTRunnerDaemonSession");
|
|
36
35
|
});
|
|
@@ -60,17 +59,6 @@ static dispatch_once_t onceTestRunnerDaemonClass;
|
|
|
60
59
|
return ((XCTRunnerDaemonSession *)[FBXCTRunnerDaemonSessionClass sharedSession]).daemonProxy;
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
#if !TARGET_OS_TV
|
|
64
|
-
+ (UIInterfaceOrientation)orientationWithApplication:(XCUIApplication *)application
|
|
65
|
-
{
|
|
66
|
-
if (nil == FBXCTRunnerDaemonSessionClass ||
|
|
67
|
-
[[FBXCTRunnerDaemonSessionClass sharedSession] useLegacyEventCoordinateTransformationPath]) {
|
|
68
|
-
return application.interfaceOrientation;
|
|
69
|
-
}
|
|
70
|
-
return UIInterfaceOrientationPortrait;
|
|
71
|
-
}
|
|
72
|
-
#endif
|
|
73
|
-
|
|
74
62
|
+ (BOOL)synthesizeEventWithRecord:(XCSynthesizedEventRecord *)record error:(NSError *__autoreleasing*)error
|
|
75
63
|
{
|
|
76
64
|
__block BOOL didSucceed = NO;
|
|
@@ -194,14 +194,6 @@
|
|
|
194
194
|
|
|
195
195
|
- (void)testDoubleTap
|
|
196
196
|
{
|
|
197
|
-
if ([UIDevice.currentDevice userInterfaceIdiom] == UIUserInterfaceIdiomPad &&
|
|
198
|
-
SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"15.0")) {
|
|
199
|
-
// "tap the element" does not work on iPadOS simulator after change the rotation in iOS 15
|
|
200
|
-
// while selecting the element worked. (I confirmed with getting an element screenshot that
|
|
201
|
-
// the FBShowAlertButtonName was actually selected after changing the orientation.)
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
197
|
NSArray<NSDictionary<NSString *, id> *> *gesture =
|
|
206
198
|
@[@{
|
|
207
199
|
@"action": @"tap",
|
|
@@ -214,16 +206,8 @@
|
|
|
214
206
|
[self verifyGesture:gesture orientation:UIDeviceOrientationLandscapeLeft];
|
|
215
207
|
}
|
|
216
208
|
|
|
217
|
-
// TODO: UIDeviceOrientationLandscapeRight is not so good in iOS 16? (Especially simulators)
|
|
218
209
|
- (void)testPress
|
|
219
210
|
{
|
|
220
|
-
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"15.0")) {
|
|
221
|
-
// Does not work on iOS 15.0.
|
|
222
|
-
// The same action tap the FBShowAlertButtonName after rotating the screen
|
|
223
|
-
// worked with W3C actions. `.click` action did not work.
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
211
|
NSArray<NSDictionary<NSString *, id> *> *gesture =
|
|
228
212
|
@[@{
|
|
229
213
|
@"action": @"press",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
#import "FBIntegrationTestCase.h"
|
|
13
13
|
#import "FBApplication.h"
|
|
14
|
+
#import "FBExceptions.h"
|
|
14
15
|
#import "FBMacros.h"
|
|
15
16
|
#import "FBSession.h"
|
|
16
17
|
#import "FBXCodeCompatibility.h"
|
|
@@ -100,6 +101,34 @@ static NSString *const SETTINGS_BUNDLE_ID = @"com.apple.Preferences";
|
|
|
100
101
|
FBAssertWaitTillBecomesTrue([self.session.activeApplication.bundleID isEqualToString:testedApp.bundleID]);
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
- (void)testAppWithInvalidBundleIDCannotBeStarted
|
|
105
|
+
{
|
|
106
|
+
FBApplication *testedApp = [[FBApplication alloc] initWithBundleIdentifier:@"yolo"];
|
|
107
|
+
@try {
|
|
108
|
+
[testedApp launch];
|
|
109
|
+
XCTFail(@"An exception is expected to be thrown");
|
|
110
|
+
} @catch (NSException *exception) {
|
|
111
|
+
XCTAssertEqualObjects(FBApplicationMissingException, exception.name);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
- (void)testAppWithInvalidBundleIDCannotBeActivated
|
|
116
|
+
{
|
|
117
|
+
FBApplication *testedApp = [[FBApplication alloc] initWithBundleIdentifier:@"yolo"];
|
|
118
|
+
@try {
|
|
119
|
+
[testedApp activate];
|
|
120
|
+
XCTFail(@"An exception is expected to be thrown");
|
|
121
|
+
} @catch (NSException *exception) {
|
|
122
|
+
XCTAssertEqualObjects(FBApplicationMissingException, exception.name);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
- (void)testAppWithInvalidBundleIDCannotBeTerminated
|
|
127
|
+
{
|
|
128
|
+
FBApplication *testedApp = [[FBApplication alloc] initWithBundleIdentifier:@"yolo"];
|
|
129
|
+
[testedApp terminate];
|
|
130
|
+
}
|
|
131
|
+
|
|
103
132
|
- (void)testLaunchUnattachedApp
|
|
104
133
|
{
|
|
105
134
|
[FBUnattachedAppLauncher launchAppWithBundleId:SETTINGS_BUNDLE_ID];
|
|
@@ -294,18 +294,8 @@
|
|
|
294
294
|
[self verifyGesture:gesture orientation:UIDeviceOrientationPortrait];
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
-
// TODO: UIDeviceOrientationLandscapeLeft did not work in iOS 16 simumlator.
|
|
298
|
-
// UIDeviceOrientationPortrait was ok.
|
|
299
297
|
- (void)testDoubleTap
|
|
300
298
|
{
|
|
301
|
-
if ([UIDevice.currentDevice userInterfaceIdiom] == UIUserInterfaceIdiomPad &&
|
|
302
|
-
SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"15.0")) {
|
|
303
|
-
// "tap the element" does not work on iPadOS simulator after change the rotation in iOS 15
|
|
304
|
-
// while selecting the element worked. (I confirmed with getting an element screenshot that
|
|
305
|
-
// the FBShowAlertButtonName was actually selected after changing the orientation.)
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
299
|
NSArray<NSDictionary<NSString *, id> *> *gesture =
|
|
310
300
|
@[@{
|
|
311
301
|
@"type": @"pointer",
|
|
@@ -326,17 +316,8 @@
|
|
|
326
316
|
[self verifyGesture:gesture orientation:UIDeviceOrientationLandscapeLeft];
|
|
327
317
|
}
|
|
328
318
|
|
|
329
|
-
// TODO: UIDeviceOrientationLandscapeRight did not work in iOS 16 simumlator.
|
|
330
|
-
// UIDeviceOrientationPortrait was ok.
|
|
331
319
|
- (void)testLongPressWithCombinedPause
|
|
332
320
|
{
|
|
333
|
-
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"15.0")) {
|
|
334
|
-
// Xcode 13 x iOS 14 also does not work while Xcode 12.5 x iOS 14 worked.
|
|
335
|
-
// Skip this test for iOS 15 since iOS 15 works with Xcode 13 at least.
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
|
|
340
321
|
NSArray<NSDictionary<NSString *, id> *> *gesture =
|
|
341
322
|
@[@{
|
|
342
323
|
@"type": @"pointer",
|
|
@@ -98,18 +98,6 @@
|
|
|
98
98
|
XCTAssertFalse(FBRectFuzzyEqualToRect(referenceRect, CGRectMake(-1, -1, 1, 1), 1));
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
- (void)testPointInvertion
|
|
103
|
-
{
|
|
104
|
-
const CGPoint testPoint = CGPointMake(1, 2);
|
|
105
|
-
const CGSize screenSize = CGSizeMake(10, 15);
|
|
106
|
-
const CGFloat t = FBDefaultFrameFuzzyThreshold;
|
|
107
|
-
XCTAssertTrue(FBPointFuzzyEqualToPoint(CGPointMake(1, 2), FBInvertPointForApplication(testPoint, screenSize, UIInterfaceOrientationPortrait), t));
|
|
108
|
-
XCTAssertTrue(FBPointFuzzyEqualToPoint(CGPointMake(9, 13), FBInvertPointForApplication(testPoint, screenSize, UIInterfaceOrientationPortraitUpsideDown), t));
|
|
109
|
-
XCTAssertTrue(FBPointFuzzyEqualToPoint(CGPointMake(2, 14), FBInvertPointForApplication(testPoint, screenSize, UIInterfaceOrientationLandscapeLeft), t));
|
|
110
|
-
XCTAssertTrue(FBPointFuzzyEqualToPoint(CGPointMake(8, 1), FBInvertPointForApplication(testPoint, screenSize, UIInterfaceOrientationLandscapeRight), t));
|
|
111
|
-
}
|
|
112
|
-
|
|
113
101
|
- (void)testSizeInversion
|
|
114
102
|
{
|
|
115
103
|
const CGSize screenSizePortrait = CGSizeMake(10, 15);
|
package/package.json
CHANGED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
-
* All rights reserved.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the BSD-style license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree. An additional grant
|
|
7
|
-
* of patent rights can be found in the PATENTS file in the same directory.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
#import <XCTest/XCTest.h>
|
|
11
|
-
|
|
12
|
-
#if !TARGET_OS_TV
|
|
13
|
-
@interface XCUICoordinate (FBFix)
|
|
14
|
-
|
|
15
|
-
- (CGPoint)fb_screenPoint;
|
|
16
|
-
|
|
17
|
-
@end
|
|
18
|
-
#endif
|