appium-webdriveragent 8.12.2 → 9.0.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 (56) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/PrivateHeaders/XCTest/XCTestManager_ManagerInterface-Protocol.h +1 -0
  3. package/WebDriverAgent.xcodeproj/project.pbxproj +12 -0
  4. package/WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.h +4 -9
  5. package/WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.m +13 -25
  6. package/WebDriverAgentLib/Categories/XCUIApplication+FBAlert.m +2 -2
  7. package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +4 -20
  8. package/WebDriverAgentLib/Categories/XCUIElement+FBAccessibility.m +15 -4
  9. package/WebDriverAgentLib/Categories/XCUIElement+FBCaching.h +0 -3
  10. package/WebDriverAgentLib/Categories/XCUIElement+FBCaching.m +1 -22
  11. package/WebDriverAgentLib/Categories/XCUIElement+FBFind.m +1 -1
  12. package/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m +28 -173
  13. package/WebDriverAgentLib/Categories/XCUIElement+FBPickerWheel.m +1 -3
  14. package/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m +33 -30
  15. package/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m +4 -8
  16. package/WebDriverAgentLib/Categories/XCUIElement+FBUID.m +2 -2
  17. package/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h +3 -36
  18. package/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +10 -68
  19. package/WebDriverAgentLib/Categories/XCUIElement+FBVisibleFrame.h +36 -0
  20. package/WebDriverAgentLib/Categories/XCUIElement+FBVisibleFrame.m +53 -0
  21. package/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m +7 -20
  22. package/WebDriverAgentLib/Commands/FBCustomCommands.m +2 -1
  23. package/WebDriverAgentLib/Commands/FBElementCommands.m +25 -47
  24. package/WebDriverAgentLib/Commands/FBFindElementCommands.m +10 -9
  25. package/WebDriverAgentLib/Commands/FBSessionCommands.m +0 -8
  26. package/WebDriverAgentLib/FBAlert.m +6 -5
  27. package/WebDriverAgentLib/Info.plist +2 -2
  28. package/WebDriverAgentLib/Routing/FBElementCache.h +4 -10
  29. package/WebDriverAgentLib/Routing/FBElementCache.m +4 -33
  30. package/WebDriverAgentLib/Routing/FBResponsePayload.m +1 -7
  31. package/WebDriverAgentLib/Utilities/FBConfiguration.h +0 -8
  32. package/WebDriverAgentLib/Utilities/FBConfiguration.m +0 -12
  33. package/WebDriverAgentLib/Utilities/FBSettings.h +0 -3
  34. package/WebDriverAgentLib/Utilities/FBSettings.m +0 -2
  35. package/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m +1 -3
  36. package/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m +1 -1
  37. package/WebDriverAgentLib/Utilities/FBXCAXClientProxy.h +4 -3
  38. package/WebDriverAgentLib/Utilities/FBXCAXClientProxy.m +7 -11
  39. package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h +3 -1
  40. package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m +2 -2
  41. package/WebDriverAgentLib/Utilities/FBXPath.m +1 -4
  42. package/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.h +3 -0
  43. package/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.m +1 -0
  44. package/WebDriverAgentTests/IntegrationTests/FBElementAttributeTests.m +2 -1
  45. package/WebDriverAgentTests/IntegrationTests/FBElementSwipingTests.m +1 -1
  46. package/WebDriverAgentTests/IntegrationTests/FBW3CTouchActionsIntegrationTests.m +1 -1
  47. package/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m +2 -2
  48. package/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHelperTests.m +21 -10
  49. package/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHitPointTests.m +1 -1
  50. package/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m +5 -3
  51. package/WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.m +10 -0
  52. package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h +1 -2
  53. package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m +1 -1
  54. package/WebDriverAgentTests/UnitTests/FBElementCacheTests.m +0 -2
  55. package/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.h +0 -1
  56. package/package.json +1 -1
@@ -20,9 +20,11 @@
20
20
  #import "XCUIApplication.h"
21
21
  #import "XCUICoordinate.h"
22
22
  #import "XCUIElement+FBIsVisible.h"
23
+ #import "XCUIElement+FBVisibleFrame.h"
23
24
  #import "XCUIElement.h"
24
25
  #import "XCUIElement+FBUtilities.h"
25
26
  #import "XCUIElement+FBWebDriverAttributes.h"
27
+ #import "XCTestPrivateSymbols.h"
26
28
 
27
29
  const CGFloat FBFuzzyPointThreshold = 20.f; //Smallest determined value that is not interpreted as touch
