appium-webdriveragent 16.1.4 → 16.1.5

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 CHANGED
@@ -1,3 +1,9 @@
1
+ ## [16.1.5](https://github.com/appium/WebDriverAgent/compare/v16.1.4...v16.1.5) (2026-08-05)
2
+
3
+ ### Bug Fixes
4
+
5
+ * Update various consumers to properly use cached snapshots ([#1198](https://github.com/appium/WebDriverAgent/issues/1198)) ([bed67cc](https://github.com/appium/WebDriverAgent/commit/bed67ccf6a1375f1d1164d7a2ef18d10ac44f632))
6
+
1
7
  ## [16.1.4](https://github.com/appium/WebDriverAgent/compare/v16.1.3...v16.1.4) (2026-08-04)
2
8
 
3
9
  ### Bug Fixes
@@ -135,7 +135,7 @@ static NSString *const FB_LIMITED_ACCESS_PROMPT_BUNDLE_ID = @"com.apple.Contacts
135
135
 
136
136
  // In case of iPad we want to check if sheet isn't contained by popover.
137
137
  // In that case we ignore it.
138
- id<FBXCElementSnapshot> sheetSnapshot = sheet.lastSnapshot ?: sheet.fb_cachedSnapshot ?: [sheet fb_customSnapshot];
138
+ id<FBXCElementSnapshot> sheetSnapshot = sheet.fb_cachedSnapshot ?: [sheet fb_customSnapshot];
139
139
  BOOL isInsidePopover = NO;
140
140
  id<FBXCElementSnapshot> ancestor = sheetSnapshot.parent;
141
141
  while (nil != ancestor) {
@@ -154,7 +154,7 @@ static NSString *const FB_LIMITED_ACCESS_PROMPT_BUNDLE_ID = @"com.apple.Contacts
154
154
  }
155
155
 
156
156
  for (XCUIElement *scrollView in scrollViews) {
157
- id<FBXCElementSnapshot> scrollViewSnapshot = scrollView.lastSnapshot ?: scrollView.fb_cachedSnapshot ?: [scrollView fb_customSnapshot];
157
+ id<FBXCElementSnapshot> scrollViewSnapshot = scrollView.fb_cachedSnapshot ?: [scrollView fb_customSnapshot];
158
158
  id<FBXCElementSnapshot> app = [[FBXCElementSnapshotWrapper ensureWrapped:scrollViewSnapshot] fb_parentMatchingType:XCUIElementTypeApplication];
159
159
  if (nil == app || ![app.label isEqualToString:FB_SAFARI_APP_NAME]) {
160
160
  continue;
@@ -137,7 +137,7 @@
137
137
  // Reuse an already-taken snapshot of `self` if one is available (e.g. the
138
138
  // caller just resolved/inspected this same element) instead of always
139
139
  // paying for a fresh one.
140
- NSArray<id<FBXCElementSnapshot>> *currentRoots = @[self.lastSnapshot ?: [self fb_customSnapshot]];
140
+ NSArray<id<FBXCElementSnapshot>> *currentRoots = @[self.lastSnapshot ?: self.fb_cachedSnapshot ?: [self fb_customSnapshot]];
141
141
  FBClassChainItem *chainItem = lookupChain.firstObject;
142
142
  NSArray<id<FBXCElementSnapshot>> *candidates = [self.class fb_snapshotsMatchingItem:chainItem inRoots:currentRoots];
143
143
  [lookupChain removeObjectAtIndex:0];
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  #import <XCTest/XCTest.h>
10
+ #import <WebDriverAgentLib/FBXCElementSnapshot.h>
10
11
 
11
12
  NS_ASSUME_NONNULL_BEGIN
12
13
 
@@ -50,6 +51,25 @@ BOOL FBTypeText(NSString *text, NSUInteger typingSpeed, NSError **error);
50
51
  frequency:(NSUInteger)frequency
51
52
  error:(NSError **)error;
52
53
 
54
+ /**
55
+ Types a text into element, reusing a snapshot the caller already holds
56
+ instead of fetching a new one. Only pass a snapshot that is known to
57
+ reflect the element's current state (e.g. one taken moments earlier in
58
+ the same operation) - a stale snapshot here will not be detected as such.
59
+
60
+ @param text text that should be typed
61
+ @param shouldClear Whether to clear the input field before start typing
62
+ @param frequency Frequency of typing (letters per sec)
63
+ @param snapshot A recent snapshot of the receiver
64
+ @param error If there is an error, upon return contains an NSError object that describes the problem.
65
+ @return YES if the operation succeeds, otherwise NO.
66
+ */
67
+ - (BOOL)fb_typeText:(NSString *)text
68
+ shouldClear:(BOOL)shouldClear
69
+ frequency:(NSUInteger)frequency
70
+ snapshot:(id<FBXCElementSnapshot>)snapshot
71
+ error:(NSError **)error;
72
+
53
73
  /**
54
74
  Clears text on element.
55
75
  It will try to activate keyboard on element, if element has no keyboard focus.
@@ -59,6 +79,19 @@ BOOL FBTypeText(NSString *text, NSUInteger typingSpeed, NSError **error);
59
79
  */
60
80
  - (BOOL)fb_clearTextWithError:(NSError **)error;
61
81
 
82
+ /**
83
+ Clears text on element, reusing a snapshot the caller already holds
84
+ instead of fetching a new one. Only pass a snapshot that is known to
85
+ reflect the element's current state (e.g. one taken moments earlier in
86
+ the same operation) - a stale snapshot here will not be detected as such.
87
+
88
+ @param snapshot A recent snapshot of the receiver
89
+ @param error If there is an error, upon return contains an NSError object that describes the problem.
90
+ @return YES if the operation succeeds, otherwise NO.
91
+ */
92
+ - (BOOL)fb_clearTextWithSnapshot:(id<FBXCElementSnapshot>)snapshot
93
+ error:(NSError **)error;
94
+
62
95
  @end
63
96
 
64
97
  NS_ASSUME_NONNULL_END
@@ -109,7 +109,22 @@ BOOL FBTypeText(NSString *text, NSUInteger typingSpeed, NSError **error)
109
109
  frequency:(NSUInteger)frequency
110
110
  error:(NSError **)error
111
111
  {
112
+ // No snapshot was handed to us, so there is nothing to safely reuse -
113
+ // always fetch a fresh one.
112
114
  id<FBXCElementSnapshot> snapshot = [self fb_standardSnapshot];
115
+ return [self fb_typeText:text
116
+ shouldClear:shouldClear
117
+ frequency:frequency
118
+ snapshot:snapshot
119
+ error:error];
120
+ }
121
+
122
+ - (BOOL)fb_typeText:(NSString *)text
123
+ shouldClear:(BOOL)shouldClear
124
+ frequency:(NSUInteger)frequency
125
+ snapshot:(id<FBXCElementSnapshot>)snapshot
126
+ error:(NSError **)error
127
+ {
113
128
  FBXCElementSnapshotWrapper *wrapped = [FBXCElementSnapshotWrapper ensureWrapped:snapshot];
114
129
  [self fb_prepareForTextInputWithSnapshot:wrapped];
115
130
  if (shouldClear && ![self fb_clearTextWithSnapshot:wrapped shouldPrepareForInput:NO error:error]) {
@@ -120,7 +135,15 @@ BOOL FBTypeText(NSString *text, NSUInteger typingSpeed, NSError **error)
120
135
 
121
136
  - (BOOL)fb_clearTextWithError:(NSError **)error
122
137
  {
138
+ // No snapshot was handed to us, so there is nothing to safely reuse -
139
+ // always fetch a fresh one.
123
140
  id<FBXCElementSnapshot> snapshot = [self fb_standardSnapshot];
141
+ return [self fb_clearTextWithSnapshot:snapshot error:error];
142
+ }
143
+
144
+ - (BOOL)fb_clearTextWithSnapshot:(id<FBXCElementSnapshot>)snapshot
145
+ error:(NSError **)error
146
+ {
124
147
  return [self fb_clearTextWithSnapshot:[FBXCElementSnapshotWrapper ensureWrapped:snapshot]
125
148
  shouldPrepareForInput:YES
126
149
  error:error];
@@ -221,9 +221,14 @@
221
221
  }
222
222
  NSUInteger frequency = (NSUInteger)[request.arguments[@"frequency"] longLongValue] ?: [FBConfiguration maxTypingFrequency];
223
223
  NSError *error = nil;
224
+ // checkStaleness:YES above already took a fresh, verified-live snapshot of
225
+ // `element` and cached it as `lastSnapshot` - reuse it instead of paying
226
+ // for another round trip.
227
+ id<FBXCElementSnapshot> snapshot = element.lastSnapshot ?: element.fb_cachedSnapshot ?: [element fb_standardSnapshot];
224
228
  if (![element fb_typeText:textToType
225
229
  shouldClear:NO
226
230
  frequency:frequency
231
+ snapshot:snapshot
227
232
  error:&error]) {
228
233
  return FBResponseWithStatus([FBCommandStatus invalidElementStateErrorWithMessage:error.description traceback:nil]);
229
234
  }
@@ -74,7 +74,7 @@
74
74
  XCUIElement *alertElement = self.alertElement;
75
75
  self.cachedAlertSnapshot = nil == alertElement
76
76
  ? nil
77
- : (alertElement.lastSnapshot ?: alertElement.fb_cachedSnapshot ?: [alertElement fb_customSnapshot]);
77
+ : (alertElement.fb_cachedSnapshot ?: [alertElement fb_customSnapshot]);
78
78
  self.hasCachedAlertSnapshot = YES;
79
79
  }
80
80
  return self.cachedAlertSnapshot;
@@ -194,7 +194,15 @@
194
194
  [self fb_raiseSetTextFailedExceptionWithReason:@"Failed to resolve the input field element"];
195
195
  }
196
196
  NSError *error;
197
- if (![dstField fb_typeText:text shouldClear:YES error:&error]) {
197
+ // dstField was just resolved via a live query in fb_elementForSnapshot:underElement:
198
+ // above, so its cached snapshot can be safely reconstructed in memory
199
+ // instead of paying for a fresh round trip.
200
+ id<FBXCElementSnapshot> snapshot = dstField.fb_cachedSnapshot ?: [dstField fb_standardSnapshot];
201
+ if (![dstField fb_typeText:text
202
+ shouldClear:YES
203
+ frequency:FBConfiguration.maxTypingFrequency
204
+ snapshot:snapshot
205
+ error:&error]) {
198
206
  [self fb_raiseSetTextFailedExceptionWithReason:error.description];
199
207
  }
200
208
  }
@@ -15,11 +15,11 @@
15
15
  <key>CFBundlePackageType</key>
16
16
  <string>FMWK</string>
17
17
  <key>CFBundleShortVersionString</key>
18
- <string>16.1.4</string>
18
+ <string>16.1.5</string>
19
19
  <key>CFBundleSignature</key>
20
20
  <string>????</string>
21
21
  <key>CFBundleVersion</key>
22
- <string>16.1.4</string>
22
+ <string>16.1.5</string>
23
23
  <key>NSPrincipalClass</key>
24
24
  <string/>
25
25
  </dict>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-webdriveragent",
3
- "version": "16.1.4",
3
+ "version": "16.1.5",
4
4
  "description": "Package bundling WebDriverAgent",
5
5
  "keywords": [
6
6
  "Appium",