Skip to content

Commit 08f1306

Browse files
feat: Refactor snapshotting mechanism (#970)
BREAKING CHANGE: snapshotTimeout and customSnapshotTimeout settings have been removed as a result of the custom snapshotting logic removal
1 parent eca2ed1 commit 08f1306

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+350
-621
lines changed

PrivateHeaders/XCTest/XCTestManager_ManagerInterface-Protocol.h

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
- (void)_XCT_requestElementAtPoint:(CGPoint)arg1 reply:(void (^)(id/*XCAccessibilityElement*/, NSError *))arg2;
2828
- (void)_XCT_fetchParameterizedAttributeForElement:(id/*XCAccessibilityElement*/)arg1 attributes:(NSNumber *)arg2 parameter:(id)arg3 reply:(void (^)(id, NSError *))arg4;
2929
- (void)_XCT_setAttribute:(NSNumber *)arg1 value:(id)arg2 element:(id/*XCAccessibilityElement*/)arg3 reply:(void (^)(BOOL, NSError *))arg4;
30+
- (void)_XCT_fetchAttributes:(id)attributes forElement:(id)element reply:(void (^)(NSDictionary *, NSError *))reply;
3031
- (void)_XCT_fetchAttributesForElement:(id/*XCAccessibilityElement*/)arg1 attributes:(NSArray *)arg2 reply:(void (^)(NSDictionary *, NSError *))arg3;
3132
- (void)_XCT_terminateApplicationWithBundleID:(NSString *)arg1 completion:(void (^)(NSError *))arg2;
3233
- (void)_XCT_performAccessibilityAction:(int)arg1 onElement:(id/*XCAccessibilityElement*/)arg2 withValue:(id)arg3 reply:(void (^)(NSError *))arg4;

WebDriverAgent.xcodeproj/project.pbxproj

+12
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,10 @@
451451
71A7EAFA1E224648001DA4F2 /* FBClassChainQueryParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 71A7EAF81E224648001DA4F2 /* FBClassChainQueryParser.m */; };
452452
71A7EAFC1E229302001DA4F2 /* FBClassChainTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 71A7EAFB1E229302001DA4F2 /* FBClassChainTests.m */; };
453453
71ACF5B8242F2FDC00F0AAD4 /* FBSafariAlertTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 71ACF5B7242F2FDC00F0AAD4 /* FBSafariAlertTests.m */; };
454+
71AE3CF72D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 71AE3CF52D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h */; };
455+
71AE3CF82D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 71AE3CF62D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m */; };
456+
71AE3CF92D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 71AE3CF52D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h */; };
457+
71AE3CFA2D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 71AE3CF62D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m */; };
454458
71B155DA23070ECF00646AFB /* FBHTTPStatusCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 71B155D923070ECF00646AFB /* FBHTTPStatusCodes.h */; settings = {ATTRIBUTES = (Public, ); }; };
455459
71B155DC230711E900646AFB /* FBCommandStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 71B155DB230711E900646AFB /* FBCommandStatus.m */; };
456460
71B155DF23080CA600646AFB /* FBProtocolHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 71B155DD23080CA600646AFB /* FBProtocolHelpers.h */; };
@@ -1050,6 +1054,8 @@
10501054
71A7EAF81E224648001DA4F2 /* FBClassChainQueryParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBClassChainQueryParser.m; sourceTree = "<group>"; };
10511055
71A7EAFB1E229302001DA4F2 /* FBClassChainTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBClassChainTests.m; sourceTree = "<group>"; };
10521056
71ACF5B7242F2FDC00F0AAD4 /* FBSafariAlertTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBSafariAlertTests.m; sourceTree = "<group>"; };
1057+
71AE3CF52D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "XCUIElement+FBVisibleFrame.h"; sourceTree = "<group>"; };
1058+
71AE3CF62D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "XCUIElement+FBVisibleFrame.m"; sourceTree = "<group>"; };
10531059
71B155D923070ECF00646AFB /* FBHTTPStatusCodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBHTTPStatusCodes.h; sourceTree = "<group>"; };
10541060
71B155DB230711E900646AFB /* FBCommandStatus.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBCommandStatus.m; sourceTree = "<group>"; };
10551061
71B155DD23080CA600646AFB /* FBProtocolHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBProtocolHelpers.h; sourceTree = "<group>"; };
@@ -1781,6 +1787,8 @@
17811787
71B49EC61ED1A58100D51AD6 /* XCUIElement+FBUID.m */,
17821788
EEE3763F1D59F81400ED88DD /* XCUIElement+FBUtilities.h */,
17831789
EEE376401D59F81400ED88DD /* XCUIElement+FBUtilities.m */,
1790+
71AE3CF52D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h */,
1791+
71AE3CF62D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m */,
17841792
EEE376471D59FAE900ED88DD /* XCUIElement+FBWebDriverAttributes.h */,
17851793
EEE376481D59FAE900ED88DD /* XCUIElement+FBWebDriverAttributes.m */,
17861794
641EE7042240CDCF00173FCB /* XCUIElement+FBTVFocuse.h */,
@@ -2399,6 +2407,7 @@
23992407
641EE6A42240C5CA00173FCB /* FBCommandHandler.h in Headers */,
24002408
641EE6A52240C5CA00173FCB /* FBSessionCommands.h in Headers */,
24012409
641EE70C2240CE2D00173FCB /* FBTVNavigationTracker.h in Headers */,
2410+
71AE3CF72D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h in Headers */,
24022411
641EE6A62240C5CA00173FCB /* FBImageProcessor.h in Headers */,
24032412
641EE6A72240C5CA00173FCB /* FBSession-Private.h in Headers */,
24042413
641EE6A82240C5CA00173FCB /* NSString+FBXMLSafeString.h in Headers */,
@@ -2585,6 +2594,7 @@
25852594
714EAA0D2673FDFE005C5B47 /* FBCapabilities.h in Headers */,
25862595
EE35AD5C1E3B77D600A02D78 /* XCTNSPredicateExpectation.h in Headers */,
25872596
EE35AD521E3B77D600A02D78 /* XCTestObservationCenter.h in Headers */,
2597+
71AE3CF92D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h in Headers */,
25882598
EE35AD5B1E3B77D600A02D78 /* XCTNSNotificationExpectation.h in Headers */,
25892599
E444DC97249131D40060D7EB /* HTTPServer.h in Headers */,
25902600
E444DCAE24913C220060D7EB /* HTTPResponseProxy.h in Headers */,
@@ -3160,6 +3170,7 @@
31603170
641EE60E2240C5CA00173FCB /* XCUIElement+FBTyping.m in Sources */,
31613171
641EE60F2240C5CA00173FCB /* XCUIElement+FBAccessibility.m in Sources */,
31623172
641EE6102240C5CA00173FCB /* FBImageUtils.m in Sources */,
3173+
71AE3CF82D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m in Sources */,
31633174
641EE6112240C5CA00173FCB /* FBSession.m in Sources */,
31643175
641EE6122240C5CA00173FCB /* FBFindElementCommands.m in Sources */,
31653176
71A5C67629A4F39600421C37 /* XCTIssue+FBPatcher.m in Sources */,
@@ -3232,6 +3243,7 @@
32323243
713AE576243A53BE0000D657 /* FBW3CActionsHelpers.m in Sources */,
32333244
71B155E123080CA600646AFB /* FBProtocolHelpers.m in Sources */,
32343245
EE158AB11CBD456F00A3E3F0 /* XCUIElement+FBIsVisible.m in Sources */,
3246+
71AE3CFA2D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m in Sources */,
32353247
EEBBD48C1D47746D00656A81 /* XCUIElement+FBFind.m in Sources */,
32363248
EE158ADD1CBD456F00A3E3F0 /* FBResponsePayload.m in Sources */,
32373249
E444DCB524913C220060D7EB /* RouteRequest.m in Sources */,

WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.h

+4-9
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,11 @@ NS_ASSUME_NONNULL_BEGIN
5858
5959
@param attribute attribute's accessibility identifier. Can be one of
6060
`XC_kAXXCAttribute`-prefixed attribute names.
61-
@return value for given accessibility property identifier
61+
@param error Error instance in case of a failure
62+
@return value for given accessibility property identifier or nil in case of failure
6263
*/
63-
- (nullable id)fb_attributeValue:(NSString *)attribute;
64+
- (nullable id)fb_attributeValue:(NSString *)attribute
65+
error:(NSError **)error;
6466

6567
/**
6668
Method used to determine whether given element matches receiver by comparing it's parameters except frame.
@@ -87,13 +89,6 @@ NS_ASSUME_NONNULL_BEGIN
8789
/**! Human-readable snapshot description */
8890
- (NSString *)fb_description;
8991

90-
/**
91-
Returns the snapshot visibleFrame with a fallback to direct attribute retrieval from FBXCAXClient in case of a snapshot fault (nil visibleFrame)
92-
93-
@return the snapshot visibleFrame
94-
*/
95-
- (CGRect)fb_visibleFrameWithFallback;
96-
9792
/**
9893
Wrapper for Apple's hitpoint, thats resolves few known issues
9994

WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.m

+13-25
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,20 @@
1010
#import "FBXCElementSnapshotWrapper+Helpers.h"
1111

1212
#import "FBFindElementCommands.h"
13+
#import "FBErrorBuilder.h"
1314
#import "FBRunLoopSpinner.h"
1415
#import "FBLogger.h"
1516
#import "FBXCElementSnapshot.h"
17+
#import "FBXCTestDaemonsProxy.h"
1618
#import "FBXCAXClientProxy.h"
1719
#import "XCTestDriver.h"
1820
#import "XCTestPrivateSymbols.h"
1921
#import "XCUIElement.h"
2022
#import "XCUIElement+FBWebDriverAttributes.h"
2123
#import "XCUIHitPointResult.h"
2224

25+
#define ATTRIBUTE_FETCH_WARN_TIME_LIMIT 0.05
26+
2327
inline static BOOL isSnapshotTypeAmongstGivenTypes(id<FBXCElementSnapshot> snapshot,
2428
NSArray<NSNumber *> *types);
2529

@@ -65,10 +69,17 @@ - (NSString *)fb_description
6569
}
6670

6771
- (id)fb_attributeValue:(NSString *)attribute
72+
error:(NSError **)error
6873
{
74+
NSDate *start = [NSDate date];
6975
NSDictionary *result = [FBXCAXClientProxy.sharedClient attributesForElement:[self accessibilityElement]
70-
attributes:@[attribute]];
71-
return result[attribute];
76+
attributes:@[attribute]
77+
error:error];
78+
NSTimeInterval elapsed = ABS([start timeIntervalSinceNow]);
79+
if (elapsed > ATTRIBUTE_FETCH_WARN_TIME_LIMIT) {
80+
NSLog(@"! Fetching of %@ value for %@ took %@s", attribute, self.fb_description, @(elapsed));
81+
}
82+
return [result objectForKey:attribute];
7283
}
7384

7485
inline static BOOL areValuesEqual(id value1, id value2);
@@ -140,29 +151,6 @@ - (BOOL)fb_framelessFuzzyMatchesElement:(id<FBXCElementSnapshot>)snapshot
140151
return targetCellSnapshot;
141152
}
142153

143-
- (CGRect)fb_visibleFrameWithFallback
144-
{
145-
CGRect thisVisibleFrame = [self visibleFrame];
146-
if (!CGRectIsEmpty(thisVisibleFrame)) {
147-
return thisVisibleFrame;
148-
}
149-
150-
NSDictionary *visibleFrameDict = (NSDictionary*)[self fb_attributeValue:@"XC_kAXXCAttributeVisibleFrame"];
151-
if (visibleFrameDict == nil) {
152-
return thisVisibleFrame;
153-
}
154-
155-
id x = [visibleFrameDict objectForKey:@"X"];
156-
id y = [visibleFrameDict objectForKey:@"Y"];
157-
id height = [visibleFrameDict objectForKey:@"Height"];
158-
id width = [visibleFrameDict objectForKey:@"Width"];
159-
if (x != nil && y != nil && height != nil && width != nil) {
160-
return CGRectMake([x doubleValue], [y doubleValue], [width doubleValue], [height doubleValue]);
161-
}
162-
163-
return thisVisibleFrame;
164-
}
165-
166154
- (NSValue *)fb_hitPoint
167155
{
168156
NSError *error;

WebDriverAgentLib/Categories/XCUIApplication+FBAlert.m

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ - (nullable XCUIElement *)fb_alertElementFromSafariWithScrollView:(XCUIElement *
5252
// and conatins at least one text view
5353
__block NSUInteger buttonsCount = 0;
5454
__block NSUInteger textViewsCount = 0;
55-
id<FBXCElementSnapshot> snapshot = candidate.fb_cachedSnapshot ?: candidate.fb_takeSnapshot;
55+
id<FBXCElementSnapshot> snapshot = candidate.fb_cachedSnapshot ?: [candidate fb_takeSnapshot:YES];
5656
[snapshot enumerateDescendantsUsingBlock:^(id<FBXCElementSnapshot> descendant) {
5757
XCUIElementType curType = descendant.elementType;
5858
if (curType == XCUIElementTypeButton) {
@@ -73,7 +73,7 @@ - (XCUIElement *)fb_alertElement
7373
if (nil == alert) {
7474
return nil;
7575
}
76-
id<FBXCElementSnapshot> alertSnapshot = alert.fb_cachedSnapshot ?: alert.fb_takeSnapshot;
76+
id<FBXCElementSnapshot> alertSnapshot = alert.fb_cachedSnapshot ?: [alert fb_takeSnapshot:YES];
7777

7878
if (alertSnapshot.elementType == XCUIElementTypeAlert) {
7979
return alert;

WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m

+4-20
Original file line numberDiff line numberDiff line change
@@ -176,31 +176,15 @@ - (NSDictionary *)fb_tree
176176

177177
- (NSDictionary *)fb_tree:(nullable NSSet<NSString *> *)excludedAttributes
178178
{
179-
// This set includes XCTest-specific internal attribute names,
180-
// while the `excludedAttributes` arg contains human-readable ones
181-
NSMutableSet* includedAttributeNames = [NSMutableSet setWithArray:FBCustomAttributeNames()];
182-
[includedAttributeNames addObjectsFromArray:FBStandardAttributeNames()];
183-
if (nil != excludedAttributes) {
184-
for (NSString *attr in excludedAttributes) {
185-
NSString *mappedName = [customExclusionAttributesMap() objectForKey:attr];
186-
if (nil != mappedName) {
187-
[includedAttributeNames removeObject:attr];
188-
}
189-
}
190-
}
191-
id<FBXCElementSnapshot> snapshot = nil == excludedAttributes
192-
? [self fb_snapshotWithAllAttributesAndMaxDepth:nil]
193-
: [self fb_snapshotWithAttributes:[includedAttributeNames allObjects] maxDepth:nil];
179+
id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:YES];
194180
return [self.class dictionaryForElement:snapshot
195181
recursive:YES
196182
excludedAttributes:excludedAttributes];
197183
}
198184

199185
- (NSDictionary *)fb_accessibilityTree
200186
{
201-
id<FBXCElementSnapshot> snapshot = self.fb_isResolvedFromCache.boolValue
202-
? self.lastSnapshot
203-
: [self fb_snapshotWithAllAttributesAndMaxDepth:nil];
187+
id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:YES];
204188
return [self.class accessibilityInfoForElement:snapshot];
205189
}
206190

@@ -445,8 +429,8 @@ - (BOOL)fb_dismissKeyboardWithKeyNames:(nullable NSArray<NSString *> *)keyNames
445429

446430
id extractedElement = extractIssueProperty(issue, @"element");
447431

448-
id<FBXCElementSnapshot> elementSnapshot = [extractedElement fb_cachedSnapshot] ?: [extractedElement fb_takeSnapshot];
449-
NSDictionary *elementAttributes = elementSnapshot
432+
id<FBXCElementSnapshot> elementSnapshot = [extractedElement fb_cachedSnapshot] ?: [extractedElement fb_takeSnapshot:NO];
433+
NSDictionary *elementAttributes = elementSnapshot
450434
? [self.class dictionaryForElement:elementSnapshot
451435
recursive:NO
452436
excludedAttributes:customAttributesToExclude]

WebDriverAgentLib/Categories/XCUIElement+FBAccessibility.m

+15-4
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ @implementation XCUIElement (FBAccessibility)
1818

1919
- (BOOL)fb_isAccessibilityElement
2020
{
21-
id<FBXCElementSnapshot> snapshot = [self fb_snapshotWithAttributes:@[FB_XCAXAIsElementAttributeName]
22-
maxDepth:@1];
21+
id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:NO];
2322
return [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_isAccessibilityElement;
2423
}
2524

@@ -33,8 +32,20 @@ - (BOOL)fb_isAccessibilityElement
3332
if (nil != isAccessibilityElement) {
3433
return isAccessibilityElement.boolValue;
3534
}
36-
37-
return [(NSNumber *)[self fb_attributeValue:FB_XCAXAIsElementAttributeName] boolValue];
35+
36+
NSError *error;
37+
NSNumber *attributeValue = [self fb_attributeValue:FB_XCAXAIsElementAttributeName
38+
error:&error];
39+
if (nil != attributeValue) {
40+
NSMutableDictionary *updatedValue = [NSMutableDictionary dictionaryWithDictionary:self.additionalAttributes ?: @{}];
41+
[updatedValue setObject:attributeValue forKey:FB_XCAXAIsElementAttribute];
42+
self.snapshot.additionalAttributes = updatedValue.copy;
43+
return [attributeValue boolValue];
44+
}
45+
46+
NSLog(@"Cannot determine accessibility of '%@' natively: %@. Defaulting to: %@",
47+
self.fb_description, error.description, @(NO));
48+
return NO;
3849
}
3950

4051
@end

WebDriverAgentLib/Categories/XCUIElement+FBCaching.h

-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ NS_ASSUME_NONNULL_BEGIN
1313

1414
@interface XCUIElement (FBCaching)
1515

16-
/*! This property is set to YES if the given element has been resolved from the cache, so it is safe to use the `lastSnapshot` property */
17-
@property (nullable, nonatomic) NSNumber *fb_isResolvedFromCache;
18-
1916
@property (nonatomic, readonly) NSString *fb_cacheId;
2017