28
30
  const CGFloat FBScrollToVisibleNormalizedDistance = .5f;
@@ -47,45 +49,35 @@ const CGFloat FBScrollTouchProportion = 0.75f;
47
49
 
48
50
  - (BOOL)fb_nativeScrollToVisibleWithError:(NSError **)error
49
51
  {
50
- id<FBXCElementSnapshot> snapshot = self.fb_isResolvedFromCache.boolValue
51
- ? self.lastSnapshot
52
- : self.fb_takeSnapshot;
52
+ id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:YES];
53
53
  return nil != [self _hitPointByAttemptingToScrollToVisibleSnapshot:snapshot
54
54
  error:error];
55
55
  }
56
56
 
57
57
  - (void)fb_scrollUpByNormalizedDistance:(CGFloat)distance
58
58
  {
59
- id<FBXCElementSnapshot> snapshot = self.fb_isResolvedFromCache.boolValue
60
- ? self.lastSnapshot
61
- : self.fb_takeSnapshot;
59
+ id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:YES];
62
60
  [[FBXCElementSnapshotWrapper ensureWrapped:snapshot] fb_scrollUpByNormalizedDistance:distance
63
61
  inApplication:self.application];
64
62
  }
65
63
 
66
64
  - (void)fb_scrollDownByNormalizedDistance:(CGFloat)distance
67
65
  {
68
- id<FBXCElementSnapshot> snapshot = self.fb_isResolvedFromCache.boolValue
69
- ? self.lastSnapshot
70
- : self.fb_takeSnapshot;
66
+ id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:YES];
71
67
  [[FBXCElementSnapshotWrapper ensureWrapped:snapshot] fb_scrollDownByNormalizedDistance:distance
72
68
  inApplication:self.application];
73
69
  }
74
70
 
75
71
  - (void)fb_scrollLeftByNormalizedDistance:(CGFloat)distance
76
72
  {
77
- id<FBXCElementSnapshot> snapshot = self.fb_isResolvedFromCache.boolValue
78
- ? self.lastSnapshot
79
- : self.fb_takeSnapshot;
73
+ id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:YES];
80
74
  [[FBXCElementSnapshotWrapper ensureWrapped:snapshot] fb_scrollLeftByNormalizedDistance:distance
81
75
  inApplication:self.application];
82
76
  }
83
77
 
84
78
  - (void)fb_scrollRightByNormalizedDistance:(CGFloat)distance
85
79
  {
86
- id<FBXCElementSnapshot> snapshot = self.fb_isResolvedFromCache.boolValue
87
- ? self.lastSnapshot
88
- : self.fb_takeSnapshot;
80
+ id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:YES];
89
81
  [[FBXCElementSnapshotWrapper ensureWrapped:snapshot] fb_scrollRightByNormalizedDistance:distance
90
82
  inApplication:self.application];
91
83
  }
@@ -95,7 +87,8 @@ const CGFloat FBScrollTouchProportion = 0.75f;
95
87
  return [self fb_scrollToVisibleWithNormalizedScrollDistance:FBScrollToVisibleNormalizedDistance error:error];
96
88
  }
97
89
 
98
- - (BOOL)fb_scrollToVisibleWithNormalizedScrollDistance:(CGFloat)normalizedScrollDistance error:(NSError **)error
90
+ - (BOOL)fb_scrollToVisibleWithNormalizedScrollDistance:(CGFloat)normalizedScrollDistance
91
+ error:(NSError **)error
99
92
  {
100
93
  return [self fb_scrollToVisibleWithNormalizedScrollDistance:normalizedScrollDistance
101
94
  scrollDirection:FBXCUIElementScrollDirectionUnknown
@@ -106,7 +99,8 @@ const CGFloat FBScrollTouchProportion = 0.75f;
106
99
  scrollDirection:(FBXCUIElementScrollDirection)scrollDirection
107
100
  error:(NSError **)error
108
101
  {
109
- FBXCElementSnapshotWrapper *prescrollSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:[self fb_takeSnapshot]];
102
+ FBXCElementSnapshotWrapper *prescrollSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:[self fb_takeSnapshot:YES]];
103
+
110
104
  if (prescrollSnapshot.isWDVisible) {
111
105
  return YES;
112
106
  }
@@ -138,12 +132,12 @@ const CGFloat FBScrollTouchProportion = 0.75f;
138
132
  FBXCElementSnapshotWrapper *wrappedCellSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:cellSnapshot];
