appium-webdriveragent 9.0.4 → 9.0.6

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,15 @@
1
+ ## [9.0.6](https://github.com/appium/WebDriverAgent/compare/v9.0.5...v9.0.6) (2025-02-28)
2
+
3
+ ### Bug Fixes
4
+
5
+ * optimize LRU cache ([#985](https://github.com/appium/WebDriverAgent/issues/985)) ([46dc417](https://github.com/appium/WebDriverAgent/commit/46dc417da9f4a843838b414c0b154d6f478dbc0b))
6
+
7
+ ## [9.0.5](https://github.com/appium/WebDriverAgent/compare/v9.0.4...v9.0.5) (2025-02-26)
8
+
9
+ ### Bug Fixes
10
+
11
+ * add autorelease pool to drain temporary objects ([#983](https://github.com/appium/WebDriverAgent/issues/983)) ([f92f1cd](https://github.com/appium/WebDriverAgent/commit/f92f1cde0fe914086103a110844bbe3bc0e3c4a6))
12
+
1
13
  ## [9.0.4](https://github.com/appium/WebDriverAgent/compare/v9.0.3...v9.0.4) (2025-02-21)
2
14
 
3
15
  ### Bug Fixes
@@ -238,9 +238,11 @@ NSDictionary<NSString *, NSString *> *customExclusionAttributesMap(void) {
238
238
  if ([childElements count]) {
239
239
  info[@"children"] = [[NSMutableArray alloc] init];
240
240
  for (id<FBXCElementSnapshot> childSnapshot in childElements) {
241
- [info[@"children"] addObject:[self dictionaryForElement:childSnapshot
242
- recursive:YES
243
- excludedAttributes:excludedAttributes]];
241
+ @autoreleasepool {
242
+ [info[@"children"] addObject:[self dictionaryForElement:childSnapshot
243
+ recursive:YES
244
+ excludedAttributes:excludedAttributes]];
245
+ }
244
246
  }
245
247
  }
246
248
  return info;
@@ -262,9 +264,11 @@ NSDictionary<NSString *, NSString *> *customExclusionAttributesMap(void) {
262
264
  } else {
263
265
  NSMutableArray *children = [[NSMutableArray alloc] init];
264
266
  for (id<FBXCElementSnapshot> childSnapshot in snapshot.children) {
265
- NSDictionary *childInfo = [self accessibilityInfoForElement:childSnapshot];
266
- if ([childInfo count]) {
267
- [children addObject: childInfo];
267
+ @autoreleasepool {
268
+ NSDictionary *childInfo = [self accessibilityInfoForElement:childSnapshot];
269
+ if ([childInfo count]) {
270
+ [children addObject: childInfo];
271
+ }
268
272
  }
269
273
  }
270
274
  if ([children count]) {
@@ -420,31 +424,33 @@ NSDictionary<NSString *, NSString *> *customExclusionAttributesMap(void) {
420
424
  [invocation setSelector:selector];
421
425
  [invocation setArgument:&auditTypes atIndex:2];
422
426
  BOOL (^issueHandler)(id) = ^BOOL(id issue) {
423
- NSString *auditType = @"";
424
- NSDictionary *valuesToNamesMap = auditTypeValuesToNames();
425
- NSNumber *auditTypeValue = [issue valueForKey:@"auditType"];
426
- if (nil != auditTypeValue) {
427
- auditType = valuesToNamesMap[auditTypeValue] ?: [auditTypeValue stringValue];
428
- }
429
-
430
- id extractedElement = extractIssueProperty(issue, @"element");
431
-
432
- id<FBXCElementSnapshot> elementSnapshot = [extractedElement fb_cachedSnapshot] ?: [extractedElement fb_takeSnapshot:NO];
433
- NSDictionary *elementAttributes = elementSnapshot
427
+ @autoreleasepool {
428
+ NSString *auditType = @"";
429
+ NSDictionary *valuesToNamesMap = auditTypeValuesToNames();
430
+ NSNumber *auditTypeValue = [issue valueForKey:@"auditType"];
431
+ if (nil != auditTypeValue) {
432
+ auditType = valuesToNamesMap[auditTypeValue] ?: [auditTypeValue stringValue];
433
+ }
434
+
435
+ id extractedElement = extractIssueProperty(issue, @"element");
436
+
437
+ id<FBXCElementSnapshot> elementSnapshot = [extractedElement fb_cachedSnapshot] ?: [extractedElement fb_takeSnapshot:NO];
438
+ NSDictionary *elementAttributes = elementSnapshot
434
439
  ? [self.class dictionaryForElement:elementSnapshot
435
440
  recursive:NO
436
441
  excludedAttributes:customAttributesToExclude]
437
442
  : @{};
438
-
439
- [resultArray addObject:@{
440
- @"detailedDescription": extractIssueProperty(issue, @"detailedDescription") ?: @"",
441
- @"compactDescription": extractIssueProperty(issue, @"compactDescription") ?: @"",
442
- @"auditType": auditType,
443
- @"element": [extractedElement description] ?: @"",
444
- @"elementDescription": [extractedElement debugDescription] ?: @"",
445
- @"elementAttributes": elementAttributes ?: @{},
446
- }];
447
- return YES;
443
+
444
+ [resultArray addObject:@{
445
+ @"detailedDescription": extractIssueProperty(issue, @"detailedDescription") ?: @"",
446
+ @"compactDescription": extractIssueProperty(issue, @"compactDescription") ?: @"",
447
+ @"auditType": auditType,
448
+ @"element": [extractedElement description] ?: @"",
449
+ @"elementDescription": [extractedElement debugDescription] ?: @"",
450
+ @"elementAttributes": elementAttributes ?: @{},
451
+ }];
452
+ return YES;
453
+ }
448
454
  };
449
455
  [invocation setArgument:&issueHandler atIndex:3];
450
456
  [invocation setArgument:&error atIndex:4];
@@ -121,7 +121,9 @@
121
121
  {
122
122
  NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id<FBXCElementSnapshot> snapshot,
123
123
  NSDictionary<NSString *,id> * _Nullable bindings) {
124
- return [[FBXCElementSnapshotWrapper wdNameWithSnapshot:snapshot] isEqualToString:accessibilityId];
124
+ @autoreleasepool {
125
+ return [[FBXCElementSnapshotWrapper wdNameWithSnapshot:snapshot] isEqualToString:accessibilityId];
126
+ }
125
127
  }];
126
128
  return [self fb_descendantsMatchingPredicate:predicate
127
129
  shouldReturnAfterFirstMatch:shouldReturnAfterFirstMatch];
@@ -25,8 +25,10 @@ NSNumber* _Nullable fetchSnapshotVisibility(id<FBXCElementSnapshot> snapshot)
25
25
 
26
26
  - (BOOL)fb_isVisible
27
27
  {
28
- id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:NO];
29
- return [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_isVisible;
28
+ @autoreleasepool {
29
+ id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:NO];
30
+ return [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_isVisible;
31
+ }
30
32
  }
31
33
 
32
34
  @end
@@ -64,7 +66,9 @@ NSNumber* _Nullable fetchSnapshotVisibility(id<FBXCElementSnapshot> snapshot)
64
66
  NSMutableDictionary *updatedValue = [NSMutableDictionary dictionaryWithDictionary:self.additionalAttributes ?: @{}];
65
67
  [updatedValue setObject:attributeValue forKey:FB_XCAXAIsVisibleAttribute];
66
68
  self.snapshot.additionalAttributes = updatedValue.copy;
67
- return [attributeValue boolValue];
69
+ @autoreleasepool {
70
+ return [attributeValue boolValue];
71
+ }
68
72
  }
69
73
 
70
74
  NSLog(@"Cannot determine visiblity of %@ natively: %@. Defaulting to: %@",
@@ -38,11 +38,13 @@ static char XCUIELEMENT_IS_RESOLVED_NATIVELY_KEY;
38
38
  return self;
39
39
  }
40
40
  NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K = %@", FBStringify(FBXCElementSnapshotWrapper, fb_uid), uid];
41
- XCUIElementQuery *query = [self.application.fb_query descendantsMatchingType:XCUIElementTypeAny];
42
- XCUIElement *result = [query matchingPredicate:predicate].allElementsBoundByIndex.firstObject;
43
- if (nil != result) {
44
- result.fb_isResolvedNatively = @NO;
45
- return result;
41
+ @autoreleasepool {
42
+ XCUIElementQuery *query = [self.application.fb_query descendantsMatchingType:XCUIElementTypeAny];
43
+ XCUIElement *result = [query matchingPredicate:predicate].allElementsBoundByIndex.firstObject;
44
+ if (nil != result) {
45
+ result.fb_isResolvedNatively = @NO;
46
+ return result;
47
+ }
46
48
  }
47
49
  return self;
48
50
  }
@@ -178,23 +178,25 @@ const CGFloat FBScrollTouchProportion = 0.75f;
178
178
  FBXCElementSnapshotWrapper *scrollViewWrapped = [FBXCElementSnapshotWrapper ensureWrapped:scrollView];
179
179
  // Scrolling till cell is visible and get current value of frames
180
180
  while (![self fb_isEquivalentElementSnapshotVisible:prescrollSnapshot] && scrollCount < maxScrollCount) {
181
- if (targetCellIndex < visibleCellIndex) {
182
- scrollDirection == FBXCUIElementScrollDirectionVertical ?
183
- [scrollViewWrapped fb_scrollUpByNormalizedDistance:normalizedScrollDistance
184
- inApplication:self.application] :
185
- [scrollViewWrapped fb_scrollLeftByNormalizedDistance:normalizedScrollDistance
186
- inApplication:self.application];
187
- }
188
- else {
189
- scrollDirection == FBXCUIElementScrollDirectionVertical ?
190
- [scrollViewWrapped fb_scrollDownByNormalizedDistance:normalizedScrollDistance
181
+ @autoreleasepool {
182
+ if (targetCellIndex < visibleCellIndex) {
183
+ scrollDirection == FBXCUIElementScrollDirectionVertical ?
184
+ [scrollViewWrapped fb_scrollUpByNormalizedDistance:normalizedScrollDistance
191
185
  inApplication:self.application] :
192
- [scrollViewWrapped fb_scrollRightByNormalizedDistance:normalizedScrollDistance
193
- inApplication:self.application];
186
+ [scrollViewWrapped fb_scrollLeftByNormalizedDistance:normalizedScrollDistance
187
+ inApplication:self.application];
188
+ }
189
+ else {
190
+ scrollDirection == FBXCUIElementScrollDirectionVertical ?
191
+ [scrollViewWrapped fb_scrollDownByNormalizedDistance:normalizedScrollDistance
192
+ inApplication:self.application] :
193
+ [scrollViewWrapped fb_scrollRightByNormalizedDistance:normalizedScrollDistance
194
+ inApplication:self.application];
195
+ }
196
+ scrollCount++;
197
+ // Wait for scroll animation
198
+ [self fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout];
194
199
  }
195
- scrollCount++;
196
- // Wait for scroll animation
197
- [self fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout];
198
200
  }
199
201
 
200
202
  if (scrollCount >= maxScrollCount) {
@@ -46,22 +46,26 @@
46
46
 
47
47
  - (id<FBXCElementSnapshot>)fb_takeSnapshot:(BOOL)inDepth
48
48
  {
49
- NSError *error = nil;
50
- self.lastSnapshot = inDepth
51
- ? [self.fb_query fb_uniqueSnapshotWithError:&error]
52
- : (id<FBXCElementSnapshot>)[self snapshotWithError:&error];
53
- if (nil == self.lastSnapshot) {
54
- NSString *hintText = @"Make sure the application UI has the expected state";
55
- if (nil != error && [error.localizedDescription containsString:@"Identity Binding"]) {
56
- hintText = [NSString stringWithFormat:@"%@. You could also try to switch the binding strategy using the 'boundElementsByIndex' setting for the element lookup", hintText];
49
+ __block id<FBXCElementSnapshot> snapshot = nil;
50
+ @autoreleasepool {
51
+ NSError *error = nil;
52
+ snapshot = inDepth
53
+ ? [self.fb_query fb_uniqueSnapshotWithError:&error]
54
+ : (id<FBXCElementSnapshot>)[self snapshotWithError:&error];
55
+ if (nil == snapshot) {
56
+ NSString *hintText = @"Make sure the application UI has the expected state";
57
+ if (nil != error && [error.localizedDescription containsString:@"Identity Binding"]) {
58
+ hintText = [NSString stringWithFormat:@"%@. You could also try to switch the binding strategy using the 'boundElementsByIndex' setting for the element lookup", hintText];
59
+ }
60
+ NSString *reason = [NSString stringWithFormat:@"The previously found element \"%@\" is not present in the current view anymore. %@",
61
+ self.description, hintText];
62
+ if (nil != error) {
63
+ reason = [NSString stringWithFormat:@"%@. Original error: %@", reason, error.localizedDescription];
64
+ }
65
+ @throw [NSException exceptionWithName:FBStaleElementException reason:reason userInfo:@{}];
57
66
  }
58
- NSString *reason = [NSString stringWithFormat:@"The previously found element \"%@\" is not present in the current view anymore. %@",
59
- self.description, hintText];
60
- if (nil != error) {
61
- reason = [NSString stringWithFormat:@"%@. Original error: %@", reason, error.localizedDescription];
62
- }
63
- @throw [NSException exceptionWithName:FBStaleElementException reason:reason userInfo:@{}];
64
67
  }
68
+ self.lastSnapshot = snapshot;
65
69
  return self.lastSnapshot;
66
70
  }
67
71
 
@@ -78,9 +82,11 @@
78
82
  }
79
83
  NSMutableArray<NSString *> *matchedIds = [NSMutableArray new];
80
84
  for (id<FBXCElementSnapshot> snapshot in snapshots) {
81
- NSString *uid = [FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot];
82
- if (nil != uid) {
83
- [matchedIds addObject:uid];
85
+ @autoreleasepool {
86
+ NSString *uid = [FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot];
87
+ if (nil != uid) {
88
+ [matchedIds addObject:uid];
89
+ }
84
90
  }
85
91
  }
86
92
  NSMutableArray<XCUIElement *> *matchedElements = [NSMutableArray array];
@@ -15,11 +15,11 @@
15
15
  <key>CFBundlePackageType</key>
16
16
  <string>FMWK</string>
17
17
  <key>CFBundleShortVersionString</key>
18
- <string>9.0.4</string>
18
+ <string>9.0.6</string>
19
19
  <key>CFBundleSignature</key>
20
20
  <string>????</string>
21
21
  <key>CFBundleVersion</key>
22
- <string>9.0.4</string>
22
+ <string>9.0.6</string>
23
23
  <key>NSPrincipalClass</key>
24
24
  <string/>
25
25
  </dict>
@@ -73,7 +73,17 @@ const int ELEMENT_CACHE_SIZE = 1024;
73
73
  @throw [NSException exceptionWithName:FBStaleElementException reason:reason userInfo:@{}];
74
74
  }
75
75
  if (checkStaleness) {
76
- [element fb_takeSnapshot:NO];
76
+ @try {
77
+ [element fb_takeSnapshot:NO];
78
+ } @catch (NSException *exception) {
79
+ // if the snapshot method threw FBStaleElementException (implying the element is stale) we need to explicitly remove it from the cache, PR: https://github.com/appium/WebDriverAgent/pull/985
80
+ if ([exception.name isEqualToString:FBStaleElementException]) {
81
+ @synchronized (self.elementCache) {
82
+ [self.elementCache removeObjectForKey:uuid];
83
+ }
84
+ }
85
+ @throw exception;
86
+ }
77
87
  }
78
88
  return element;
79
89
  }
@@ -103,35 +103,40 @@ id<FBResponsePayload> FBResponseWithStatus(FBCommandStatus *status)
103
103
 
104
104
  inline NSDictionary *FBDictionaryResponseWithElement(XCUIElement *element, BOOL compact)
105
105
  {
106
- id<FBXCElementSnapshot> snapshot = element.lastSnapshot ?: element.fb_cachedSnapshot ?: [element fb_takeSnapshot:YES];
107
- NSDictionary *compactResult = FBToElementDict((NSString *)[FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot]);
108
- if (compact) {
109
- return compactResult;
110
- }
106
+ __block NSDictionary *elementResponse = nil;
107
+ @autoreleasepool {
108
+ id<FBXCElementSnapshot> snapshot = element.lastSnapshot ?: element.fb_cachedSnapshot ?: [element fb_takeSnapshot:YES];
109
+ NSDictionary *compactResult = FBToElementDict((NSString *)[FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot]);
110
+ if (compact) {
111
+ elementResponse = compactResult;
112
+ return elementResponse;
113
+ }
111
114
 
112
- NSMutableDictionary *result = compactResult.mutableCopy;
113
- FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:snapshot];
114
- NSArray *fields = [FBConfiguration.elementResponseAttributes componentsSeparatedByString:@","];
115
- for (NSString *field in fields) {
116
- // 'name' here is the w3c-approved identifier for what we mean by 'type'
117
- if ([field isEqualToString:@"name"] || [field isEqualToString:@"type"]) {
118
- result[field] = wrappedSnapshot.wdType;
119
- } else if ([field isEqualToString:@"text"]) {
120
- result[field] = FBFirstNonEmptyValue(wrappedSnapshot.wdValue, wrappedSnapshot.wdLabel) ?: [NSNull null];
121
- } else if ([field isEqualToString:@"rect"]) {
122
- result[field] = wrappedSnapshot.wdRect;
123
- } else if ([field isEqualToString:@"enabled"]) {
124
- result[field] = @(wrappedSnapshot.wdEnabled);
125
- } else if ([field isEqualToString:@"displayed"]) {
126
- result[field] = @(wrappedSnapshot.wdVisible);
127
- } else if ([field isEqualToString:@"selected"]) {
128
- result[field] = @(wrappedSnapshot.wdSelected);
129
- } else if ([field isEqualToString:@"label"]) {
130
- result[field] = wrappedSnapshot.wdLabel ?: [NSNull null];
131
- } else if ([field hasPrefix:arbitraryAttrPrefix]) {
132
- NSString *attributeName = [field substringFromIndex:[arbitraryAttrPrefix length]];
133
- result[field] = [wrappedSnapshot fb_valueForWDAttributeName:attributeName] ?: [NSNull null];
115
+ NSMutableDictionary *result = compactResult.mutableCopy;
116
+ FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:snapshot];
117
+ NSArray *fields = [FBConfiguration.elementResponseAttributes componentsSeparatedByString:@","];
118
+ for (NSString *field in fields) {
119
+ // 'name' here is the w3c-approved identifier for what we mean by 'type'
120
+ if ([field isEqualToString:@"name"] || [field isEqualToString:@"type"]) {
121
+ result[field] = wrappedSnapshot.wdType;
122
+ } else if ([field isEqualToString:@"text"]) {
123
+ result[field] = FBFirstNonEmptyValue(wrappedSnapshot.wdValue, wrappedSnapshot.wdLabel) ?: [NSNull null];
124
+ } else if ([field isEqualToString:@"rect"]) {
125
+ result[field] = wrappedSnapshot.wdRect;
126
+ } else if ([field isEqualToString:@"enabled"]) {
127
+ result[field] = @(wrappedSnapshot.wdEnabled);
128
+ } else if ([field isEqualToString:@"displayed"]) {
129
+ result[field] = @(wrappedSnapshot.wdVisible);
130
+ } else if ([field isEqualToString:@"selected"]) {
131
+ result[field] = @(wrappedSnapshot.wdSelected);
132
+ } else if ([field isEqualToString:@"label"]) {
133
+ result[field] = wrappedSnapshot.wdLabel ?: [NSNull null];
134
+ } else if ([field hasPrefix:arbitraryAttrPrefix]) {
135
+ NSString *attributeName = [field substringFromIndex:[arbitraryAttrPrefix length]];
136
+ result[field] = [wrappedSnapshot fb_valueForWDAttributeName:attributeName] ?: [NSNull null];
137
+ }
134
138
  }
139
+ elementResponse = result.copy;
135
140
  }
136
- return result.copy;
141
+ return elementResponse;
137
142
  }
@@ -364,7 +364,7 @@ static NSString *const topNodeIndexPath = @"top";
364
364
  {
365
365
  NSAssert((indexPath == nil && elementStore == nil) || (indexPath != nil && elementStore != nil), @"Either both or none of indexPath and elementStore arguments should be equal to nil", nil);
366
366
 
367
- id<FBXCElementSnapshot> currentSnapshot;
367
+ __block id<FBXCElementSnapshot> currentSnapshot;
368
368
  NSArray<id<FBXCElementSnapshot>> *children;
369
369
  if ([root isKindOfClass:XCUIElement.class]) {
370
370
  XCUIElement *element = (XCUIElement *)root;
@@ -373,7 +373,9 @@ static NSString *const topNodeIndexPath = @"top";
373
373
  // then the snapshot retrieval operation might freeze and time out
374
374
  [element.application fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout];
375
375
  }
376
- currentSnapshot = [element fb_takeSnapshot:YES];
376
+ @autoreleasepool {
377
+ currentSnapshot = [element fb_takeSnapshot:YES];
378
+ }
377
379
  children = currentSnapshot.children;
378
380
  } else {
379
381
  currentSnapshot = (id<FBXCElementSnapshot>)root;
@@ -400,18 +402,20 @@ static NSString *const topNodeIndexPath = @"top";
400
402
  }
401
403
 
402
404
  for (NSUInteger i = 0; i < [children count]; i++) {
403
- id<FBXCElementSnapshot> childSnapshot = [children objectAtIndex:i];
404
- NSString *newIndexPath = (indexPath != nil) ? [indexPath stringByAppendingFormat:@",%lu", (unsigned long)i] : nil;
405
- if (elementStore != nil && newIndexPath != nil) {
406
- [elementStore setObject:childSnapshot forKey:(id)newIndexPath];
407
- }
408
- rc = [self writeXmlWithRootElement:[FBXCElementSnapshotWrapper ensureWrapped:childSnapshot]
409
- indexPath:newIndexPath
410
- elementStore:elementStore
411
- includedAttributes:includedAttributes
412
- writer:writer];
413
- if (rc < 0) {
414
- return rc;
405
+ @autoreleasepool {
406
+ id<FBXCElementSnapshot> childSnapshot = [children objectAtIndex:i];
407
+ NSString *newIndexPath = (indexPath != nil) ? [indexPath stringByAppendingFormat:@",%lu", (unsigned long)i] : nil;
408
+ if (elementStore != nil && newIndexPath != nil) {
409
+ [elementStore setObject:childSnapshot forKey:(id)newIndexPath];
410
+ }
411
+ rc = [self writeXmlWithRootElement:[FBXCElementSnapshotWrapper ensureWrapped:childSnapshot]
412
+ indexPath:newIndexPath
413
+ elementStore:elementStore
414
+ includedAttributes:includedAttributes
415
+ writer:writer];
416
+ if (rc < 0) {
417
+ return rc;
418
+ }
415
419
  }
416
420
  }
417
421
 
@@ -54,6 +54,13 @@ NS_ASSUME_NONNULL_BEGIN
54
54
  */
55
55
  - (NSArray *)allObjects;
56
56
 
57
+ /**
58
+ Removes the object associated with the specified key from the cache.
59
+
60
+ @param key The key identifying the object to remove.
61
+ */
62
+ - (void)removeObjectForKey:(id<NSCopying>)key;
63
+
57
64
  @end
58
65
 
59
66
  NS_ASSUME_NONNULL_END
@@ -135,4 +135,12 @@
135
135
  }
136
136
  }
137
137
 
138
+ - (void)removeObjectForKey:(id<NSCopying>)key
139
+ {
140
+ LRUCacheNode *node = self.store[key];
141
+ if (node != nil) {
142
+ [self removeNode:node];
143
+ }
144
+ }
145
+
138
146
  @end
@@ -59,8 +59,10 @@
59
59
  NSPredicate *wdPredicate = [self.class fb_formatSearchPredicate:input];
60
60
  return [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject,
61
61
  NSDictionary<NSString *,id> * _Nullable bindings) {
62
- FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:evaluatedObject];
63
- return [wdPredicate evaluateWithObject:wrappedSnapshot];
62
+ @autoreleasepool {
63
+ FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:evaluatedObject];
64
+ return [wdPredicate evaluateWithObject:wrappedSnapshot];
65
+ }
64
66
  }];
65
67
  }
66
68
 
@@ -96,4 +96,33 @@
96
96
  XCTAssertEqualObjects(@[@(count)], cache.allObjects);
97
97
  }
98
98
 
99
+ - (void)testRemoveExistingObjectForKey {
100
+ LRUCache *cache = [[LRUCache alloc] initWithCapacity:3];
101
+ [cache setObject:@"foo" forKey:@"bar"];
102
+ [cache setObject:@"foo2" forKey:@"bar2"];
103
+ [cache setObject:@"foo3" forKey:@"bar3"];
104
+ [self assertArray:@[@"foo3", @"foo2", @"foo"] equalsTo:cache.allObjects];
105
+ [cache removeObjectForKey:@"bar2"];
106
+ XCTAssertNil([cache objectForKey:@"bar2"]);
107
+ [self assertArray:@[@"foo3", @"foo"] equalsTo:cache.allObjects];
108
+ }
109
+
110
+ - (void)testRemoveNonExistingObjectForKey {
111
+ LRUCache *cache = [[LRUCache alloc] initWithCapacity:2];
112
+ [cache setObject:@"foo" forKey:@"bar"];
113
+ [cache removeObjectForKey:@"nonExisting"];
114
+ XCTAssertNotNil([cache objectForKey:@"bar"]);
115
+ [self assertArray:@[@"foo"] equalsTo:cache.allObjects];
116
+ }
117
+
118
+ - (void)testRemoveAndInsertFlow {
119
+ LRUCache *cache = [[LRUCache alloc] initWithCapacity:2];
120
+ [cache setObject:@"foo" forKey:@"bar"];
121
+ [cache setObject:@"foo2" forKey:@"bar2"];
122
+ [cache removeObjectForKey:@"bar"];
123
+ XCTAssertNil([cache objectForKey:@"bar"]);
124
+ [cache setObject:@"foo3" forKey:@"bar3"];
125
+ [self assertArray:@[@"foo3", @"foo2"] equalsTo:cache.allObjects];
126
+ }
127
+
99
128
  @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-webdriveragent",
3
- "version": "9.0.4",
3
+ "version": "9.0.6",
4
4
  "description": "Package bundling WebDriverAgent",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",