2118
@end

WebDriverAgentLib/Categories/XCUIElement+FBCaching.m

+1-22
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,6 @@
1818

1919
@implementation XCUIElement (FBCaching)
2020

21-
static char XCUIELEMENT_IS_RESOLVED_FROM_CACHE_KEY;
22-
23-
@dynamic fb_isResolvedFromCache;
24-
25-
- (void)setFb_isResolvedFromCache:(NSNumber *)isResolvedFromCache
26-
{
27-
objc_setAssociatedObject(self, &XCUIELEMENT_IS_RESOLVED_FROM_CACHE_KEY, isResolvedFromCache, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
28-
}
29-
30-
- (NSNumber *)fb_isResolvedFromCache
31-
{
32-
return (NSNumber *)objc_getAssociatedObject(self, &XCUIELEMENT_IS_RESOLVED_FROM_CACHE_KEY);
33-
}
34-
3521
static char XCUIELEMENT_CACHE_ID_KEY;
3622

3723
@dynamic fb_cacheId;
@@ -43,14 +29,7 @@ - (NSString *)fb_cacheId
4329
return (NSString *)result;
4430
}
4531

46-
NSString *uid;
47-
if ([self isKindOfClass:XCUIApplication.class]) {
48-
uid = self.fb_uid;
49-
} else {
50-
id<FBXCElementSnapshot> snapshot = self.fb_cachedSnapshot ?: self.fb_takeSnapshot;
51-
uid = [FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot];
52-
}
53-
32+
NSString *uid = self.fb_uid;
5433
objc_setAssociatedObject(self, &XCUIELEMENT_CACHE_ID_KEY, uid, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
5534
return uid;
5635
}

WebDriverAgentLib/Categories/XCUIElement+FBFind.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ @implementation XCUIElement (FBFind)
110110
matchingSnapshots = @[snapshot];
111111
}
112112
return [self fb_filterDescendantsWithSnapshots:matchingSnapshots
113-
selfUID:[FBXCElementSnapshotWrapper wdUIDWithSnapshot:self.lastSnapshot]
113+
selfUID:self.fb_uid
114114
onlyChildren:NO];
115115
}
116116

0 commit comments

Comments
 (0)