139
133
  if (wrappedCellSnapshot.wdVisible) {
140
134
  [visibleCellSnapshots addObject:cellSnapshot];
135
+ if (visibleCellSnapshots.count > 1) {
136
+ return YES;
137
+ }
141
138
  }
142
139
  }
143
140
 
144
- if (visibleCellSnapshots.count > 1) {
145
- return YES;
146
- }
147
141
  return NO;
148
142
  }];
149
143
 
@@ -213,9 +207,9 @@ const CGFloat FBScrollTouchProportion = 0.75f;
213
207
  // Cell is now visible, but it might be only partialy visible, scrolling till whole frame is visible.
214
208
  // Sometimes, attempting to grab the parent snapshot of the target cell after scrolling is complete causes a stale element reference exception.
215
209
  // Trying fb_cachedSnapshot first
216
- FBXCElementSnapshotWrapper *targetCellSnapshotWrapped = [FBXCElementSnapshotWrapper ensureWrapped:([self fb_cachedSnapshot] ?: [self fb_takeSnapshot])];
210
+ FBXCElementSnapshotWrapper *targetCellSnapshotWrapped = [FBXCElementSnapshotWrapper ensureWrapped:[self fb_takeSnapshot:YES]];
217
211
  targetCellSnapshot = [targetCellSnapshotWrapped fb_parentCellSnapshot];
218
- CGRect visibleFrame = [FBXCElementSnapshotWrapper ensureWrapped:targetCellSnapshot].fb_visibleFrameWithFallback;
212
+ CGRect visibleFrame = [FBXCElementSnapshotWrapper ensureWrapped:targetCellSnapshot].fb_visibleFrame;
219
213
 
220
214
  CGVector scrollVector = CGVectorMake(visibleFrame.size.width - targetCellSnapshot.frame.size.width,
221
215
  visibleFrame.size.height - targetCellSnapshot.frame.size.height
@@ -233,7 +227,7 @@ const CGFloat FBScrollTouchProportion = 0.75f;
233
227
  return YES;
234
228
  }
235
229
 
236
- id<FBXCElementSnapshot> appSnapshot = [self.application fb_takeSnapshot];
230
+ id<FBXCElementSnapshot> appSnapshot = [self.application fb_takeSnapshot:YES];
237
231
  for (id<FBXCElementSnapshot> elementSnapshot in appSnapshot._allDescendants.copy) {
238
232
  FBXCElementSnapshotWrapper *wrappedElementSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:elementSnapshot];
239
233
  // We are comparing pre-scroll snapshot so frames are irrelevant.
@@ -255,27 +249,32 @@ const CGFloat FBScrollTouchProportion = 0.75f;
255
249
  return self.visibleFrame;
256
250
  }
257
251
 
258
- - (void)fb_scrollUpByNormalizedDistance:(CGFloat)distance inApplication:(XCUIApplication *)application
252
+ - (void)fb_scrollUpByNormalizedDistance:(CGFloat)distance
253
+ inApplication:(XCUIApplication *)application
259
254
  {
260
255
  [self fb_scrollByNormalizedVector:CGVectorMake(0.0, distance) inApplication:application];
261
256
  }
262
257
 
263
- - (void)fb_scrollDownByNormalizedDistance:(CGFloat)distance inApplication:(XCUIApplication *)application
258
+ - (void)fb_scrollDownByNormalizedDistance:(CGFloat)distance
259
+ inApplication:(XCUIApplication *)application
264
260
  {
265
261
  [self fb_scrollByNormalizedVector:CGVectorMake(0.0, -distance) inApplication:application];
266
262
  }
267
263
 
268
- - (void)fb_scrollLeftByNormalizedDistance:(CGFloat)distance inApplication:(XCUIApplication *)application
264
+ - (void)fb_scrollLeftByNormalizedDistance:(CGFloat)distance
265
+ inApplication:(XCUIApplication *)application
269
266
  {
270
267
  [self fb_scrollByNormalizedVector:CGVectorMake(distance, 0.0) inApplication:application];
271
268
  }
272
269
 
273
- - (void)fb_scrollRightByNormalizedDistance:(CGFloat)distance inApplication:(XCUIApplication *)application
270
+ - (void)fb_scrollRightByNormalizedDistance:(CGFloat)distance
271
+ inApplication:(XCUIApplication *)application
274
272
  {
275
273
  [self fb_scrollByNormalizedVector:CGVectorMake(-distance, 0.0) inApplication:application];
276
274
  }
