diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBClassChain.m b/WebDriverAgentLib/Categories/XCUIElement+FBClassChain.m index 1be6dc774..1bf7f957d 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBClassChain.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBClassChain.m @@ -134,10 +134,8 @@ - (XCUIElementQuery *)fb_queryWithChainItem:(FBClassChainItem *)item query:(null - (NSArray *)fb_snapshotDescendantsMatchingChainItems:(NSArray *)chainItems shouldReturnAfterFirstMatch:(BOOL)shouldReturnAfterFirstMatch { NSMutableArray *lookupChain = chainItems.mutableCopy; - // Reuse an already-taken snapshot of `self` if one is available (e.g. the - // caller just resolved/inspected this same element) instead of always - // paying for a fresh one. - NSArray> *currentRoots = @[self.lastSnapshot ?: self.fb_cachedSnapshot ?: [self fb_customSnapshot]]; + // self.lastSnapshot may be stale leftover from an unrelated earlier command. + NSArray> *currentRoots = @[self.fb_cachedSnapshot ?: [self fb_customSnapshot]]; FBClassChainItem *chainItem = lookupChain.firstObject; NSArray> *candidates = [self.class fb_snapshotsMatchingItem:chainItem inRoots:currentRoots]; [lookupChain removeObjectAtIndex:0]; diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m index 7a616424b..1312cc2f4 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m @@ -100,9 +100,11 @@ @implementation XCUIElement (FBUtilities) } } NSMutableArray *matchedElements = [NSMutableArray array]; - NSString *uid = nil == self.lastSnapshot + // self.lastSnapshot may be stale leftover from an unrelated earlier command. + id selfSnapshot = self.fb_cachedSnapshot; + NSString *uid = nil == selfSnapshot ? self.fb_uid - : [FBXCElementSnapshotWrapper wdUIDWithSnapshot:self.lastSnapshot]; + : [FBXCElementSnapshotWrapper wdUIDWithSnapshot:selfSnapshot]; if (nil != uid && [matchedIds containsObject:uid]) { XCUIElement *stableSelf = [self fb_stableInstanceWithUid:uid]; if (1 == snapshots.count) { diff --git a/WebDriverAgentLib/Utilities/FBXPath.m b/WebDriverAgentLib/Utilities/FBXPath.m index 09a9aef13..0e97b052b 100644 --- a/WebDriverAgentLib/Utilities/FBXPath.m +++ b/WebDriverAgentLib/Utilities/FBXPath.m @@ -258,10 +258,11 @@ + (nullable NSString *)xmlStringWithRootElement:(id)root if ([root isKindOfClass:XCUIElement.class]) { lookupScopeSnapshot = [self snapshotWithRoot:[(XCUIElement *)root application] useNative:useNativeSnapshot]; + // root.lastSnapshot may be stale leftover from an unrelated earlier command. contextRootSnapshot = [root isKindOfClass:XCUIApplication.class] ? nil - : ([(XCUIElement *)root lastSnapshot] ?: [self snapshotWithRoot:(XCUIElement *)root - useNative:useNativeSnapshot]); + : ([(XCUIElement *)root fb_cachedSnapshot] ?: [self snapshotWithRoot:(XCUIElement *)root + useNative:useNativeSnapshot]); } else { lookupScopeSnapshot = (id)root; contextRootSnapshot = nil == lookupScopeSnapshot.parent ? nil : (id)root; diff --git a/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m b/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m index 2137ff5fc..f03f6a62d 100644 --- a/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m +++ b/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m @@ -21,6 +21,7 @@ #import "XCUIElement+FBResolve.h" #import "FBXPath.h" #import "FBXCodeCompatibility.h" +#import "XCUIElement+FBUtilities.h" @interface XCUIElementFBFindTests : FBIntegrationTestCase @property (nonatomic, strong) XCUIElement *testedView; @@ -536,3 +537,24 @@ - (void)testPerformanceOfClassChainLookupOnDeepHierarchy } @end + +@interface XCUIElementFBFindTests_StaleAppSnapshot : FBIntegrationTestCase +@end +@implementation XCUIElementFBFindTests_StaleAppSnapshot + +// Regression test for https://github.com/appium/appium/issues/22672. +- (void)testClassChainWithIntermediatePositionAfterStaleAppSnapshot +{ + [self launchApplication]; + // Simulates a stale snapshot cached by an earlier, unrelated command (e.g. GET /source). + [self.testedApplication fb_customSnapshot]; + [self goToDeepHierarchyPage]; + + NSString *query = @"**/XCUIElementTypeOther[`label == \"View 10\"`][1]/**/XCUIElementTypeOther[`label BEGINSWITH \"View 19\"`]"; + NSArray *matches = [self.testedApplication fb_descendantsMatchingClassChain:query + shouldReturnAfterFirstMatch:NO]; + XCTAssertEqual(matches.count, 1); + XCTAssertEqualObjects(matches.firstObject.label, @"View 19"); +} + +@end