appium-webdriveragent 4.6.0 → 4.8.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 (102) hide show
  1. package/PrivateHeaders/XCTest/XCAXClient_iOS.h +2 -4
  2. package/PrivateHeaders/XCTest/XCActivityRecord.h +3 -3
  3. package/PrivateHeaders/XCTest/XCApplicationQuery.h +3 -3
  4. package/PrivateHeaders/XCTest/XCTElementSetTransformer-Protocol.h +2 -2
  5. package/PrivateHeaders/XCTest/XCTRunnerDaemonSession.h +1 -1
  6. package/PrivateHeaders/XCTest/XCTestManager_IDEInterface-Protocol.h +5 -5
  7. package/PrivateHeaders/XCTest/XCTestManager_ManagerInterface-Protocol.h +8 -8
  8. package/PrivateHeaders/XCTest/XCUIApplication.h +2 -2
  9. package/PrivateHeaders/XCTest/XCUIApplicationImpl.h +2 -2
  10. package/PrivateHeaders/XCTest/XCUIApplicationProcess.h +3 -5
  11. package/PrivateHeaders/XCTest/XCUIElement.h +4 -4
  12. package/PrivateHeaders/XCTest/XCUIElementQuery.h +4 -4
  13. package/PrivateHeaders/XCTest/XCUIRecorderNodeFinder.h +3 -3
  14. package/PrivateHeaders/XCTest/XCUIRecorderUtilities.h +3 -3
  15. package/Scripts/build.sh +3 -6
  16. package/WebDriverAgent.xcodeproj/project.pbxproj +66 -70
  17. package/WebDriverAgent.xcodeproj/project.xcworkspace/xcuserdata/elf.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  18. package/WebDriverAgentLib/Categories/{XCElementSnapshot+FBHelpers.h → FBXCElementSnapshotWrapper+Helpers.h} +18 -11
  19. package/WebDriverAgentLib/Categories/{XCElementSnapshot+FBHelpers.m → FBXCElementSnapshotWrapper+Helpers.m} +57 -39
  20. package/WebDriverAgentLib/Categories/NSExpression+FBFormat.m +8 -3
  21. package/WebDriverAgentLib/Categories/XCUIApplication+FBAlert.m +8 -7
  22. package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h +2 -2
  23. package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +29 -28
  24. package/WebDriverAgentLib/Categories/XCUIApplicationProcess+FBQuiescence.m +5 -0
  25. package/WebDriverAgentLib/Categories/XCUICoordinate+FBFix.m +0 -1
  26. package/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m +8 -5
  27. package/WebDriverAgentLib/Categories/XCUIElement+FBAccessibility.h +2 -2
  28. package/WebDriverAgentLib/Categories/XCUIElement+FBAccessibility.m +5 -4
  29. package/WebDriverAgentLib/Categories/XCUIElement+FBCaching.m +3 -2
  30. package/WebDriverAgentLib/Categories/XCUIElement+FBFind.m +22 -18
  31. package/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.h +2 -3
  32. package/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m +28 -26
  33. package/WebDriverAgentLib/Categories/XCUIElement+FBPickerWheel.m +2 -1
  34. package/WebDriverAgentLib/Categories/XCUIElement+FBResolve.m +8 -4
  35. package/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.h +10 -0
  36. package/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m +81 -50
  37. package/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m +11 -10
  38. package/WebDriverAgentLib/Categories/XCUIElement+FBUID.h +10 -5
  39. package/WebDriverAgentLib/Categories/XCUIElement+FBUID.m +15 -3
  40. package/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h +7 -7
  41. package/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +29 -20
  42. package/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.h +2 -2
  43. package/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m +16 -13
  44. package/WebDriverAgentLib/Categories/XCUIElementQuery+FBHelpers.h +2 -3
  45. package/WebDriverAgentLib/Categories/XCUIElementQuery+FBHelpers.m +3 -3
  46. package/WebDriverAgentLib/Commands/FBElementCommands.m +29 -15
  47. package/WebDriverAgentLib/Commands/FBFindElementCommands.m +5 -6
  48. package/WebDriverAgentLib/FBAlert.m +16 -13
  49. package/WebDriverAgentLib/FBApplication.m +8 -8
  50. package/WebDriverAgentLib/Routing/FBElementUtils.h +11 -2
  51. package/WebDriverAgentLib/Routing/FBElementUtils.m +15 -12
  52. package/WebDriverAgentLib/Routing/FBResponsePayload.m +11 -10
  53. package/WebDriverAgentLib/Routing/FBSession.m +1 -1
  54. package/{PrivateHeaders/XCTest/XCAccessibilityElement.h → WebDriverAgentLib/Routing/FBXCAccessibilityElement.h} +19 -18
  55. package/WebDriverAgentLib/{Categories/XCAccessibilityElement+FBComparison.m → Routing/FBXCAccessibilityElement.m} +5 -11
  56. package/WebDriverAgentLib/Routing/FBXCDeviceEvent.h +35 -0
  57. package/WebDriverAgentLib/Routing/FBXCDeviceEvent.m +43 -0
  58. package/{PrivateHeaders/XCTest/XCElementSnapshot.h → WebDriverAgentLib/Routing/FBXCElementSnapshot.h} +25 -44
  59. package/WebDriverAgentLib/Routing/FBXCElementSnapshot.m +10 -0
  60. package/WebDriverAgentLib/Routing/FBXCElementSnapshotWrapper.h +30 -0
  61. package/WebDriverAgentLib/Routing/FBXCElementSnapshotWrapper.m +45 -0
  62. package/WebDriverAgentLib/Utilities/FBActiveAppDetectionPoint.h +3 -4
  63. package/WebDriverAgentLib/Utilities/FBActiveAppDetectionPoint.m +4 -4
  64. package/WebDriverAgentLib/Utilities/FBBaseActionsSynthesizer.h +2 -2
  65. package/WebDriverAgentLib/Utilities/FBBaseActionsSynthesizer.m +7 -8
  66. package/WebDriverAgentLib/Utilities/FBClassChainQueryParser.m +1 -2
  67. package/WebDriverAgentLib/Utilities/FBConfiguration.m +0 -1
  68. package/WebDriverAgentLib/Utilities/FBImageIOScaler.m +3 -0
  69. package/WebDriverAgentLib/Utilities/FBKeyboard.m +1 -2
  70. package/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m +1 -1
  71. package/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m +3 -3
  72. package/WebDriverAgentLib/Utilities/FBXCAXClientProxy.h +10 -9
  73. package/WebDriverAgentLib/Utilities/FBXCAXClientProxy.m +14 -8
  74. package/WebDriverAgentLib/Utilities/FBXCTestDaemonsProxy.h +0 -1
  75. package/WebDriverAgentLib/Utilities/FBXCTestDaemonsProxy.m +6 -0
  76. package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h +0 -10
  77. package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m +0 -24
  78. package/WebDriverAgentLib/Utilities/FBXPath-Private.h +1 -1
  79. package/WebDriverAgentLib/Utilities/FBXPath.h +3 -3
  80. package/WebDriverAgentLib/Utilities/FBXPath.m +15 -13
  81. package/WebDriverAgentLib/Utilities/NSPredicate+FBFormat.h +14 -1
  82. package/WebDriverAgentLib/Utilities/NSPredicate+FBFormat.m +18 -9
  83. package/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.m +9 -3
  84. package/WebDriverAgentLib/Utilities/XCUIApplicationProcessDelay.m +7 -1
  85. package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.m +7 -1
  86. package/WebDriverAgentLib/WebDriverAgentLib.h +0 -1
  87. package/WebDriverAgentRunner-Runner.app.zip +0 -0
  88. package/WebDriverAgentTests/IntegrationTests/FBScrollingTests.m +10 -0
  89. package/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m +26 -19
  90. package/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHelperTests.m +24 -29
  91. package/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHitPointTests.m +2 -2
  92. package/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m +5 -3
  93. package/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m +2 -1
  94. package/{WebDriverAgentLib/Categories/XCElementSnapshot+FBHitPoint.h → WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.h} +3 -14
  95. package/WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.m +99 -0
  96. package/WebDriverAgentTests/UnitTests/FBXPathTests.m +21 -13
  97. package/WebDriverAgentTests/UnitTests/NSPredicateFBFormatTests.m +4 -5
  98. package/package.json +1 -2
  99. package/WebDriverAgentLib/Categories/XCAccessibilityElement+FBComparison.h +0 -27
  100. package/WebDriverAgentLib/Categories/XCElementSnapshot+FBHitPoint.m +0 -29
  101. package/WebDriverAgentLib/Utilities/FBPredicate.h +0 -28
  102. package/WebDriverAgentLib/Utilities/FBPredicate.m +0 -29
