appium-webdriveragent 8.12.2 → 9.0.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.
- package/CHANGELOG.md +10 -0
- package/PrivateHeaders/XCTest/XCTestManager_ManagerInterface-Protocol.h +1 -0
- package/WebDriverAgent.xcodeproj/project.pbxproj +12 -0
- package/WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.h +4 -9
- package/WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.m +13 -25
- package/WebDriverAgentLib/Categories/XCUIApplication+FBAlert.m +2 -2
- package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +4 -20
- package/WebDriverAgentLib/Categories/XCUIElement+FBAccessibility.m +15 -4
- package/WebDriverAgentLib/Categories/XCUIElement+FBCaching.h +0 -3
- package/WebDriverAgentLib/Categories/XCUIElement+FBCaching.m +1 -22
- package/WebDriverAgentLib/Categories/XCUIElement+FBFind.m +1 -1
- package/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m +28 -173
- package/WebDriverAgentLib/Categories/XCUIElement+FBPickerWheel.m +1 -3
- package/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m +33 -30
- package/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m +4 -8
- package/WebDriverAgentLib/Categories/XCUIElement+FBUID.m +2 -2
- package/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h +3 -36
- package/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +10 -68
- package/WebDriverAgentLib/Categories/XCUIElement+FBVisibleFrame.h +36 -0
- package/WebDriverAgentLib/Categories/XCUIElement+FBVisibleFrame.m +53 -0
- package/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m +7 -20
- package/WebDriverAgentLib/Commands/FBCustomCommands.m +2 -1
- package/WebDriverAgentLib/Commands/FBElementCommands.m +25 -47
- package/WebDriverAgentLib/Commands/FBFindElementCommands.m +10 -9
- package/WebDriverAgentLib/Commands/FBSessionCommands.m +0 -8
- package/WebDriverAgentLib/FBAlert.m +6 -5
- package/WebDriverAgentLib/Info.plist +2 -2
- package/WebDriverAgentLib/Routing/FBElementCache.h +4 -10
- package/WebDriverAgentLib/Routing/FBElementCache.m +4 -33
- package/WebDriverAgentLib/Routing/FBResponsePayload.m +1 -7
- package/WebDriverAgentLib/Utilities/FBConfiguration.h +0 -8
- package/WebDriverAgentLib/Utilities/FBConfiguration.m +0 -12
- package/WebDriverAgentLib/Utilities/FBSettings.h +0 -3
- package/WebDriverAgentLib/Utilities/FBSettings.m +0 -2
- package/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m +1 -3
- package/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m +1 -1
- package/WebDriverAgentLib/Utilities/FBXCAXClientProxy.h +4 -3
- package/WebDriverAgentLib/Utilities/FBXCAXClientProxy.m +7 -11
- package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h +3 -1
- package/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m +2 -2
- package/WebDriverAgentLib/Utilities/FBXPath.m +1 -4
- package/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.h +3 -0
- package/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.m +1 -0
- package/WebDriverAgentTests/IntegrationTests/FBElementAttributeTests.m +2 -1
- package/WebDriverAgentTests/IntegrationTests/FBElementSwipingTests.m +1 -1
- package/WebDriverAgentTests/IntegrationTests/FBW3CTouchActionsIntegrationTests.m +1 -1
- package/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m +2 -2
- package/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHelperTests.m +21 -10
- package/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHitPointTests.m +1 -1
- package/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m +5 -3
- package/WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.m +10 -0
- package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h +1 -2
- package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m +1 -1
- package/WebDriverAgentTests/UnitTests/FBElementCacheTests.m +0 -2
- package/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.h +0 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## [9.0.0](https://github.com/appium/WebDriverAgent/compare/v8.12.2...v9.0.0) (2025-01-16)
|
|
2
|
+
|
|
3
|
+
### ⚠ BREAKING CHANGES
|
|
4
|
+
|
|
5
|
+
* snapshotTimeout and customSnapshotTimeout settings have been removed as a result of the custom snapshotting logic removal
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* Refactor snapshotting mechanism ([#970](https://github.com/appium/WebDriverAgent/issues/970)) ([08f1306](https://github.com/appium/WebDriverAgent/commit/08f13060119c710f53b34a98c95683287c0365a0))
|
|
10
|
+
|
|
1
11
|
## [8.12.2](https://github.com/appium/WebDriverAgent/compare/v8.12.1...v8.12.2) (2025-01-13)
|
|
2
12
|
|
|
3
13
|
### Miscellaneous Chores
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
- (void)_XCT_requestElementAtPoint:(CGPoint)arg1 reply:(void (^)(id/*XCAccessibilityElement*/, NSError *))arg2;
|
|
28
28
|
- (void)_XCT_fetchParameterizedAttributeForElement:(id/*XCAccessibilityElement*/)arg1 attributes:(NSNumber *)arg2 parameter:(id)arg3 reply:(void (^)(id, NSError *))arg4;
|
|
29
29
|
- (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;
|
|
30
31
|
- (void)_XCT_fetchAttributesForElement:(id/*XCAccessibilityElement*/)arg1 attributes:(NSArray *)arg2 reply:(void (^)(NSDictionary *, NSError *))arg3;
|
|
31
32
|
- (void)_XCT_terminateApplicationWithBundleID:(NSString *)arg1 completion:(void (^)(NSError *))arg2;
|
|
32
33
|
- (void)_XCT_performAccessibilityAction:(int)arg1 onElement:(id/*XCAccessibilityElement*/)arg2 withValue:(id)arg3 reply:(void (^)(NSError *))arg4;
|
|
@@ -451,6 +451,10 @@
|
|
|
451
451
|
71A7EAFA1E224648001DA4F2 /* FBClassChainQueryParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 71A7EAF81E224648001DA4F2 /* FBClassChainQueryParser.m */; };
|
|
452
452
|
71A7EAFC1E229302001DA4F2 /* FBClassChainTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 71A7EAFB1E229302001DA4F2 /* FBClassChainTests.m */; };
|
|
453
453
|
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 */; };
|
|
454
458
|
71B155DA23070ECF00646AFB /* FBHTTPStatusCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 71B155D923070ECF00646AFB /* FBHTTPStatusCodes.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
|
455
459
|
71B155DC230711E900646AFB /* FBCommandStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 71B155DB230711E900646AFB /* FBCommandStatus.m */; };
|
|
456
460
|
71B155DF23080CA600646AFB /* FBProtocolHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 71B155DD23080CA600646AFB /* FBProtocolHelpers.h */; };
|
|
@@ -1050,6 +1054,8 @@
|
|
|
1050
1054
|
71A7EAF81E224648001DA4F2 /* FBClassChainQueryParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBClassChainQueryParser.m; sourceTree = "<group>"; };
|
|
1051
1055
|
71A7EAFB1E229302001DA4F2 /* FBClassChainTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBClassChainTests.m; sourceTree = "<group>"; };
|
|
1052
1056
|
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>"; };
|
|
1053
1059
|
71B155D923070ECF00646AFB /* FBHTTPStatusCodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBHTTPStatusCodes.h; sourceTree = "<group>"; };
|
|
1054
1060
|
71B155DB230711E900646AFB /* FBCommandStatus.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBCommandStatus.m; sourceTree = "<group>"; };
|
|
1055
1061
|
71B155DD23080CA600646AFB /* FBProtocolHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBProtocolHelpers.h; sourceTree = "<group>"; };
|
|
@@ -1781,6 +1787,8 @@
|
|
|
1781
1787
|
71B49EC61ED1A58100D51AD6 /* XCUIElement+FBUID.m */,
|
|
1782
1788
|
EEE3763F1D59F81400ED88DD /* XCUIElement+FBUtilities.h */,
|
|
1783
1789
|
EEE376401D59F81400ED88DD /* XCUIElement+FBUtilities.m */,
|
|
1790
|
+
71AE3CF52D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h */,
|
|
1791
|
+
71AE3CF62D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m */,
|
|
1784
1792
|
EEE376471D59FAE900ED88DD /* XCUIElement+FBWebDriverAttributes.h */,
|
|
1785
1793
|
EEE376481D59FAE900ED88DD /* XCUIElement+FBWebDriverAttributes.m */,
|
|
1786
1794
|
641EE7042240CDCF00173FCB /* XCUIElement+FBTVFocuse.h */,
|
|
@@ -2399,6 +2407,7 @@
|
|
|
2399
2407
|
641EE6A42240C5CA00173FCB /* FBCommandHandler.h in Headers */,
|
|
2400
2408
|
641EE6A52240C5CA00173FCB /* FBSessionCommands.h in Headers */,
|
|
2401
2409
|
641EE70C2240CE2D00173FCB /* FBTVNavigationTracker.h in Headers */,
|
|
2410
|
+
71AE3CF72D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h in Headers */,
|
|
2402
2411
|
641EE6A62240C5CA00173FCB /* FBImageProcessor.h in Headers */,
|
|
2403
2412
|
641EE6A72240C5CA00173FCB /* FBSession-Private.h in Headers */,
|
|
2404
2413
|
641EE6A82240C5CA00173FCB /* NSString+FBXMLSafeString.h in Headers */,
|
|
@@ -2585,6 +2594,7 @@
|
|
|
2585
2594
|
714EAA0D2673FDFE005C5B47 /* FBCapabilities.h in Headers */,
|
|
2586
2595
|
EE35AD5C1E3B77D600A02D78 /* XCTNSPredicateExpectation.h in Headers */,
|
|
2587
2596
|
EE35AD521E3B77D600A02D78 /* XCTestObservationCenter.h in Headers */,
|
|
2597
|
+
71AE3CF92D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h in Headers */,
|
|
2588
2598
|
EE35AD5B1E3B77D600A02D78 /* XCTNSNotificationExpectation.h in Headers */,
|
|
2589
2599
|
E444DC97249131D40060D7EB /* HTTPServer.h in Headers */,
|
|
2590
2600
|
E444DCAE24913C220060D7EB /* HTTPResponseProxy.h in Headers */,
|
|
@@ -3160,6 +3170,7 @@
|
|
|
3160
3170
|
641EE60E2240C5CA00173FCB /* XCUIElement+FBTyping.m in Sources */,
|
|
3161
3171
|
641EE60F2240C5CA00173FCB /* XCUIElement+FBAccessibility.m in Sources */,
|
|
3162
3172
|
641EE6102240C5CA00173FCB /* FBImageUtils.m in Sources */,
|
|
3173
|
+
71AE3CF82D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m in Sources */,
|
|
3163
3174
|
641EE6112240C5CA00173FCB /* FBSession.m in Sources */,
|
|
3164
3175
|
641EE6122240C5CA00173FCB /* FBFindElementCommands.m in Sources */,
|
|
3165
3176
|
71A5C67629A4F39600421C37 /* XCTIssue+FBPatcher.m in Sources */,
|
|
@@ -3232,6 +3243,7 @@
|
|
|
3232
3243
|
713AE576243A53BE0000D657 /* FBW3CActionsHelpers.m in Sources */,
|
|
3233
3244
|
71B155E123080CA600646AFB /* FBProtocolHelpers.m in Sources */,
|
|
3234
3245
|
EE158AB11CBD456F00A3E3F0 /* XCUIElement+FBIsVisible.m in Sources */,
|
|
3246
|
+
71AE3CFA2D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m in Sources */,
|
|
3235
3247
|
EEBBD48C1D47746D00656A81 /* XCUIElement+FBFind.m in Sources */,
|
|
3236
3248
|
EE158ADD1CBD456F00A3E3F0 /* FBResponsePayload.m in Sources */,
|
|
3237
3249
|
E444DCB524913C220060D7EB /* RouteRequest.m in Sources */,
|
|
@@ -58,9 +58,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
58
58
|
|
|
59
59
|
@param attribute attribute's accessibility identifier. Can be one of
|
|
60
60
|
`XC_kAXXCAttribute`-prefixed attribute names.
|
|
61
|
-
@
|
|
61
|
+
@param error Error instance in case of a failure
|
|
62
|
+
@return value for given accessibility property identifier or nil in case of failure
|
|
62
63
|
*/
|
|
63
|
-
- (nullable id)fb_attributeValue:(NSString *)attribute
|
|
64
|
+
- (nullable id)fb_attributeValue:(NSString *)attribute
|
|
65
|
+
error:(NSError **)error;
|
|
64
66
|
|
|
65
67
|
/**
|
|
66
68
|
Method used to determine whether given element matches receiver by comparing it's parameters except frame.
|
|
@@ -87,13 +89,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
87
89
|
/**! Human-readable snapshot description */
|
|
88
90
|
- (NSString *)fb_description;
|
|
89
91
|
|
|
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
|
-
|
|
97
92
|
/**
|
|
98
93
|
Wrapper for Apple's hitpoint, thats resolves few known issues
|
|
99
94
|
|
|
@@ -10,9 +10,11 @@
|
|
|
10
10
|
#import "FBXCElementSnapshotWrapper+Helpers.h"
|
|
11
11
|
|
|
12
12
|
#import "FBFindElementCommands.h"
|
|
13
|
+
#import "FBErrorBuilder.h"
|
|
13
14
|
#import "FBRunLoopSpinner.h"
|
|
14
15
|
#import "FBLogger.h"
|
|
15
16
|
#import "FBXCElementSnapshot.h"
|
|
17
|
+
#import "FBXCTestDaemonsProxy.h"
|
|
16
18
|
#import "FBXCAXClientProxy.h"
|
|
17
19
|
#import "XCTestDriver.h"
|
|
18
20
|
#import "XCTestPrivateSymbols.h"
|
|
@@ -20,6 +22,8 @@
|
|
|
20
22
|
#import "XCUIElement+FBWebDriverAttributes.h"
|
|
21
23
|
#import "XCUIHitPointResult.h"
|
|
22
24
|
|
|
25
|
+
#define ATTRIBUTE_FETCH_WARN_TIME_LIMIT 0.05
|
|
26
|
+
|
|
23
27
|
inline static BOOL isSnapshotTypeAmongstGivenTypes(id<FBXCElementSnapshot> snapshot,
|
|
24
28
|
NSArray<NSNumber *> *types);
|
|
25
29
|
|
|
@@ -65,10 +69,17 @@ inline static BOOL isSnapshotTypeAmongstGivenTypes(id<FBXCElementSnapshot> snaps
|
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
- (id)fb_attributeValue:(NSString *)attribute
|
|
72
|
+
error:(NSError **)error
|
|
68
73
|
{
|
|
74
|
+
NSDate *start = [NSDate date];
|
|
69
75
|
NSDictionary *result = [FBXCAXClientProxy.sharedClient attributesForElement:[self accessibilityElement]
|
|
70
|
-
attributes:@[attribute]
|
|
71
|
-
|
|
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];
|
|
72
83
|
}
|
|
73
84
|
|
|
74
85
|
inline static BOOL areValuesEqual(id value1, id value2);
|
|
@@ -140,29 +151,6 @@ inline static BOOL isNilOrEmpty(id value);
|
|
|
140
151
|
return targetCellSnapshot;
|
|
141
152
|
}
|
|
142
153
|
|
|
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
|
-
|
|
166
154
|
- (NSValue *)fb_hitPoint
|
|
167
155
|
{
|
|
168
156
|
NSError *error;
|
|
@@ -52,7 +52,7 @@ NSString *const FB_SAFARI_APP_NAME = @"Safari";
|
|
|
52
52
|
// and conatins at least one text view
|
|
53
53
|
__block NSUInteger buttonsCount = 0;
|
|
54
54
|
__block NSUInteger textViewsCount = 0;
|
|
55
|
-
id<FBXCElementSnapshot> snapshot = candidate.fb_cachedSnapshot ?: candidate
|
|
55
|
+
id<FBXCElementSnapshot> snapshot = candidate.fb_cachedSnapshot ?: [candidate fb_takeSnapshot:YES];
|
|
56
56
|
[snapshot enumerateDescendantsUsingBlock:^(id<FBXCElementSnapshot> descendant) {
|
|
57
57
|
XCUIElementType curType = descendant.elementType;
|
|
58
58
|
if (curType == XCUIElementTypeButton) {
|
|
@@ -73,7 +73,7 @@ NSString *const FB_SAFARI_APP_NAME = @"Safari";
|
|
|
73
73
|
if (nil == alert) {
|
|
74
74
|
return nil;
|
|
75
75
|
}
|
|
76
|
-
id<FBXCElementSnapshot> alertSnapshot = alert.fb_cachedSnapshot ?: alert
|
|
76
|
+
id<FBXCElementSnapshot> alertSnapshot = alert.fb_cachedSnapshot ?: [alert fb_takeSnapshot:YES];
|
|
77
77
|
|
|
78
78
|
if (alertSnapshot.elementType == XCUIElementTypeAlert) {
|
|
79
79
|
return alert;
|
|
@@ -176,21 +176,7 @@ NSDictionary<NSString *, NSString *> *customExclusionAttributesMap(void) {
|
|
|
176
176
|
|
|
177
177
|
- (NSDictionary *)fb_tree:(nullable NSSet<NSString *> *)excludedAttributes
|
|
178
178
|
{
|
|
179
|
-
|
|
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];
|
|
194
180
|
return [self.class dictionaryForElement:snapshot
|
|
195
181
|
recursive:YES
|
|
196
182
|
excludedAttributes:excludedAttributes];
|
|
@@ -198,9 +184,7 @@ NSDictionary<NSString *, NSString *> *customExclusionAttributesMap(void) {
|
|
|
198
184
|
|
|
199
185
|
- (NSDictionary *)fb_accessibilityTree
|
|
200
186
|
{
|
|
201
|
-
id<FBXCElementSnapshot> snapshot = self
|
|
202
|
-
? self.lastSnapshot
|
|
203
|
-
: [self fb_snapshotWithAllAttributesAndMaxDepth:nil];
|
|
187
|
+
id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:YES];
|
|
204
188
|
return [self.class accessibilityInfoForElement:snapshot];
|
|
205
189
|
}
|
|
206
190
|
|
|
@@ -445,8 +429,8 @@ NSDictionary<NSString *, NSString *> *customExclusionAttributesMap(void) {
|
|
|
445
429
|
|
|
446
430
|
id extractedElement = extractIssueProperty(issue, @"element");
|
|
447
431
|
|
|
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
|
|
450
434
|
? [self.class dictionaryForElement:elementSnapshot
|
|
451
435
|
recursive:NO
|
|
452
436
|
excludedAttributes:customAttributesToExclude]
|
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
- (BOOL)fb_isAccessibilityElement
|
|
20
20
|
{
|
|
21
|
-
id<FBXCElementSnapshot> snapshot = [self
|
|
22
|
-
maxDepth:@1];
|
|
21
|
+
id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:NO];
|
|
23
22
|
return [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_isAccessibilityElement;
|
|
24
23
|
}
|
|
25
24
|
|
|
@@ -33,8 +32,20 @@
|
|
|
33
32
|
if (nil != isAccessibilityElement) {
|
|
34
33
|
return isAccessibilityElement.boolValue;
|
|
35
34
|
}
|
|
36
|
-
|
|
37
|
-
|
|
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;
|
|
38
49
|
}
|
|
39
50
|
|
|
40
51
|
@end
|
|
@@ -13,9 +13,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
13
13
|
|
|
14
14
|
@interface XCUIElement (FBCaching)
|
|
15
15
|
|
|
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
|
-
|
|
19
16
|
@property (nonatomic, readonly) NSString *fb_cacheId;
|
|
20
17
|
|
|
21
18
|
@end
|
|
@@ -18,20 +18,6 @@
|
|
|
18
18
|
|
|
19
19
|
@implementation XCUIElement (FBCaching)
|
|
20
20
|
|
|
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
|
-
|
|
35
21
|
static char XCUIELEMENT_CACHE_ID_KEY;
|
|
36
22
|
|
|
37
23
|
@dynamic fb_cacheId;
|
|
@@ -43,14 +29,7 @@ static char XCUIELEMENT_CACHE_ID_KEY;
|
|
|
43
29
|
return (NSString *)result;
|
|
44
30
|
}
|
|
45
31
|
|
|
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;
|
|
54
33
|
objc_setAssociatedObject(self, &XCUIELEMENT_CACHE_ID_KEY, uid, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
55
34
|
return uid;
|
|
56
35
|
}
|
|
@@ -9,24 +9,23 @@
|
|
|
9
9
|
|
|
10
10
|
#import "XCUIElement+FBIsVisible.h"
|
|
11
11
|
|
|
12
|
-
#import "FBConfiguration.h"
|
|
13
12
|
#import "FBElementUtils.h"
|
|
14
|
-
#import "FBMathUtils.h"
|
|
15
|
-
#import "FBActiveAppDetectionPoint.h"
|
|
16
|
-
#import "FBSession.h"
|
|
17
|
-
#import "FBXCAccessibilityElement.h"
|
|
18
13
|
#import "FBXCodeCompatibility.h"
|
|
19
14
|
#import "FBXCElementSnapshotWrapper+Helpers.h"
|
|
20
15
|
#import "XCUIElement+FBUtilities.h"
|
|
21
|
-
#import "XCUIElement+
|
|
16
|
+
#import "XCUIElement+FBVisibleFrame.h"
|
|
22
17
|
#import "XCTestPrivateSymbols.h"
|
|
23
18
|
|
|
19
|
+
NSNumber* _Nullable fetchSnapshotVisibility(id<FBXCElementSnapshot> snapshot)
|
|
20
|
+
{
|
|
21
|
+
return nil == snapshot.additionalAttributes ? nil : snapshot.additionalAttributes[FB_XCAXAIsVisibleAttribute];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
24
|
@implementation XCUIElement (FBIsVisible)
|
|
25
25
|
|
|
26
26
|
- (BOOL)fb_isVisible
|
|
27
27
|
{
|
|
28
|
-
id<FBXCElementSnapshot> snapshot = [self
|
|
29
|
-
maxDepth:@1];
|
|
28
|
+
id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:NO];
|
|
30
29
|
return [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_isVisible;
|
|
31
30
|
}
|
|
32
31
|
|
|
@@ -34,187 +33,43 @@
|
|
|
34
33
|
|
|
35
34
|
@implementation FBXCElementSnapshotWrapper (FBIsVisible)
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
{
|
|
39
|
-
return [FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot] ?: [NSString stringWithFormat:@"%p", (void *)snapshot];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
- (nullable NSNumber *)fb_cachedVisibilityValue
|
|
36
|
+
- (BOOL)fb_hasVisibleDescendants
|
|
43
37
|
{
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return nil;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
NSDictionary<NSString *, NSNumber *> *result = cache[@(self.generation)];
|
|
50
|
-
if (nil == result) {
|
|
51
|
-
// There is no need to keep the cached data for the previous generations
|
|
52
|
-
[cache removeAllObjects];
|
|
53
|
-
cache[@(self.generation)] = [NSMutableDictionary dictionary];
|
|
54
|
-
return nil;
|
|
55
|
-
}
|
|
56
|
-
return result[[self.class fb_uniqIdWithSnapshot:self.snapshot]];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
- (BOOL)fb_cacheVisibilityWithValue:(BOOL)isVisible
|
|
60
|
-
forAncestors:(nullable NSArray<id<FBXCElementSnapshot>> *)ancestors
|
|
61
|
-
{
|
|
62
|
-
NSMutableDictionary *cache = FBSession.activeSession.elementsVisibilityCache;
|
|
63
|
-
if (nil == cache) {
|
|
64
|
-
return isVisible;
|
|
65
|
-
}
|
|
66
|
-
NSMutableDictionary<NSString *, NSNumber *> *destination = cache[@(self.generation)];
|
|
67
|
-
if (nil == destination) {
|
|
68
|
-
return isVisible;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
NSNumber *visibleObj = [NSNumber numberWithBool:isVisible];
|
|
72
|
-
destination[[self.class fb_uniqIdWithSnapshot:self.snapshot]] = visibleObj;
|
|
73
|
-
if (isVisible && nil != ancestors) {
|
|
74
|
-
// if an element is visible then all its ancestors must be visible as well
|
|
75
|
-
for (id<FBXCElementSnapshot> ancestor in ancestors) {
|
|
76
|
-
NSString *ancestorId = [self.class fb_uniqIdWithSnapshot:ancestor];
|
|
77
|
-
if (nil == destination[ancestorId]) {
|
|
78
|
-
destination[ancestorId] = visibleObj;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return isVisible;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
- (CGRect)fb_frameInContainer:(id<FBXCElementSnapshot>)container
|
|
86
|
-
hierarchyIntersection:(nullable NSValue *)intersectionRectange
|
|
87
|
-
{
|
|
88
|
-
CGRect currentRectangle = nil == intersectionRectange ? self.frame : [intersectionRectange CGRectValue];
|
|
89
|
-
id<FBXCElementSnapshot> parent = self.parent;
|
|
90
|
-
CGRect parentFrame = parent.frame;
|
|
91
|
-
CGRect containerFrame = container.frame;
|
|
92
|
-
if (CGSizeEqualToSize(parentFrame.size, CGSizeZero) &&
|
|
93
|
-
CGPointEqualToPoint(parentFrame.origin, CGPointZero)) {
|
|
94
|
-
// Special case (or XCTest bug). Shift the origin and return immediately after shift
|
|
95
|
-
id<FBXCElementSnapshot> nextParent = parent.parent;
|
|
96
|
-
BOOL isGrandparent = YES;
|
|
97
|
-
while (nextParent && nextParent != container) {
|
|
98
|
-
CGRect nextParentFrame = nextParent.frame;
|
|
99
|
-
if (isGrandparent &&
|
|
100
|
-
CGSizeEqualToSize(nextParentFrame.size, CGSizeZero) &&
|
|
101
|
-
CGPointEqualToPoint(nextParentFrame.origin, CGPointZero)) {
|
|
102
|
-
// Double zero-size container inclusion means that element coordinates are absolute
|
|
103
|
-
return CGRectIntersection(currentRectangle, containerFrame);
|
|
104
|
-
}
|
|
105
|
-
isGrandparent = NO;
|
|
106
|
-
if (!CGPointEqualToPoint(nextParentFrame.origin, CGPointZero)) {
|
|
107
|
-
currentRectangle.origin.x += nextParentFrame.origin.x;
|
|
108
|
-
currentRectangle.origin.y += nextParentFrame.origin.y;
|
|
109
|
-
return CGRectIntersection(currentRectangle, containerFrame);
|
|
110
|
-
}
|
|
111
|
-
nextParent = nextParent.parent;
|
|
112
|
-
}
|
|
113
|
-
return CGRectIntersection(currentRectangle, containerFrame);
|
|
114
|
-
}
|
|
115
|
-
// Skip parent containers if they are outside of the viewport
|
|
116
|
-
CGRect intersectionWithParent = CGRectIntersectsRect(parentFrame, containerFrame) || parent.elementType != XCUIElementTypeOther
|
|
117
|
-
? CGRectIntersection(currentRectangle, parentFrame)
|
|
118
|
-
: currentRectangle;
|
|
119
|
-
if (CGRectIsEmpty(intersectionWithParent) &&
|
|
120
|
-
parent != container &&
|
|
121
|
-
self.elementType == XCUIElementTypeOther) {
|
|
122
|
-
// Special case (or XCTest bug). Shift the origin
|
|
123
|
-
if (CGSizeEqualToSize(parentFrame.size, containerFrame.size) ||
|
|
124
|
-
// The size might be inverted in landscape
|
|
125
|
-
CGSizeEqualToSize(parentFrame.size, CGSizeMake(containerFrame.size.height, containerFrame.size.width)) ||
|
|
126
|
-
CGSizeEqualToSize(self.frame.size, CGSizeZero)) {
|
|
127
|
-
// Covers ActivityListView and RemoteBridgeView cases
|
|
128
|
-
currentRectangle.origin.x += parentFrame.origin.x;
|
|
129
|
-
currentRectangle.origin.y += parentFrame.origin.y;
|
|
130
|
-
return CGRectIntersection(currentRectangle, containerFrame);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
if (CGRectIsEmpty(intersectionWithParent) || parent == container) {
|
|
134
|
-
return intersectionWithParent;
|
|
135
|
-
}
|
|
136
|
-
return [[FBXCElementSnapshotWrapper ensureWrapped:parent] fb_frameInContainer:container
|
|
137
|
-
hierarchyIntersection:[NSValue valueWithCGRect:intersectionWithParent]];
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
- (BOOL)fb_hasAnyVisibleLeafs
|
|
141
|
-
{
|
|
142
|
-
NSArray<id<FBXCElementSnapshot>> *children = self.children;
|
|
143
|
-
if (0 == children.count) {
|
|
144
|
-
return self.fb_isVisible;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
for (id<FBXCElementSnapshot> child in children) {
|
|
148
|
-
if ([FBXCElementSnapshotWrapper ensureWrapped:child].fb_hasAnyVisibleLeafs) {
|
|
38
|
+
for (id<FBXCElementSnapshot> descendant in (self._allDescendants ?: @[])) {
|
|
39
|
+
if ([fetchSnapshotVisibility(descendant) boolValue]) {
|
|
149
40
|
return YES;
|
|
150
41
|
}
|
|
151
42
|
}
|
|
152
|
-
|
|
153
43
|
return NO;
|
|
154
44
|
}
|
|
155
45
|
|
|
156
46
|
- (BOOL)fb_isVisible
|
|
157
47
|
{
|
|
158
|
-
NSNumber *isVisible = self
|
|
159
|
-
if (
|
|
48
|
+
NSNumber *isVisible = fetchSnapshotVisibility(self);
|
|
49
|
+
if (nil != isVisible) {
|
|
160
50
|
return isVisible.boolValue;
|
|
161
51
|
}
|
|
162
|
-
|
|
163
|
-
NSNumber *cachedValue = [self fb_cachedVisibilityValue];
|
|
164
|
-
if (nil != cachedValue) {
|
|
165
|
-
return [cachedValue boolValue];
|
|
166
|
-
}
|
|
167
52
|
|
|
168
|
-
|
|
169
|
-
if
|
|
170
|
-
|
|
53
|
+
// Fetching the attribute value is expensive.
|
|
54
|
+
// Shortcircuit here to save time and assume if any of descendants
|
|
55
|
+
// is already determined as visible then the container should be visible as well
|
|
56
|
+
if ([self fb_hasVisibleDescendants]) {
|
|
57
|
+
return YES;
|
|
171
58
|
}
|
|
172
59
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
60
|
+
NSError *error;
|
|
61
|
+
NSNumber *attributeValue = [self fb_attributeValue:FB_XCAXAIsVisibleAttributeName
|
|
62
|
+
error:&error];
|
|
63
|
+
if (nil != attributeValue) {
|
|
64
|
+
NSMutableDictionary *updatedValue = [NSMutableDictionary dictionaryWithDictionary:self.additionalAttributes ?: @{}];
|
|
65
|
+
[updatedValue setObject:attributeValue forKey:FB_XCAXAIsVisibleAttribute];
|
|
66
|
+
self.snapshot.additionalAttributes = updatedValue.copy;
|
|
67
|
+
return [attributeValue boolValue];
|
|
177
68
|
}
|
|
178
69
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
visibleRect = [self fb_frameInContainer:parentWindow hierarchyIntersection:nil];
|
|
183
|
-
}
|
|
184
|
-
if (CGRectIsEmpty(visibleRect)) {
|
|
185
|
-
return [self fb_cacheVisibilityWithValue:NO forAncestors:ancestors];
|
|
186
|
-
}
|
|
187
|
-
CGPoint midPoint = CGPointMake(visibleRect.origin.x + visibleRect.size.width / 2,
|
|
188
|
-
visibleRect.origin.y + visibleRect.size.height / 2);
|
|
189
|
-
id<FBXCAccessibilityElement> hitElement = [FBActiveAppDetectionPoint axElementWithPoint:midPoint];
|
|
190
|
-
if (nil != hitElement) {
|
|
191
|
-
if (FBIsAXElementEqualToOther(self.accessibilityElement, hitElement)) {
|
|
192
|
-
return [self fb_cacheVisibilityWithValue:YES forAncestors:ancestors];
|
|
193
|
-
}
|
|
194
|
-
for (id<FBXCElementSnapshot> ancestor in ancestors) {
|
|
195
|
-
if (FBIsAXElementEqualToOther(hitElement, ancestor.accessibilityElement)) {
|
|
196
|
-
return [self fb_cacheVisibilityWithValue:YES forAncestors:ancestors];
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
if (self.children.count > 0) {
|
|
201
|
-
if (nil != hitElement) {
|
|
202
|
-
for (id<FBXCElementSnapshot> descendant in self._allDescendants) {
|
|
203
|
-
if (FBIsAXElementEqualToOther(hitElement, descendant.accessibilityElement)) {
|
|
204
|
-
return [self fb_cacheVisibilityWithValue:YES
|
|
205
|
-
forAncestors:[FBXCElementSnapshotWrapper ensureWrapped:descendant].fb_ancestors];
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
if (self.fb_hasAnyVisibleLeafs) {
|
|
210
|
-
return [self fb_cacheVisibilityWithValue:YES forAncestors:ancestors];
|
|
211
|
-
}
|
|
212
|
-
} else if (nil == hitElement) {
|
|
213
|
-
// Sometimes XCTest returns nil for leaf elements hit test even if such elements are hittable
|
|
214
|
-
// Assume such elements are visible if their rectInContainer is visible
|
|
215
|
-
return [self fb_cacheVisibilityWithValue:YES forAncestors:ancestors];
|
|
216
|
-
}
|
|
217
|
-
return [self fb_cacheVisibilityWithValue:NO forAncestors:ancestors];
|
|
70
|
+
NSLog(@"Cannot determine visiblity of %@ natively: %@. Defaulting to: %@",
|
|
71
|
+
self.fb_description, error.description, @(NO));
|
|
72
|
+
return NO;
|
|
218
73
|
}
|
|
219
74
|
|
|
220
75
|
@end
|
|
@@ -23,9 +23,7 @@ static const NSTimeInterval VALUE_CHANGE_TIMEOUT = 2;
|
|
|
23
23
|
|
|
24
24
|
- (BOOL)fb_scrollWithOffset:(CGFloat)relativeHeightOffset error:(NSError **)error
|
|
25
25
|
{
|
|
26
|
-
id<FBXCElementSnapshot> snapshot = self
|
|
27
|
-
? self.lastSnapshot
|
|
28
|
-
: self.fb_takeSnapshot;
|
|
26
|
+
id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:NO];
|
|
29
27
|
NSString *previousValue = snapshot.value;
|
|
30
28
|
XCUICoordinate *startCoord = [self coordinateWithNormalizedOffset:CGVectorMake(0.5, 0.5)];
|
|
31
29
|
XCUICoordinate *endCoord = [startCoord coordinateWithOffset:CGVectorMake(0.0, relativeHeightOffset * snapshot.frame.size.height)];
|