277
275
 
278
- - (BOOL)fb_scrollByNormalizedVector:(CGVector)normalizedScrollVector inApplication:(XCUIApplication *)application
276
+ - (BOOL)fb_scrollByNormalizedVector:(CGVector)normalizedScrollVector
277
+ inApplication:(XCUIApplication *)application
279
278
  {
280
279
  CGVector scrollVector = CGVectorMake(CGRectGetWidth(self.scrollingFrame) * normalizedScrollVector.dx,
281
280
  CGRectGetHeight(self.scrollingFrame) * normalizedScrollVector.dy
@@ -283,7 +282,9 @@ const CGFloat FBScrollTouchProportion = 0.75f;
283
282
  return [self fb_scrollByVector:scrollVector inApplication:application error:nil];
284
283
  }
285
284
 
286
- - (BOOL)fb_scrollByVector:(CGVector)vector inApplication:(XCUIApplication *)application error:(NSError **)error
285
+ - (BOOL)fb_scrollByVector:(CGVector)vector
286
+ inApplication:(XCUIApplication *)application
287
+ error:(NSError **)error
287
288
  {
288
289
  CGVector scrollBoundingVector = CGVectorMake(
289
290
  CGRectGetWidth(self.scrollingFrame) * FBScrollTouchProportion,
@@ -314,7 +315,9 @@ const CGFloat FBScrollTouchProportion = 0.75f;
314
315
  return CGVectorMake((CGFloat)floor(x), (CGFloat)floor(y));
315
316
  }
316
317
 
317
- - (BOOL)fb_scrollAncestorScrollViewByVectorWithinScrollViewFrame:(CGVector)vector inApplication:(XCUIApplication *)application error:(NSError **)error
318
+ - (BOOL)fb_scrollAncestorScrollViewByVectorWithinScrollViewFrame:(CGVector)vector
319
+ inApplication:(XCUIApplication *)application
320
+ error:(NSError **)error
318
321
  {
319
322
  CGVector hitpointOffset = [self fb_hitPointOffsetForScrollingVector:vector];
320
323
 
@@ -91,7 +91,7 @@ BOOL FBTypeText(NSString *text, NSUInteger typingSpeed, NSError **error)
91
91
  [FBLogger logFmt:@"Trying to tap the \"%@\" element to have it focused", snapshot.fb_description];
92
92
  [self tap];
93
93
  // It might take some time to update the UI
94
- [self fb_takeSnapshot];
94
+ [self fb_takeSnapshot:NO];
95
95
  #endif
96
96
  }
97
97
 
@@ -110,9 +110,7 @@ BOOL FBTypeText(NSString *text, NSUInteger typingSpeed, NSError **error)
110
110
  frequency:(NSUInteger)frequency
111
111
  error:(NSError **)error
112
112
  {
113
- id<FBXCElementSnapshot> snapshot = self.fb_isResolvedFromCache.boolValue
114
- ? self.lastSnapshot
115
- : self.fb_takeSnapshot;
113
+ id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:NO];
116
114
  FBXCElementSnapshotWrapper *wrapped = [FBXCElementSnapshotWrapper ensureWrapped:snapshot];
117
115
  [self fb_prepareForTextInputWithSnapshot:wrapped];
118
116
  if (shouldClear && ![self fb_clearTextWithSnapshot:wrapped shouldPrepareForInput:NO error:error]) {
@@ -123,9 +121,7 @@ BOOL FBTypeText(NSString *text, NSUInteger typingSpeed, NSError **error)
123
121
 
124
122
  - (BOOL)fb_clearTextWithError:(NSError **)error
125
123
  {
126
- id<FBXCElementSnapshot> snapshot = self.fb_isResolvedFromCache.boolValue
127
- ? self.lastSnapshot
128
- : self.fb_takeSnapshot;
124
+ id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:NO];
129
125
  return [self fb_clearTextWithSnapshot:[FBXCElementSnapshotWrapper ensureWrapped:snapshot]
130
126
  shouldPrepareForInput:YES
131
127
  error:error];
@@ -182,7 +178,7 @@ BOOL FBTypeText(NSString *text, NSUInteger typingSpeed, NSError **error)
182
178
  return NO;
183
179
  }
184
180
 
185
- currentValue = self.fb_takeSnapshot.value;
181
+ currentValue = [self fb_takeSnapshot:NO].value;
186
182
  if (nil != placeholderValue && [currentValue isEqualToString:placeholderValue]) {
187
183
  // Short circuit if only the placeholder value left
188
184
  return YES;
@@ -22,14 +22,14 @@
22
22
  {
23
23
  return [FBElementUtils idWithAccessibilityElement:([self isKindOfClass:XCUIApplication.class]
24
24
  ? [(XCUIApplication *)self accessibilityElement]
25
- : [self fb_takeSnapshot].accessibilityElement)];
25
+ : [self fb_takeSnapshot:NO].accessibilityElement)];
26
26
  }
27
27
 
28
28
  - (NSString *)fb_uid
29
29
  {
30
30
  return [self isKindOfClass:XCUIApplication.class]
31
31
  ? [FBElementUtils uidWithAccessibilityElement:[(XCUIApplication *)self accessibilityElement]]
32
- : [FBXCElementSnapshotWrapper ensureWrapped:[self fb_takeSnapshot]].fb_uid;
32
+ : [FBXCElementSnapshotWrapper ensureWrapped:[self fb_takeSnapshot:NO]].fb_uid;
33
33
  }
34
34
 
35
35
  @end
@@ -19,12 +19,13 @@ NS_ASSUME_NONNULL_BEGIN
19
19
  Gets the most recent snapshot of the current element. The element will be
20
20
  automatically resolved if the snapshot is not available yet.
21
21
  Calls to this method mutate the `lastSnapshot` instance property..
22
- Calls to this method reset the `fb_isResolvedFromCache` property value to `NO`.
23
22
 
23
+ @param inDepth Whether to resolve snapshot parents and children. Setting it to NO
24
+ would improve the snapshotting performance
24
25
  @return The recent snapshot of the element
25
26
  @throws FBStaleElementException if the element is not present in DOM and thus no snapshot could be made
26
27
  */
27
- - (id<FBXCElementSnapshot>)fb_takeSnapshot;
28
+ - (id<FBXCElementSnapshot>)fb_takeSnapshot:(BOOL)inDepth;
28
29
 
29
30
  /**
30
31
  Extracts the cached element snapshot from its query.
@@ -36,40 +37,6 @@ NS_ASSUME_NONNULL_BEGIN
36
37
  */
37
38
  - (nullable id<FBXCElementSnapshot>)fb_cachedSnapshot;
38
39
 
39
- /**
40
- Gets the most recent snapshot of the current element and already resolves the accessibility attributes
41
- needed for creating the page source of this element. No additional calls to the accessibility layer
42
- are required.
43
- Calls to this method mutate the `lastSnapshot` instance property.
44
- Calls to this method reset the `fb_isResolvedFromCache` property value to `NO`.
45
-
46
- @param maxDepth The maximum depth of the snapshot. nil value means to use the default depth.
47
- with custom attributes cannot be resolved
48
-
49
- @return The recent snapshot of the element with all attributes resolved or a snapshot with default
50
- attributes resolved if there was a failure while resolving additional attributes
51
- @throws FBStaleElementException if the element is not present in DOM and thus no snapshot could be made
52
- */
53
- - (nullable id<FBXCElementSnapshot>)fb_snapshotWithAllAttributesAndMaxDepth:(nullable NSNumber *)maxDepth;
54
-
55
- /**
56
- Gets the most recent snapshot of the current element with given attributes resolved.
57
- No additional calls to the accessibility layer are required.
58
- Calls to this method mutate the `lastSnapshot` instance property.
59
- Calls to this method reset the `fb_isResolvedFromCache` property value to `NO`.
60
-
61
- @param attributeNames The list of attribute names to resolve. Must be one of
62
- FB_...Name values exported by XCTestPrivateSymbols.h module.
63
- `nil` value means that only the default attributes must be extracted
64
- @param maxDepth The maximum depth of the snapshot. nil value means to use the default depth.
65
-
66
- @return The recent snapshot of the element with the given attributes resolved or a snapshot with default
67
- attributes resolved if there was a failure while resolving additional attributes
68
- @throws FBStaleElementException if the element is not present in DOM and thus no snapshot could be made
69
- */
70
- - (nullable id<FBXCElementSnapshot>)fb_snapshotWithAttributes:(nullable NSArray<NSString *> *)attributeNames
71
- maxDepth:(nullable NSNumber *)maxDepth;
72
-
73
40
  /**
74
41
  Filters elements by matching them to snapshots from the corresponding array
75
42
 
@@ -14,6 +14,7 @@
14
14
  #import "FBConfiguration.h"
15
15
  #import "FBExceptions.h"
16
16
  #import "FBImageUtils.h"
17
+ #import "FBElementUtils.h"
17
18
  #import "FBLogger.h"
18
19
  #import "FBMacros.h"
19
20
  #import "FBMathUtils.h"
@@ -32,6 +33,7 @@
32
33
  #import "XCTestPrivateSymbols.h"
33
34
  #import "XCTRunnerDaemonSession.h"
34
35
  #import "XCUIApplicationProcess+FBQuiescence.h"
36
+ #import "XCUIApplication.h"
35
37
  #import "XCUIElement+FBCaching.h"
36
38
  #import "XCUIElement+FBWebDriverAttributes.h"
37
39
  #import "XCUIElementQuery.h"
@@ -40,22 +42,21 @@
40
42
  #import "XCUIScreen.h"
41
43
  #import "XCUIElement+FBResolve.h"
42
44
 
43
- #define DEFAULT_AX_TIMEOUT 60.
44
-
45
45
  @implementation XCUIElement (FBUtilities)
46
46
 
47
- - (id<FBXCElementSnapshot>)fb_takeSnapshot
47
+ - (id<FBXCElementSnapshot>)fb_takeSnapshot:(BOOL)inDepth
48
48
  {
49
49
  NSError *error = nil;
50
- self.fb_isResolvedFromCache = @(NO);
51
- self.lastSnapshot = [self.fb_query fb_uniqueSnapshotWithError:&error];
50
+ self.lastSnapshot = inDepth
51
+ ? [self.fb_query fb_uniqueSnapshotWithError:&error]
52
+ : (id<FBXCElementSnapshot>)[self snapshotWithError:&error];
52
53
  if (nil == self.lastSnapshot) {
53
54
  NSString *hintText = @"Make sure the application UI has the expected state";
54
- if (nil != error
55
- && [error.localizedDescription containsString:@"Identity Binding"]) {
55
+ if (nil != error && [error.localizedDescription containsString:@"Identity Binding"]) {
56
56
  hintText = [NSString stringWithFormat:@"%@. You could also try to switch the binding strategy using the 'boundElementsByIndex' setting for the element lookup", hintText];
57
57
  }
58
- NSString *reason = [NSString stringWithFormat:@"The previously found element \"%@\" is not present in the current view anymore. %@", self.description, hintText];
58
+ NSString *reason = [NSString stringWithFormat:@"The previously found element \"%@\" is not present in the current view anymore. %@",
59
+ self.description, hintText];
59
60
  if (nil != error) {
60
61
  reason = [NSString stringWithFormat:@"%@. Original error: %@", reason, error.localizedDescription];
61
62
  }
@@ -69,63 +70,6 @@
69
70
  return [self.query fb_cachedSnapshot];
70
71
  }
71
72
 
72
- - (nullable id<FBXCElementSnapshot>)fb_snapshotWithAllAttributesAndMaxDepth:(NSNumber *)maxDepth
73
- {
74
- NSMutableArray *allNames = [NSMutableArray arrayWithArray:FBStandardAttributeNames()];
75
- [allNames addObjectsFromArray:FBCustomAttributeNames()];
76
- return [self fb_snapshotWithAttributes:allNames.copy
77
- maxDepth:maxDepth];
78
- }
79
-
80
- - (nullable id<FBXCElementSnapshot>)fb_snapshotWithAttributes:(NSArray<NSString *> *)attributeNames
81
- maxDepth:(NSNumber *)maxDepth
82
- {
83
- NSSet<NSString *> *standardAttributes = [NSSet setWithArray:FBStandardAttributeNames()];
84
- id<FBXCElementSnapshot> snapshot = self.fb_takeSnapshot;
85
- NSTimeInterval axTimeout = FBConfiguration.customSnapshotTimeout;
86
- if (nil == attributeNames
87
- || [[NSSet setWithArray:attributeNames] isSubsetOfSet:standardAttributes]
88
- || axTimeout < DBL_EPSILON) {
89
- // return the "normal" element snapshot if no custom attributes are requested
90
- return snapshot;
91
- }
92
-
93
- id<FBXCAccessibilityElement> axElement = snapshot.accessibilityElement;
94
- if (nil == axElement) {
95
- return nil;
96
- }
97
-
98
- NSError *setTimeoutError;
99
- BOOL isTimeoutSet = [FBXCAXClientProxy.sharedClient setAXTimeout:axTimeout
100
- error:&setTimeoutError];
101
- if (!isTimeoutSet) {
102
- [FBLogger logFmt:@"Cannot set snapshoting timeout to %.1fs. Original error: %@",
103
- axTimeout, setTimeoutError.localizedDescription];
104
- }
105
-
106
- NSError *error;
107
- id<FBXCElementSnapshot> snapshotWithAttributes = [FBXCAXClientProxy.sharedClient snapshotForElement:axElement
108
- attributes:attributeNames
109
- maxDepth:maxDepth
110
- error:&error];
111
- if (nil == snapshotWithAttributes) {
112
- NSString *description = [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_description;
113
- [FBLogger logFmt:@"Cannot take a snapshot with attribute(s) %@ of '%@' after %.2f seconds",
114
- attributeNames, description, axTimeout];
115
- [FBLogger logFmt:@"This timeout could be customized via '%@' setting", FB_SETTING_CUSTOM_SNAPSHOT_TIMEOUT];
116
- [FBLogger logFmt:@"Internal error: %@", error.localizedDescription];
117
- [FBLogger logFmt:@"Falling back to the default snapshotting mechanism for the element '%@' (some attribute values, like visibility or accessibility might not be precise though)", description];
118
- snapshotWithAttributes = self.lastSnapshot;
119
- } else {
120
- self.lastSnapshot = snapshotWithAttributes;
121
- }
122
-
123
- if (isTimeoutSet) {
124
- [FBXCAXClientProxy.sharedClient setAXTimeout:DEFAULT_AX_TIMEOUT error:nil];
125
- }
126
- return snapshotWithAttributes;
127
- }
128
-
129
73
  - (NSArray<XCUIElement *> *)fb_filterDescendantsWithSnapshots:(NSArray<id<FBXCElementSnapshot>> *)snapshots
130
74
  selfUID:(NSString *)selfUID
131
75
  onlyChildren:(BOOL)onlyChildren
@@ -143,9 +87,7 @@
143
87
  NSMutableArray<XCUIElement *> *matchedElements = [NSMutableArray array];
144
88
  NSString *uid = selfUID;
145
89
  if (nil == uid) {
146
- uid = self.fb_isResolvedFromCache.boolValue
147
- ? [FBXCElementSnapshotWrapper wdUIDWithSnapshot:self.lastSnapshot]
148
- : self.fb_uid;
90
+ uid = self.fb_uid;
149
91
  }
150
92
  if (nil != uid && [matchedIds containsObject:uid]) {
151
93
  XCUIElement *stableSelf = self.fb_stableInstance;
@@ -0,0 +1,36 @@
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 "FBXCElementSnapshotWrapper.h"
11
+
12
+ NS_ASSUME_NONNULL_BEGIN
13
+
14
+ @interface XCUIElement (FBVisibleFrame)
15
+
16
+ /**
17
+ Returns the snapshot visibleFrame with a fallback to direct attribute retrieval from FBXCAXClient in case of a snapshot fault (nil visibleFrame)
18
+
19
+ @return the snapshot visibleFrame
20
+ */
21
+ - (CGRect)fb_visibleFrame;
22
+
23
+ @end
24
+
25
+ @interface FBXCElementSnapshotWrapper (FBVisibleFrame)
26
+
27
+ /**
28
+ Returns the snapshot visibleFrame with a fallback to direct attribute retrieval from FBXCAXClient in case of a snapshot fault (nil visibleFrame)
29
+
30
+ @return the snapshot visibleFrame
31
+ */
32
+ - (CGRect)fb_visibleFrame;
33
+
34
+ @end
35
+
36
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,53 @@
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 "XCUIElement+FBVisibleFrame.h"
11
+ #import "FBElementUtils.h"
12
+ #import "FBXCodeCompatibility.h"
13
+ #import "FBXCElementSnapshotWrapper+Helpers.h"
14
+ #import "XCUIElement+FBUtilities.h"
15
+ #import "XCTestPrivateSymbols.h"
16
+
17
+ @implementation XCUIElement (FBVisibleFrame)
18
+
19
+ - (CGRect)fb_visibleFrame
20
+ {
21
+ id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:NO];
22
+ return [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_visibleFrame;
23
+ }
24
+
25
+ @end
26
+
27
+ @implementation FBXCElementSnapshotWrapper (FBVisibleFrame)
28
+
29
+ - (CGRect)fb_visibleFrame
30
+ {
31
+ CGRect thisVisibleFrame = [self visibleFrame];
32
+ if (!CGRectIsEmpty(thisVisibleFrame)) {
33
+ return thisVisibleFrame;
34
+ }
35
+
36
+ NSDictionary *visibleFrameDict = [self fb_attributeValue:FB_XCAXAVisibleFrameAttributeName
37
+ error:nil];
38
+ if (nil == visibleFrameDict) {
39
+ return thisVisibleFrame;
40
+ }
41
+
42
+ id x = [visibleFrameDict objectForKey:@"X"];
43
+ id y = [visibleFrameDict objectForKey:@"Y"];
44
+ id height = [visibleFrameDict objectForKey:@"Height"];
45
+ id width = [visibleFrameDict objectForKey:@"Width"];
46
+ if (x != nil && y != nil && height != nil && width != nil) {
47
+ return CGRectMake([x doubleValue], [y doubleValue], [width doubleValue], [height doubleValue]);
48
+ }
49
+
50
+ return thisVisibleFrame;
51
+ }
52
+
53
+ @end
@@ -28,24 +28,10 @@
28
28
 
29
29
  - (id<FBXCElementSnapshot>)fb_snapshotForAttributeName:(NSString *)name
30
30
  {
31
- // These attributes are special, because we can only retrieve them from
32
- // the snapshot if we explicitly ask XCTest to include them into the query while taking it.
33
- // That is why fb_snapshotWithAllAttributes method must be used instead of the default snapshot
34
- // call
35
- if ([name isEqualToString:FBStringify(XCUIElement, isWDVisible)]) {
36
- return [self fb_snapshotWithAttributes:@[FB_XCAXAIsVisibleAttributeName]
37
- maxDepth:@1];
38
- }
39
- if ([name isEqualToString:FBStringify(XCUIElement, isWDAccessible)]) {
40
- return [self fb_snapshotWithAttributes:@[FB_XCAXAIsElementAttributeName]
41
- maxDepth:@1];
42
- }
43
- if ([name isEqualToString:FBStringify(XCUIElement, isWDAccessibilityContainer)]) {
44
- return [self fb_snapshotWithAttributes:@[FB_XCAXAIsElementAttributeName]
45
- maxDepth:nil];
46
- }
47
-
48
- return self.fb_takeSnapshot;
31
+ BOOL inDepth = [name isEqualToString:FBStringify(XCUIElement, isWDAccessible)]
32
+ || [name isEqualToString:FBStringify(XCUIElement, isWDAccessibilityContainer)]
33
+ || [name isEqualToString:FBStringify(XCUIElement, wdIndex)];
34
+ return [self fb_takeSnapshot:inDepth];
49
35
  }
50
36
 
51
37
  - (id)fb_valueForWDAttributeName:(NSString *)name
@@ -92,6 +78,7 @@
92
78
  value = @([value boolValue]);
93
79
  } else if (elementType == XCUIElementTypeTextView ||
94
80
  elementType == XCUIElementTypeTextField ||
81
+ elementType == XCUIElementTypeSearchField ||
95
82
  elementType == XCUIElementTypeSecureTextField) {
96
83
  NSString *placeholderValue = self.placeholderValue;
97
84
  value = FBFirstNonEmptyValue(value, placeholderValue);
@@ -183,8 +170,8 @@
183
170
  // In the scenario when table provides Search results controller, table could be marked as accessible element, even though it isn't
184
171
  // As it is highly unlikely that table view should ever be an accessibility element itself,
185
172
  // for now we work around that by skipping Table View in container checks
186
- if ([FBXCElementSnapshotWrapper ensureWrapped:parentSnapshot].fb_isAccessibilityElement
187
- && parentSnapshot.elementType != XCUIElementTypeTable) {
173
+ if (parentSnapshot.elementType != XCUIElementTypeTable
174
+ && [FBXCElementSnapshotWrapper ensureWrapped:parentSnapshot].fb_isAccessibilityElement) {
188
175
  return NO;
189
176
  }
190
177
  parentSnapshot = parentSnapshot.parent;
@@ -567,7 +567,8 @@
567
567
  FBElementCache *elementCache = request.session.elementCache;
568
568
  BOOL hasElement = ![request.parameters[@"uuid"] isEqual:@"0"];
569
569
  XCUIElement *destination = hasElement
570
- ? [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]
570
+ ? [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]
571
+ checkStaleness:YES]
571
572
  : request.session.activeApplication;
572
573
  id keys = request.arguments[@"keys"];
573
574