@@ -13,7 +13,8 @@
13
13
  #import "FBErrorBuilder.h"
14
14
  #import "FBKeyboard.h"
15
15
  #import "NSString+FBVisualLength.h"
16
- #import "XCElementSnapshot+FBHelpers.h"
16
+ #import "FBXCElementSnapshotWrapper.h"
17
+ #import "FBXCElementSnapshotWrapper+Helpers.h"
17
18
  #import "XCUIElement+FBCaching.h"
18
19
  #import "XCUIElement+FBTap.h"
19
20
  #import "XCUIElement+FBUtilities.h"
@@ -39,19 +40,19 @@
39
40
  @end
40
41
 
41
42
 
42
- @interface XCElementSnapshot (FBKeyboardFocus)
43
+ @interface FBXCElementSnapshotWrapper (FBKeyboardFocus)
43
44
 
44
45
  - (BOOL)fb_hasKeyboardFocus;
45
46
 
46
47
  @end
47
48
 
48
- @implementation XCElementSnapshot (FBKeyboardFocus)
49
+ @implementation FBXCElementSnapshotWrapper (FBKeyboardFocus)
49
50
 
50
51
  - (BOOL)fb_hasKeyboardFocus
51
52
  {
52
53
  // https://developer.apple.com/documentation/xctest/xcuielement/1500968-typetext?language=objc
53
54
  // > The element or a descendant must have keyboard focus; otherwise an error is raised.
54
- return self.hasKeyboardFocus || [self descendantsByFilteringWithBlock:^BOOL(XCElementSnapshot *snapshot) {
55
+ return self.hasKeyboardFocus || [self descendantsByFilteringWithBlock:^BOOL(id<FBXCElementSnapshot> snapshot) {
55
56
  return snapshot.hasKeyboardFocus;
56
57
  }].count > 0;
57
58
  }
@@ -61,7 +62,7 @@
61
62
 
62
63
  @implementation XCUIElement (FBTyping)
63
64
 
64
- - (void)fb_prepareForTextInputWithSnapshot:(XCElementSnapshot *)snapshot
65
+ - (void)fb_prepareForTextInputWithSnapshot:(FBXCElementSnapshotWrapper *)snapshot
65
66
  {
66
67
  if (snapshot.fb_hasKeyboardFocus) {
67
68
  return;
@@ -92,10 +93,10 @@
92
93
  frequency:(NSUInteger)frequency
93
94
  error:(NSError **)error
94
95
  {
95
- XCElementSnapshot *snapshot = self.fb_isResolvedFromCache.boolValue
96
+ id<FBXCElementSnapshot> snapshot = self.fb_isResolvedFromCache.boolValue
96
97
  ? self.lastSnapshot
97
98
  : self.fb_takeSnapshot;
98
- [self fb_prepareForTextInputWithSnapshot:snapshot];
99
+ [self fb_prepareForTextInputWithSnapshot:[FBXCElementSnapshotWrapper ensureWrapped:snapshot]];
99
100
  if (shouldClear && ![self fb_clearTextWithSnapshot:self.lastSnapshot
100
101
  shouldPrepareForInput:NO
101
102
  error:error]) {
@@ -106,15 +107,15 @@
106
107
 
107
108
  - (BOOL)fb_clearTextWithError:(NSError **)error
108
109
  {
109
- XCElementSnapshot *snapshot = self.fb_isResolvedFromCache.boolValue
110
+ id<FBXCElementSnapshot> snapshot = self.fb_isResolvedFromCache.boolValue
110
111
  ? self.lastSnapshot
111
112
  : self.fb_takeSnapshot;
112
- return [self fb_clearTextWithSnapshot:snapshot
113
+ return [self fb_clearTextWithSnapshot:[FBXCElementSnapshotWrapper ensureWrapped:snapshot]
113
114
  shouldPrepareForInput:YES
114
115
  error:error];
115
116
  }
116
117
 
117
- - (BOOL)fb_clearTextWithSnapshot:(XCElementSnapshot *)snapshot
118
+ - (BOOL)fb_clearTextWithSnapshot:(FBXCElementSnapshotWrapper *)snapshot
118
119
  shouldPrepareForInput:(BOOL)shouldPrepareForInput
119
120
  error:(NSError **)error
120
121
  {
@@ -7,24 +7,29 @@
7
7
  * of patent rights can be found in the PATENTS file in the same directory.
8
8
  */
9
9
 
10
- #import <WebDriverAgentLib/XCElementSnapshot.h>
11
- #import <WebDriverAgentLib/XCUIElement.h>
10
+ #import "FBXCElementSnapshotWrapper.h"
12
11
 
13
12
  NS_ASSUME_NONNULL_BEGIN
14
13
 
15
14
  @interface XCUIElement (FBUID)
16
15
 
17
- /*! Represents unique internal element identifier, which is the same for an element and its snapshot */
16
+ /*! Represents unique internal element identifier, which is the same for an element and its snapshot as UUIDv4 */
18
17
  @property (nonatomic, nullable, readonly, copy) NSString *fb_uid;
19
18
 
19
+ /*! Represents unique internal element identifier, which is the same for an element and its snapshot */
20
+ @property (nonatomic, readonly) unsigned long long fb_accessibiltyId;
21
+
20
22
  @end
21
23
 
22
24
 
23
- @interface XCElementSnapshot (FBUID)
25
+ @interface FBXCElementSnapshotWrapper (FBUID)
24
26
 
25
- /*! Represents unique internal element identifier, which is the same for an element and its snapshot */
27
+ /*! Represents unique internal element identifier, which is the same for an element and its snapshot as UUIDv4 */
26
28
  @property (nonatomic, nullable, readonly, copy) NSString *fb_uid;
27
29
 
30
+ /*! Represents unique internal element identifier, which is the same for an element and its snapshot */
31
+ @property (nonatomic, readonly) unsigned long long fb_accessibiltyId;
32
+
28
33
  @end
29
34
 
30
35
  NS_ASSUME_NONNULL_END
@@ -15,20 +15,32 @@
15
15
 
16
16
  @implementation XCUIElement (FBUID)
17
17
 
18
+ - (unsigned long long)fb_accessibiltyId
19
+ {
20
+ return [FBElementUtils idWithAccessibilityElement:([self isKindOfClass:XCUIApplication.class]
21
+ ? [(XCUIApplication *)self accessibilityElement]
22
+ : [self fb_takeSnapshot].accessibilityElement)];
23
+ }
24
+
18
25
  - (NSString *)fb_uid
19
26
  {
20
27
  return [self isKindOfClass:XCUIApplication.class]
21
28
  ? [FBElementUtils uidWithAccessibilityElement:[(XCUIApplication *)self accessibilityElement]]
22
- : [self fb_takeSnapshot].fb_uid;
29
+ : [FBXCElementSnapshotWrapper ensureWrapped:[self fb_takeSnapshot]].fb_uid;
23
30
  }
24
31
 
25
32
  @end
26
33
 
27
- @implementation XCElementSnapshot (FBUID)
34
+ @implementation FBXCElementSnapshotWrapper (FBUID)
35
+
36
+ - (unsigned long long)fb_accessibiltyId
37
+ {
38
+ return [FBElementUtils idWithAccessibilityElement:self.accessibilityElement];
39
+ }
28
40
 
29
41
  - (NSString *)fb_uid
30
42
  {
31
- return [FBElementUtils uidWithAccessibilityElement:self.accessibilityElement];
43
+ return [FBElementUtils uidWithAccessibilityElement:[self accessibilityElement]];
32
44
  }
33
45
 
34
46
  @end
@@ -8,8 +8,8 @@
8
8
  */
9
9
 
10
10
  #import <XCTest/XCTest.h>
11
- #import <WebDriverAgentLib/XCElementSnapshot.h>
12
11
  #import <WebDriverAgentLib/FBElement.h>
12
+ #import "FBXCElementSnapshot.h"
13
13
 
14
14
  NS_ASSUME_NONNULL_BEGIN
15
15
 
@@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
24
24
  @return The recent snapshot of the element
25
25
  @throws FBStaleElementException if the element is not present in DOM and thus no snapshot could be made
26
26
  */
27
- - (XCElementSnapshot *)fb_takeSnapshot;
27
+ - (id<FBXCElementSnapshot>)fb_takeSnapshot;
28
28
 
29
29
  /**
30
30
  Extracts the cached element snapshot from its query.
@@ -34,7 +34,7 @@ NS_ASSUME_NONNULL_BEGIN
34
34
 
35
35
  @return Either the cached snapshot or nil
36
36
  */
37
- - (nullable XCElementSnapshot *)fb_cachedSnapshot;
37
+ - (nullable id<FBXCElementSnapshot>)fb_cachedSnapshot;
38
38
 
39
39
  /**
40
40
  Gets the most recent snapshot of the current element and already resolves the accessibility attributes
@@ -50,7 +50,7 @@ NS_ASSUME_NONNULL_BEGIN
50
50
  attributes resolved if there was a failure while resolving additional attributes
51
51
  @throws FBStaleElementException if the element is not present in DOM and thus no snapshot could be made
52
52
  */
53
- - (nullable XCElementSnapshot *)fb_snapshotWithAllAttributesAndMaxDepth:(nullable NSNumber *)maxDepth;
53
+ - (nullable id<FBXCElementSnapshot>)fb_snapshotWithAllAttributesAndMaxDepth:(nullable NSNumber *)maxDepth;
54
54
 
55
55
  /**
56
56
  Gets the most recent snapshot of the current element with given attributes resolved.
@@ -67,8 +67,8 @@ NS_ASSUME_NONNULL_BEGIN
67
67
  attributes resolved if there was a failure while resolving additional attributes
68
68
  @throws FBStaleElementException if the element is not present in DOM and thus no snapshot could be made
69
69
  */
70
- - (nullable XCElementSnapshot *)fb_snapshotWithAttributes:(nullable NSArray<NSString *> *)attributeNames
71
- maxDepth:(nullable NSNumber *)maxDepth;
70
+ - (nullable id<FBXCElementSnapshot>)fb_snapshotWithAttributes:(nullable NSArray<NSString *> *)attributeNames
71
+ maxDepth:(nullable NSNumber *)maxDepth;
72
72
 
73
73
  /**
74
74
  Filters elements by matching them to snapshots from the corresponding array
@@ -80,7 +80,7 @@ NS_ASSUME_NONNULL_BEGIN
80
80
 
81
81
  @return Array of filtered elements, which have matches in snapshots array
82
82
  */
83
- - (NSArray<XCUIElement *> *)fb_filterDescendantsWithSnapshots:(NSArray<XCElementSnapshot *> *)snapshots
83
+ - (NSArray<XCUIElement *> *)fb_filterDescendantsWithSnapshots:(NSArray<id<FBXCElementSnapshot>> *)snapshots
84
84
  selfUID:(nullable NSString *)selfUID
85
85
  onlyChildren:(BOOL)onlyChildren;
86
86
 
@@ -22,6 +22,8 @@
22
22
  #import "FBScreenshot.h"
23
23
  #import "FBXCAXClientProxy.h"
24
24
  #import "FBXCodeCompatibility.h"
25
+ #import "FBXCElementSnapshot.h"
26
+ #import "FBXCElementSnapshotWrapper+Helpers.h"
25
27
  #import "XCUIApplication.h"
26
28
  #import "XCUIApplication+FBQuiescence.h"
27
29
  #import "XCUIApplicationImpl.h"
@@ -41,7 +43,7 @@
41
43
 
42
44
  @implementation XCUIElement (FBUtilities)
43
45
 
44
- - (XCElementSnapshot *)fb_takeSnapshot
46
+ - (id<FBXCElementSnapshot>)fb_takeSnapshot
45
47
  {
46
48
  NSError *error = nil;
47
49
  self.fb_isResolvedFromCache = @(NO);
@@ -61,12 +63,12 @@
61
63
  return self.lastSnapshot;
62
64
  }
63
65
 
64
- - (XCElementSnapshot *)fb_cachedSnapshot
66
+ - (id<FBXCElementSnapshot>)fb_cachedSnapshot
65
67
  {
66
68
  return [self.query fb_cachedSnapshot];
67
69
  }
68
70
 
69
- - (nullable XCElementSnapshot *)fb_snapshotWithAllAttributesAndMaxDepth:(NSNumber *)maxDepth
71
+ - (nullable id<FBXCElementSnapshot>)fb_snapshotWithAllAttributesAndMaxDepth:(NSNumber *)maxDepth
70
72
  {
71
73
  NSMutableArray *allNames = [NSMutableArray arrayWithArray:FBStandardAttributeNames()];
72
74
  [allNames addObjectsFromArray:FBCustomAttributeNames()];
@@ -74,11 +76,11 @@
74
76
  maxDepth:maxDepth];
75
77
  }
76
78
 
77
- - (nullable XCElementSnapshot *)fb_snapshotWithAttributes:(NSArray<NSString *> *)attributeNames
78
- maxDepth:(NSNumber *)maxDepth
79
+ - (nullable id<FBXCElementSnapshot>)fb_snapshotWithAttributes:(NSArray<NSString *> *)attributeNames
80
+ maxDepth:(NSNumber *)maxDepth
79
81
  {
80
82
  NSSet<NSString *> *standardAttributes = [NSSet setWithArray:FBStandardAttributeNames()];
81
- XCElementSnapshot *snapshot = self.fb_takeSnapshot;
83
+ id<FBXCElementSnapshot> snapshot = self.fb_takeSnapshot;
82
84
  NSTimeInterval axTimeout = FBConfiguration.customSnapshotTimeout;
83
85
  if (nil == attributeNames
84
86
  || [[NSSet setWithArray:attributeNames] isSubsetOfSet:standardAttributes]
@@ -87,7 +89,7 @@
87
89
  return snapshot;
88
90
  }
89
91
 
90
- XCAccessibilityElement *axElement = snapshot.accessibilityElement;
92
+ id<FBXCAccessibilityElement> axElement = snapshot.accessibilityElement;
91
93
  if (nil == axElement) {
92
94
  return nil;
93
95
  }
@@ -101,16 +103,17 @@
101
103
  }
102
104
 
103
105
  NSError *error;
104
- XCElementSnapshot *snapshotWithAttributes = [FBXCAXClientProxy.sharedClient snapshotForElement:axElement
105
- attributes:attributeNames
106
- maxDepth:maxDepth
107
- error:&error];
106
+ id<FBXCElementSnapshot> snapshotWithAttributes = [FBXCAXClientProxy.sharedClient snapshotForElement:axElement
107
+ attributes:attributeNames
108
+ maxDepth:maxDepth
109
+ error:&error];
108
110
  if (nil == snapshotWithAttributes) {
111
+ NSString *description = [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_description;
109
112
  [FBLogger logFmt:@"Cannot take a snapshot with attribute(s) %@ of '%@' after %.2f seconds",
110
- attributeNames, snapshot.fb_description, axTimeout];
113
+ attributeNames, description, axTimeout];
111
114
  [FBLogger logFmt:@"This timeout could be customized via '%@' setting", FB_SETTING_CUSTOM_SNAPSHOT_TIMEOUT];
112
115
  [FBLogger logFmt:@"Internal error: %@", error.localizedDescription];
113
- [FBLogger logFmt:@"Falling back to the default snapshotting mechanism for the element '%@' (some attribute values, like visibility or accessibility might not be precise though)", snapshot.fb_description];
116
+ [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];
114
117
  snapshotWithAttributes = self.lastSnapshot;
115
118
  } else {
116
119
  self.lastSnapshot = snapshotWithAttributes;
@@ -122,19 +125,22 @@
122
125
  return snapshotWithAttributes;
123
126
  }
124
127
 
125
- - (NSArray<XCUIElement *> *)fb_filterDescendantsWithSnapshots:(NSArray<XCElementSnapshot *> *)snapshots
128
+ - (NSArray<XCUIElement *> *)fb_filterDescendantsWithSnapshots:(NSArray<id<FBXCElementSnapshot>> *)snapshots
126
129
  selfUID:(NSString *)selfUID
127
130
  onlyChildren:(BOOL)onlyChildren
128
131
  {
129
132
  if (0 == snapshots.count) {
130
133
  return @[];
131
134
  }
132
- NSArray<NSString *> *sortedIds = [snapshots valueForKey:FBStringify(XCUIElement, wdUID)];
135
+ NSMutableArray<NSString *> *sortedIds = [NSMutableArray new];
136
+ for (id<FBXCElementSnapshot> snapshot in snapshots) {
137
+ [sortedIds addObject:(NSString *)[FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_uid];
138
+ }
133
139
  NSMutableArray<XCUIElement *> *matchedElements = [NSMutableArray array];
134
140
  NSString *uid = selfUID;
135
141
  if (nil == uid) {
136
142
  uid = self.fb_isResolvedFromCache.boolValue
137
- ? self.lastSnapshot.fb_uid
143
+ ? [FBXCElementSnapshotWrapper ensureWrapped:self.lastSnapshot].fb_uid
138
144
  : self.fb_uid;
139
145
  }
140
146
  if ([sortedIds containsObject:uid]) {
@@ -151,7 +157,10 @@
151
157
  XCUIElementQuery *query = onlyChildren
152
158
  ? [self.fb_query childrenMatchingType:type]
153
159
  : [self.fb_query descendantsMatchingType:type];
154
- query = [query matchingPredicate:[NSPredicate predicateWithFormat:@"%K IN %@", FBStringify(XCUIElement, wdUID), sortedIds]];
160
+ NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id<FBXCElementSnapshot> snapshot, NSDictionary *bindings) {
161
+ return [sortedIds containsObject:(NSString *)[FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_uid];
162
+ }];
163
+ query = [query matchingPredicate:predicate];
155
164
  if (1 == snapshots.count) {
156
165
  XCUIElement *result = query.fb_firstMatch;
157
166
  result.fb_isResolvedNatively = @NO;
@@ -206,7 +215,7 @@
206
215
 
207
216
  - (NSData *)fb_screenshotWithError:(NSError **)error
208
217
  {
209
- XCElementSnapshot *selfSnapshot = self.fb_isResolvedFromCache.boolValue
218
+ id<FBXCElementSnapshot> selfSnapshot = self.fb_isResolvedFromCache.boolValue
210
219
  ? self.lastSnapshot
211
220
  : self.fb_takeSnapshot;
212
221
  if (CGRectIsEmpty(selfSnapshot.frame)) {
@@ -221,8 +230,8 @@
221
230
  UIInterfaceOrientation orientation = self.application.interfaceOrientation;
222
231
  if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
223
232
  // Workaround XCTest bug when element frame is returned as in portrait mode even if the screenshot is rotated
224
- NSArray<XCElementSnapshot *> *ancestors = selfSnapshot.fb_ancestors;
225
- XCElementSnapshot *parentWindow = nil;
233
+ NSArray<id<FBXCElementSnapshot>> *ancestors = [FBXCElementSnapshotWrapper ensureWrapped:selfSnapshot].fb_ancestors;
234
+ id<FBXCElementSnapshot> parentWindow = nil;
226
235
  if (1 == ancestors.count) {
227
236
  parentWindow = selfSnapshot;
228
237
  } else if (ancestors.count > 1) {
@@ -8,8 +8,8 @@
8
8
  */
9
9
 
10
10
  #import <WebDriverAgentLib/FBElement.h>
11
- #import <WebDriverAgentLib/XCElementSnapshot.h>
12
11
  #import <WebDriverAgentLib/XCUIElement.h>
12
+ #import "FBXCElementSnapshotWrapper.h"
13
13
 
14
14
  NS_ASSUME_NONNULL_BEGIN
15
15
 
@@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN
18
18
  @end
19
19
 
20
20
 
21
- @interface XCElementSnapshot (WebDriverAttributes) <FBElement>
21
+ @interface FBXCElementSnapshotWrapper (WebDriverAttributes) <FBElement>
22
22
 
23
23
  @end
24
24
 
@@ -14,6 +14,7 @@
14
14
  #import "FBElementTypeTransformer.h"
15
15
  #import "FBLogger.h"
16
16
  #import "FBMacros.h"
17
+ #import "FBXCElementSnapshotWrapper.h"
17
18
  #import "XCUIElement+FBAccessibility.h"
18
19
  #import "XCUIElement+FBIsVisible.h"
19
20
  #import "XCUIElement+FBUID.h"
@@ -26,7 +27,7 @@
26
27
 
27
28
  @implementation XCUIElement (WebDriverAttributesForwarding)
28
29
 
29
- - (XCElementSnapshot *)fb_snapshotForAttributeName:(NSString *)name
30
+ - (id<FBXCElementSnapshot>)fb_snapshotForAttributeName:(NSString *)name
30
31
  {
31
32
  // These attrbiutes are special, because we can only retrieve them from
32
33
  // the snapshot if we explicitly ask XCTest to include them into the query while taking it.
@@ -51,8 +52,8 @@
51
52
  - (id)fb_valueForWDAttributeName:(NSString *)name
52
53
  {
53
54
  NSString *wdAttributeName = [FBElementUtils wdAttributeNameForAttributeName:name];
54
- XCElementSnapshot *snapshot = [self fb_snapshotForAttributeName:wdAttributeName];
55
- return [snapshot fb_valueForWDAttributeName:name];
55
+ id<FBXCElementSnapshot> snapshot = [self fb_snapshotForAttributeName:wdAttributeName];
56
+ return [[FBXCElementSnapshotWrapper ensureWrapped:snapshot] fb_valueForWDAttributeName:name];
56
57
  }
57
58
 
58
59
  - (id)forwardingTargetForSelector:(SEL)aSelector
@@ -61,13 +62,13 @@
61
62
  SEL webDriverAttributesSelector = descr.name;
62
63
  return nil == webDriverAttributesSelector
63
64
  ? nil
64
- : [self fb_snapshotForAttributeName:NSStringFromSelector(webDriverAttributesSelector)];
65
+ : [FBXCElementSnapshotWrapper ensureWrapped:[self fb_snapshotForAttributeName:NSStringFromSelector(webDriverAttributesSelector)]];
65
66
  }
66
67
 
67
68
  @end
68
69
 
69
70
 
70
- @implementation XCElementSnapshot (WebDriverAttributes)
71
+ @implementation FBXCElementSnapshotWrapper (WebDriverAttributes)
71
72
 
72
73
  - (id)fb_valueForWDAttributeName:(NSString *)name
73
74
  {
@@ -161,8 +162,8 @@
161
162
  // Text fields: actual accessible element isn't text field itself, but nested element
162
163
  if (elementType == XCUIElementTypeCell) {
163
164
  if (!self.fb_isAccessibilityElement) {
164
- XCElementSnapshot *containerView = [[self children] firstObject];
165
- if (!containerView.fb_isAccessibilityElement) {
165
+ id<FBXCElementSnapshot> containerView = [[self children] firstObject];
166
+ if (![FBXCElementSnapshotWrapper ensureWrapped:containerView].fb_isAccessibilityElement) {
166
167
  return NO;
167
168
  }
168
169
  }
@@ -171,12 +172,13 @@
171
172
  return NO;
172
173
  }
173
174
  }
174
- XCElementSnapshot *parentSnapshot = self.parent;
175
+ id<FBXCElementSnapshot> parentSnapshot = self.parent;
175
176
  while (parentSnapshot) {
176
177
  // In the scenario when table provides Search results controller, table could be marked as accessible element, even though it isn't
177
178
  // As it is highly unlikely that table view should ever be an accessibility element itself,
178
179
  // for now we work around that by skipping Table View in container checks
179
- if (parentSnapshot.fb_isAccessibilityElement && parentSnapshot.elementType != XCUIElementTypeTable) {
180
+ if ([FBXCElementSnapshotWrapper ensureWrapped:parentSnapshot].fb_isAccessibilityElement
181
+ && parentSnapshot.elementType != XCUIElementTypeTable) {
180
182
  return NO;
181
183
  }
182
184
  parentSnapshot = parentSnapshot.parent;
@@ -186,9 +188,10 @@
186
188
 
187
189
  - (BOOL)isWDAccessibilityContainer
188
190
  {
189
- NSArray<XCElementSnapshot *> *children = self.children;
190
- for (XCElementSnapshot *child in children) {
191
- if (child.isWDAccessibilityContainer || child.fb_isAccessibilityElement) {
191
+ NSArray<id<FBXCElementSnapshot>> *children = self.children;
192
+ for (id<FBXCElementSnapshot> child in children) {
193
+ FBXCElementSnapshotWrapper *wrappedChild = [FBXCElementSnapshotWrapper ensureWrapped:child];
194
+ if (wrappedChild.isWDAccessibilityContainer || wrappedChild.fb_isAccessibilityElement) {
192
195
  return YES;
193
196
  }
194
197
  }
@@ -209,7 +212,7 @@
209
212
  {
210
213
  if (nil != self.parent) {
211
214
  for (NSUInteger index = 0; index < self.parent.children.count; ++index) {
212
- if ([self.parent.children objectAtIndex:index] == self) {
215
+ if ([self.parent.children objectAtIndex:index] == self.snapshot) {
213
216
  return index;
214
217
  }
215
218
  }
@@ -8,8 +8,7 @@
8
8
  */
9
9
 
10
10
  #import <XCTest/XCTest.h>
11
-
12
- @class XCElementSnapshot;
11
+ #import "FBXCElementSnapshot.h"
13
12
 
14
13
  NS_ASSUME_NONNULL_BEGIN
15
14
 
@@ -23,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
23
22
 
24
23
  @return Either the cached snapshot or nil
25
24
  */
26
- - (nullable XCElementSnapshot *)fb_cachedSnapshot;
25
+ - (nullable id<FBXCElementSnapshot>)fb_cachedSnapshot;
27
26
 
28
27
  @end
29
28
 
@@ -11,13 +11,13 @@
11
11
 
12
12
  #import "FBXCodeCompatibility.h"
13
13
  #import "XCUIElementQuery.h"
14
-
14
+ #import "FBXCElementSnapshot.h"
15
15
 
16
16
  @implementation XCUIElementQuery (FBHelpers)
17
17
 
18
- - (nullable XCElementSnapshot *)fb_cachedSnapshot
18
+ - (nullable id<FBXCElementSnapshot>)fb_cachedSnapshot
19
19
  {
20
- XCElementSnapshot *rootElementSnapshot = self.rootElementSnapshot;
20
+ id<FBXCElementSnapshot> rootElementSnapshot = self.rootElementSnapshot;
21
21
  if (nil == rootElementSnapshot) {
22
22
  return nil;
23
23
  }
@@ -12,7 +12,6 @@
12
12
  #import "FBApplication.h"
13
13
  #import "FBConfiguration.h"
14
14
  #import "FBKeyboard.h"
15
- #import "FBPredicate.h"
16
15
  #import "FBRoute.h"
17
16
  #import "FBRouteRequest.h"
18
17
  #import "FBRunLoopSpinner.h"
@@ -84,6 +83,7 @@
84
83
  [[FBRoute POST:@"/wda/element/:uuid/tapWithNumberOfTaps"] respondWithTarget:self action:@selector(handleTapWithNumberOfTaps:)],
85
84
  [[FBRoute POST:@"/wda/element/:uuid/touchAndHold"] respondWithTarget:self action:@selector(handleTouchAndHold:)],
86
85
  [[FBRoute POST:@"/wda/element/:uuid/scroll"] respondWithTarget:self action:@selector(handleScroll:)],
86
+ [[FBRoute POST:@"/wda/element/:uuid/scrollTo"] respondWithTarget:self action:@selector(handleScrollTo:)],
87
87
  [[FBRoute POST:@"/wda/element/:uuid/dragfromtoforduration"] respondWithTarget:self action:@selector(handleDrag:)],
88
88
  [[FBRoute POST:@"/wda/element/:uuid/forceTouch"] respondWithTarget:self action:@selector(handleForceTouch:)],
89
89
  [[FBRoute POST:@"/wda/dragfromtoforduration"] respondWithTarget:self action:@selector(handleDragCoordinate:)],
@@ -104,7 +104,7 @@
104
104
  {
105
105
  FBElementCache *elementCache = request.session.elementCache;
106
106
  XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
107
- BOOL isEnabled = element.lastSnapshot.isWDEnabled;
107
+ BOOL isEnabled = [FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].isWDEnabled;
108
108
  return FBResponseWithObject(isEnabled ? @YES : @NO);
109
109
  }
110
110
 
@@ -112,7 +112,7 @@
112
112
  {
113
113
  FBElementCache *elementCache = request.session.elementCache;
114
114
  XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
115
- return FBResponseWithObject(element.lastSnapshot.wdRect);
115
+ return FBResponseWithObject([FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].wdRect);
116
116
  }
117
117
 
118
118
  + (id<FBResponsePayload>)handleGetAttribute:(FBRouteRequest *)request
@@ -142,7 +142,8 @@
142
142
  {
143
143
  FBElementCache *elementCache = request.session.elementCache;
144
144
  XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
145
- id text = FBFirstNonEmptyValue(element.lastSnapshot.wdValue, element.lastSnapshot.wdLabel);
145
+ FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot];
146
+ id text = FBFirstNonEmptyValue(wrappedSnapshot.wdValue, wrappedSnapshot.wdLabel);
146
147
  return FBResponseWithObject(text ?: @"");
147
148
  }
148
149
 
@@ -152,7 +153,7 @@
152
153
  XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]
153
154
  resolveForAdditionalAttributes:@[FB_XCAXAIsVisibleAttributeName]
154
155
  andMaxDepth:@1];
155
- return FBResponseWithObject(@(element.lastSnapshot.isWDVisible));
156
+ return FBResponseWithObject(@([FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].isWDVisible));
156
157
  }
157
158
 
158
159
  + (id<FBResponsePayload>)handleGetAccessible:(FBRouteRequest *)request
@@ -161,7 +162,7 @@
161
162
  XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]
162
163
  resolveForAdditionalAttributes:@[FB_XCAXAIsElementAttributeName]
163
164
  andMaxDepth:@1];
164
- return FBResponseWithObject(@(element.lastSnapshot.isWDAccessible));
165
+ return FBResponseWithObject(@([FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].isWDAccessible));
165
166
  }
166
167
 
167
168
  + (id<FBResponsePayload>)handleGetIsAccessibilityContainer:(FBRouteRequest *)request
@@ -170,21 +171,21 @@
170
171
  XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]
171
172
  resolveForAdditionalAttributes:@[FB_XCAXAIsElementAttributeName]
172
173
  andMaxDepth:nil];
173
- return FBResponseWithObject(@(element.lastSnapshot.isWDAccessibilityContainer));
174
+ return FBResponseWithObject(@([FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].isWDAccessibilityContainer));
174
175
  }
175
176
 
176
177
  + (id<FBResponsePayload>)handleGetName:(FBRouteRequest *)request
177
178
  {
178
179
  FBElementCache *elementCache = request.session.elementCache;
179
180
  XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
180
- return FBResponseWithObject(element.lastSnapshot.wdType);
181
+ return FBResponseWithObject([FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].wdType);
181
182
  }
182
183
 
183
184
  + (id<FBResponsePayload>)handleGetSelected:(FBRouteRequest *)request
184
185
  {
185
186
  FBElementCache *elementCache = request.session.elementCache;
186
187
  XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
187
- return FBResponseWithObject(@(element.lastSnapshot.wdSelected));
188
+ return FBResponseWithObject(@([FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].wdSelected));
188
189
  }
189
190
 
190
191
  + (id<FBResponsePayload>)handleSetValue:(FBRouteRequest *)request
@@ -198,7 +199,7 @@
198
199
  NSString *textToType = [value isKindOfClass:NSArray.class]
199
200
  ? [value componentsJoinedByString:@""]
200
201
  : value;
201
- XCUIElementType elementType = element.lastSnapshot.elementType;
202
+ XCUIElementType elementType = [(id<FBXCElementSnapshot>)element.lastSnapshot elementType];
202
203
  #if !TARGET_OS_TV
203
204
  if (elementType == XCUIElementTypePickerWheel) {
204
205
  [element adjustToPickerWheelValue:textToType];
@@ -369,7 +370,8 @@
369
370
 
370
371
  NSString *const predicateString = request.arguments[@"predicateString"];
371
372
  if (predicateString) {
372
- NSPredicate *formattedPredicate = [NSPredicate fb_formatSearchPredicate:[FBPredicate predicateWithFormat:predicateString]];
373
+ NSPredicate *formattedPredicate = [NSPredicate fb_snapshotBlockPredicateWithPredicate:[NSPredicate
374
+ predicateWithFormat:predicateString]];
373
375
  XCUIElement *childElement = [[[[element.fb_query descendantsMatchingType:XCUIElementTypeAny] matchingPredicate:formattedPredicate] allElementsBoundByAccessibilityElement] lastObject];
374
376
  if (!childElement) {
375
377
  return FBResponseWithStatus([FBCommandStatus noSuchElementErrorWithMessage:[NSString stringWithFormat:@"'%@' predicate didn't match any elements", predicateString] traceback:[NSString stringWithFormat:@"%@", NSThread.callStackSymbols]]);
@@ -383,6 +385,17 @@
383
385
  return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:@"Unsupported scroll type" traceback:nil]);
384
386
  }
385
387
 
388
+ + (id<FBResponsePayload>)handleScrollTo:(FBRouteRequest *)request
389
+ {
390
+ FBElementCache *elementCache = request.session.elementCache;
391
+ XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
392
+ NSError *error;
393
+ return [element fb_nativeScrollToVisibleWithError:&error]
394
+ ? FBResponseWithOK()
395
+ : FBResponseWithStatus([FBCommandStatus invalidElementStateErrorWithMessage:error.description
396
+ traceback:nil]);
397
+ }
398
+
386
399
  + (id<FBResponsePayload>)handleDragCoordinate:(FBRouteRequest *)request
387
400
  {
388
401
  FBSession *session = request.session;
@@ -402,7 +415,7 @@
402
415
  FBSession *session = request.session;
403
416
  FBElementCache *elementCache = session.elementCache;
404
417
  XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
405
- CGRect frame = element.lastSnapshot.frame;
418
+ CGRect frame = [(id<FBXCElementSnapshot>)element.lastSnapshot frame];
406
419
  CGPoint startPoint = CGPointMake((CGFloat)(frame.origin.x + [request.arguments[@"fromX"] doubleValue]), (CGFloat)(frame.origin.y + [request.arguments[@"fromY"] doubleValue]));
407
420
  CGPoint endPoint = CGPointMake((CGFloat)(frame.origin.x + [request.arguments[@"toX"] doubleValue]), (CGFloat)(frame.origin.y + [request.arguments[@"toY"] doubleValue]));
408
421
  NSTimeInterval duration = [request.arguments[@"duration"] doubleValue];
@@ -537,7 +550,8 @@
537
550
  NSError *error;
538
551
  NSData *screenshotData = [element fb_screenshotWithError:&error];
539
552
  if (nil == screenshotData) {
540
- return FBResponseWithStatus([FBCommandStatus unableToCaptureScreenErrorWithMessage:error.description traceback:nil]);
553
+ return FBResponseWithStatus([FBCommandStatus unableToCaptureScreenErrorWithMessage:error.description
554
+ traceback:nil]);
541
555
  }
542
556
  NSString *screenshot = [screenshotData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
543
557
  return FBResponseWithObject(screenshot);
@@ -551,7 +565,7 @@ static const CGFloat DEFAULT_OFFSET = (CGFloat)0.2;
551
565
  {
552
566
  FBElementCache *elementCache = request.session.elementCache;
553
567
  XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]];
554
- if (element.lastSnapshot.elementType != XCUIElementTypePickerWheel) {
568
+ if ([element.lastSnapshot elementType] != XCUIElementTypePickerWheel) {
555
569
  return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:[NSString stringWithFormat:@"The element is expected to be a valid Picker Wheel control. '%@' was given instead", element.wdType] traceback:[NSString stringWithFormat:@"%@", NSThread.callStackSymbols]]);
556
570
  }
557
571
  NSString* order = [request.arguments[@"order"] lowercaseString];
@@ -621,7 +635,7 @@ static const CGFloat DEFAULT_OFFSET = (CGFloat)0.2;
621
635
  XCUIElement *window = application.windows.fb_firstMatch;
622
636
  if (window) {
623
637
  element = window;
624
- XCElementSnapshot *snapshot = element.fb_cachedSnapshot ?: element.fb_takeSnapshot;
638
+ id<FBXCElementSnapshot> snapshot = element.fb_cachedSnapshot ?: element.fb_takeSnapshot;
625
639
  point.x -= snapshot.frame.origin.x;
626
640
  point.y -= snapshot.frame.origin.y;
627
641
  }