appium-webdriveragent 9.9.0 → 9.10.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/WebDriverAgent.xcodeproj/project.pbxproj +12 -0
- package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +5 -0
- package/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m +17 -0
- package/WebDriverAgentLib/Info.plist +2 -2
- package/WebDriverAgentLib/Routing/FBElement.h +3 -0
- package/WebDriverAgentLib/Utilities/FBAccessibilityTraits.h +21 -0
- package/WebDriverAgentLib/Utilities/FBAccessibilityTraits.m +62 -0
- package/WebDriverAgentLib/Utilities/FBXPath.m +24 -7
- package/WebDriverAgentTests/IntegrationTests/FBElementAttributeTests.m +46 -0
- package/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m +9 -0
- package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h +2 -0
- package/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m +8 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## [9.10.0](https://github.com/appium/WebDriverAgent/compare/v9.9.0...v9.10.0) (2025-05-27)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* Add accessibility traits of the element ([#1020](https://github.com/appium/WebDriverAgent/issues/1020)) ([9465aaf](https://github.com/appium/WebDriverAgent/commit/9465aafd5e81ef57be7f78e9f2e188d3c1ba1bee))
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
* Use native snapshots if hittable attribute is requested in xPath ([#1023](https://github.com/appium/WebDriverAgent/issues/1023)) ([49d26cb](https://github.com/appium/WebDriverAgent/commit/49d26cb02a8515d1a1b52b65b7cb65512dfd749b))
|
|
10
|
+
|
|
1
11
|
## [9.9.0](https://github.com/appium/WebDriverAgent/compare/v9.8.0...v9.9.0) (2025-05-26)
|
|
2
12
|
|
|
3
13
|
### Features
|
|
@@ -539,6 +539,10 @@
|
|
|
539
539
|
ADBC39981D07842800327304 /* XCUIElementDouble.m in Sources */ = {isa = PBXBuildFile; fileRef = ADBC39971D07842800327304 /* XCUIElementDouble.m */; };
|
|
540
540
|
ADDA07241D6BB2BF001700AC /* FBScrollViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDA07231D6BB2BF001700AC /* FBScrollViewController.m */; };
|
|
541
541
|
ADEF63AF1D09DEBE0070A7E3 /* FBRuntimeUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = ADEF63AE1D09DEBE0070A7E3 /* FBRuntimeUtilsTests.m */; };
|
|
542
|
+
B316351C2DDF0CF5007D9317 /* FBAccessibilityTraits.m in Sources */ = {isa = PBXBuildFile; fileRef = B316351B2DDF0CF5007D9317 /* FBAccessibilityTraits.m */; };
|
|
543
|
+
B316351D2DDF0CF5007D9317 /* FBAccessibilityTraits.m in Sources */ = {isa = PBXBuildFile; fileRef = B316351B2DDF0CF5007D9317 /* FBAccessibilityTraits.m */; };
|
|
544
|
+
B316351F2DDF0D0B007D9317 /* FBAccessibilityTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = B316351E2DDF0D0B007D9317 /* FBAccessibilityTraits.h */; };
|
|
545
|
+
B31635202DDF0D0B007D9317 /* FBAccessibilityTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = B316351E2DDF0D0B007D9317 /* FBAccessibilityTraits.h */; };
|
|
542
546
|
C845206222D5E79400EA68CB /* FBUnattachedAppLauncher.h in Headers */ = {isa = PBXBuildFile; fileRef = C8FB547722D4C1FC00B69954 /* FBUnattachedAppLauncher.h */; };
|
|
543
547
|
C845206322D5E79700EA68CB /* FBUnattachedAppLauncher.m in Sources */ = {isa = PBXBuildFile; fileRef = C8FB547822D4C1FC00B69954 /* FBUnattachedAppLauncher.m */; };
|
|
544
548
|
C8FB547422D3949C00B69954 /* LSApplicationWorkspace.h in Headers */ = {isa = PBXBuildFile; fileRef = C8FB547322D3949C00B69954 /* LSApplicationWorkspace.h */; };
|
|
@@ -1115,6 +1119,8 @@
|
|
|
1115
1119
|
ADDA07221D6BB2BF001700AC /* FBScrollViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBScrollViewController.h; sourceTree = "<group>"; };
|
|
1116
1120
|
ADDA07231D6BB2BF001700AC /* FBScrollViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBScrollViewController.m; sourceTree = "<group>"; };
|
|
1117
1121
|
ADEF63AE1D09DEBE0070A7E3 /* FBRuntimeUtilsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBRuntimeUtilsTests.m; sourceTree = "<group>"; };
|
|
1122
|
+
B316351B2DDF0CF5007D9317 /* FBAccessibilityTraits.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBAccessibilityTraits.m; sourceTree = "<group>"; };
|
|
1123
|
+
B316351E2DDF0D0B007D9317 /* FBAccessibilityTraits.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBAccessibilityTraits.h; sourceTree = "<group>"; };
|
|
1118
1124
|
C8FB547322D3949C00B69954 /* LSApplicationWorkspace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LSApplicationWorkspace.h; sourceTree = "<group>"; };
|
|
1119
1125
|
C8FB547722D4C1FC00B69954 /* FBUnattachedAppLauncher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBUnattachedAppLauncher.h; sourceTree = "<group>"; };
|
|
1120
1126
|
C8FB547822D4C1FC00B69954 /* FBUnattachedAppLauncher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBUnattachedAppLauncher.m; sourceTree = "<group>"; };
|
|
@@ -1979,6 +1985,8 @@
|
|
|
1979
1985
|
EE6B64FC1D0F86EF00E85F5D /* XCTestPrivateSymbols.m */,
|
|
1980
1986
|
633E904A220DEE7F007CADF9 /* XCUIApplicationProcessDelay.h */,
|
|
1981
1987
|
6385F4A5220A40760095BBDB /* XCUIApplicationProcessDelay.m */,
|
|
1988
|
+
B316351B2DDF0CF5007D9317 /* FBAccessibilityTraits.m */,
|
|
1989
|
+
B316351E2DDF0D0B007D9317 /* FBAccessibilityTraits.h */,
|
|
1982
1990
|
);
|
|
1983
1991
|
name = Utilities;
|
|
1984
1992
|
path = WebDriverAgentLib/Utilities;
|
|
@@ -2420,6 +2428,7 @@
|
|
|
2420
2428
|
641EE6A62240C5CA00173FCB /* FBImageProcessor.h in Headers */,
|
|
2421
2429
|
641EE6A72240C5CA00173FCB /* FBSession-Private.h in Headers */,
|
|
2422
2430
|
641EE6A82240C5CA00173FCB /* NSString+FBXMLSafeString.h in Headers */,
|
|
2431
|
+
B316351F2DDF0D0B007D9317 /* FBAccessibilityTraits.h in Headers */,
|
|
2423
2432
|
64E3502F2AC0B6FE005F3ACB /* NSDictionary+FBUtf8SafeDictionary.h in Headers */,
|
|
2424
2433
|
641EE6A92240C5CA00173FCB /* FBCommandStatus.h in Headers */,
|
|
2425
2434
|
71822702258744A400661B83 /* HTTPResponseProxy.h in Headers */,
|
|
@@ -2712,6 +2721,7 @@
|
|
|
2712
2721
|
EE35AD571E3B77D600A02D78 /* XCTestSuiteRun.h in Headers */,
|
|
2713
2722
|
EE35AD701E3B77D600A02D78 /* XCUIElementAsynchronousHandlerWrapper.h in Headers */,
|
|
2714
2723
|
EE35AD4C1E3B77D600A02D78 /* XCTestLog.h in Headers */,
|
|
2724
|
+
B31635202DDF0D0B007D9317 /* FBAccessibilityTraits.h in Headers */,
|
|
2715
2725
|
71BB58E82B96328700CB9BFE /* FBScreenRecordingRequest.h in Headers */,
|
|
2716
2726
|
EE35AD231E3B77D600A02D78 /* UITapGestureRecognizer-RecordingAdditions.h in Headers */,
|
|
2717
2727
|
EE35AD2A1E3B77D600A02D78 /* XCDebugLogDelegate-Protocol.h in Headers */,
|
|
@@ -3173,6 +3183,7 @@
|
|
|
3173
3183
|
641EE6082240C5CA00173FCB /* FBRuntimeUtils.m in Sources */,
|
|
3174
3184
|
641EE6092240C5CA00173FCB /* XCUIElement+FBUtilities.m in Sources */,
|
|
3175
3185
|
641EE60A2240C5CA00173FCB /* FBLogger.m in Sources */,
|
|
3186
|
+
B316351D2DDF0CF5007D9317 /* FBAccessibilityTraits.m in Sources */,
|
|
3176
3187
|
641EE60B2240C5CA00173FCB /* FBCustomCommands.m in Sources */,
|
|
3177
3188
|
71BB58E42B9631F100CB9BFE /* FBScreenRecordingPromise.m in Sources */,
|
|
3178
3189
|
641EE60C2240C5CA00173FCB /* XCUIDevice+FBHelpers.m in Sources */,
|
|
@@ -3257,6 +3268,7 @@
|
|
|
3257
3268
|
71AE3CFA2D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m in Sources */,
|
|
3258
3269
|
EEBBD48C1D47746D00656A81 /* XCUIElement+FBFind.m in Sources */,
|
|
3259
3270
|
EE158ADD1CBD456F00A3E3F0 /* FBResponsePayload.m in Sources */,
|
|
3271
|
+
B316351C2DDF0CF5007D9317 /* FBAccessibilityTraits.m in Sources */,
|
|
3260
3272
|
E444DCB524913C220060D7EB /* RouteRequest.m in Sources */,
|
|
3261
3273
|
C8FB547A22D4C1FC00B69954 /* FBUnattachedAppLauncher.m in Sources */,
|
|
3262
3274
|
EE158ADF1CBD456F00A3E3F0 /* FBRoute.m in Sources */,
|
|
@@ -48,6 +48,7 @@ static NSString* const FBExclusionAttributeAccessible = @"accessible";
|
|
|
48
48
|
static NSString* const FBExclusionAttributeFocused = @"focused";
|
|
49
49
|
static NSString* const FBExclusionAttributePlaceholderValue = @"placeholderValue";
|
|
50
50
|
static NSString* const FBExclusionAttributeNativeFrame = @"nativeFrame";
|
|
51
|
+
static NSString* const FBExclusionAttributeTraits = @"traits";
|
|
51
52
|
|
|
52
53
|
_Nullable id extractIssueProperty(id issue, NSString *propertyName) {
|
|
53
54
|
SEL selector = NSSelectorFromString(propertyName);
|
|
@@ -209,6 +210,7 @@ NSDictionary<NSString *, NSString *> *customExclusionAttributesMap(void) {
|
|
|
209
210
|
FBExclusionAttributeFrame,
|
|
210
211
|
FBExclusionAttributePlaceholderValue,
|
|
211
212
|
FBExclusionAttributeNativeFrame,
|
|
213
|
+
FBExclusionAttributeTraits,
|
|
212
214
|
nil];
|
|
213
215
|
|
|
214
216
|
for (NSString *key in attributeBlocks) {
|
|
@@ -265,6 +267,9 @@ NSDictionary<NSString *, NSString *> *customExclusionAttributesMap(void) {
|
|
|
265
267
|
},
|
|
266
268
|
FBExclusionAttributeFocused: ^{
|
|
267
269
|
return [@([wrappedSnapshot isWDFocused]) stringValue];
|
|
270
|
+
},
|
|
271
|
+
FBExclusionAttributeTraits: ^{
|
|
272
|
+
return wrappedSnapshot.wdTraits;
|
|
268
273
|
}
|
|
269
274
|
} mutableCopy];
|
|
270
275
|
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
#import "FBElementUtils.h"
|
|
23
23
|
#import "XCTestPrivateSymbols.h"
|
|
24
24
|
#import "XCUIHitPointResult.h"
|
|
25
|
+
#import "FBAccessibilityTraits.h"
|
|
25
26
|
|
|
26
27
|
#define BROKEN_RECT CGRectMake(-1, -1, 0, 0)
|
|
27
28
|
|
|
@@ -159,6 +160,22 @@
|
|
|
159
160
|
return self.frame;
|
|
160
161
|
}
|
|
161
162
|
|
|
163
|
+
/**
|
|
164
|
+
Returns a comma-separated string of accessibility traits for the element.
|
|
165
|
+
This method converts the element's accessibility traits bitmask into human-readable strings
|
|
166
|
+
using FBAccessibilityTraitsToStringsArray. The traits represent various accessibility
|
|
167
|
+
characteristics of the element such as Button, Link, Image, etc.
|
|
168
|
+
You can find the list of possible traits in the Apple documentation:
|
|
169
|
+
https://developer.apple.com/documentation/uikit/uiaccessibilitytraits?language=objc
|
|
170
|
+
|
|
171
|
+
@return A comma-separated string of accessibility traits, or an empty string if no traits are set
|
|
172
|
+
*/
|
|
173
|
+
- (NSString *)wdTraits
|
|
174
|
+
{
|
|
175
|
+
NSArray<NSString *> *traits = FBAccessibilityTraitsToStringsArray(self.snapshot.traits);
|
|
176
|
+
return [traits componentsJoinedByString:@", "];
|
|
177
|
+
}
|
|
178
|
+
|
|
162
179
|
- (BOOL)isWDVisible
|
|
163
180
|
{
|
|
164
181
|
return self.fb_isVisible;
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
<key>CFBundlePackageType</key>
|
|
16
16
|
<string>FMWK</string>
|
|
17
17
|
<key>CFBundleShortVersionString</key>
|
|
18
|
-
<string>9.
|
|
18
|
+
<string>9.10.0</string>
|
|
19
19
|
<key>CFBundleSignature</key>
|
|
20
20
|
<string>????</string>
|
|
21
21
|
<key>CFBundleVersion</key>
|
|
22
|
-
<string>9.
|
|
22
|
+
<string>9.10.0</string>
|
|
23
23
|
<key>NSPrincipalClass</key>
|
|
24
24
|
<string/>
|
|
25
25
|
</dict>
|
|
@@ -38,6 +38,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
38
38
|
/*! Element's type */
|
|
39
39
|
@property (nonatomic, readonly, copy) NSString *wdType;
|
|
40
40
|
|
|
41
|
+
/*! Element's accessibility traits as a comma-separated string */
|
|
42
|
+
@property (nonatomic, readonly, copy) NSString *wdTraits;
|
|
43
|
+
|
|
41
44
|
/*! Element's value */
|
|
42
45
|
@property (nonatomic, readonly, strong, nullable) NSString *wdValue;
|
|
43
46
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the BSD-style license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree. An additional grant
|
|
7
|
+
* of patent rights can be found in the PATENTS file in the same directory.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#import <XCTest/XCTest.h>
|
|
11
|
+
|
|
12
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
Converts accessibility traits bitmask to an array of string representations
|
|
16
|
+
@param traits The accessibility traits bitmask
|
|
17
|
+
@return Array of strings representing the accessibility traits
|
|
18
|
+
*/
|
|
19
|
+
NSArray<NSString *> *FBAccessibilityTraitsToStringsArray(unsigned long long traits);
|
|
20
|
+
|
|
21
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the BSD-style license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree. An additional grant
|
|
7
|
+
* of patent rights can be found in the PATENTS file in the same directory.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#import "FBAccessibilityTraits.h"
|
|
11
|
+
|
|
12
|
+
NSArray<NSString *> *FBAccessibilityTraitsToStringsArray(unsigned long long traits) {
|
|
13
|
+
NSMutableArray<NSString *> *traitStringsArray;
|
|
14
|
+
NSNumber *key;
|
|
15
|
+
|
|
16
|
+
static NSDictionary<NSNumber *, NSString *> *traitsMapping;
|
|
17
|
+
static dispatch_once_t onceToken;
|
|
18
|
+
|
|
19
|
+
dispatch_once(&onceToken, ^{
|
|
20
|
+
NSMutableDictionary<NSNumber *, NSString *> *mapping = [@{
|
|
21
|
+
@(UIAccessibilityTraitNone): @"None",
|
|
22
|
+
@(UIAccessibilityTraitButton): @"Button",
|
|
23
|
+
@(UIAccessibilityTraitLink): @"Link",
|
|
24
|
+
@(UIAccessibilityTraitHeader): @"Header",
|
|
25
|
+
@(UIAccessibilityTraitSearchField): @"SearchField",
|
|
26
|
+
@(UIAccessibilityTraitImage): @"Image",
|
|
27
|
+
@(UIAccessibilityTraitSelected): @"Selected",
|
|
28
|
+
@(UIAccessibilityTraitPlaysSound): @"PlaysSound",
|
|
29
|
+
@(UIAccessibilityTraitKeyboardKey): @"KeyboardKey",
|
|
30
|
+
@(UIAccessibilityTraitStaticText): @"StaticText",
|
|
31
|
+
@(UIAccessibilityTraitSummaryElement): @"SummaryElement",
|
|
32
|
+
@(UIAccessibilityTraitNotEnabled): @"NotEnabled",
|
|
33
|
+
@(UIAccessibilityTraitUpdatesFrequently): @"UpdatesFrequently",
|
|
34
|
+
@(UIAccessibilityTraitStartsMediaSession): @"StartsMediaSession",
|
|
35
|
+
@(UIAccessibilityTraitAdjustable): @"Adjustable",
|
|
36
|
+
@(UIAccessibilityTraitAllowsDirectInteraction): @"AllowsDirectInteraction",
|
|
37
|
+
@(UIAccessibilityTraitCausesPageTurn): @"CausesPageTurn",
|
|
38
|
+
@(UIAccessibilityTraitTabBar): @"TabBar"
|
|
39
|
+
} mutableCopy];
|
|
40
|
+
|
|
41
|
+
#if __clang_major__ >= 16
|
|
42
|
+
// Add iOS 17.0 specific traits if available
|
|
43
|
+
if (@available(iOS 17.0, *)) {
|
|
44
|
+
[mapping addEntriesFromDictionary:@{
|
|
45
|
+
@(UIAccessibilityTraitToggleButton): @"ToggleButton",
|
|
46
|
+
@(UIAccessibilityTraitSupportsZoom): @"SupportsZoom"
|
|
47
|
+
}];
|
|
48
|
+
}
|
|
49
|
+
#endif
|
|
50
|
+
|
|
51
|
+
traitsMapping = [mapping copy];
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
traitStringsArray = [NSMutableArray array];
|
|
55
|
+
for (key in traitsMapping) {
|
|
56
|
+
if (traits & [key unsignedLongLongValue] && nil != traitsMapping[key]) {
|
|
57
|
+
[traitStringsArray addObject:(id)traitsMapping[key]];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return [traitStringsArray copy];
|
|
62
|
+
}
|
|
@@ -146,7 +146,8 @@ static NSString *const topNodeIndexPath = @"top";
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
if (rc >= 0) {
|
|
149
|
-
|
|
149
|
+
[self waitUntilStableWithElement:root];
|
|
150
|
+
rc = [self xmlRepresentationWithRootElement:[self snapshotWithRoot:root useNative:NO]
|
|
150
151
|
writer:writer
|
|
151
152
|
elementStore:nil
|
|
152
153
|
query:nil
|
|
@@ -196,17 +197,23 @@ static NSString *const topNodeIndexPath = @"top";
|
|
|
196
197
|
int rc = xmlTextWriterStartDocument(writer, NULL, _UTF8Encoding, NULL);
|
|
197
198
|
id<FBXCElementSnapshot> lookupScopeSnapshot = nil;
|
|
198
199
|
id<FBXCElementSnapshot> contextRootSnapshot = nil;
|
|
200
|
+
BOOL useNativeSnapshot = nil == xpathQuery
|
|
201
|
+
? NO
|
|
202
|
+
: [[self.class elementAttributesWithXPathQuery:xpathQuery] containsObject:FBHittableAttribute.class];
|
|
199
203
|
if (rc < 0) {
|
|
200
204
|
[FBLogger logFmt:@"Failed to invoke libxml2>xmlTextWriterStartDocument. Error code: %d", rc];
|
|
201
205
|
} else {
|
|
206
|
+
[self waitUntilStableWithElement:root];
|
|
202
207
|
if (FBConfiguration.limitXpathContextScope) {
|
|
203
|
-
lookupScopeSnapshot = [self snapshotWithRoot:root];
|
|
208
|
+
lookupScopeSnapshot = [self snapshotWithRoot:root useNative:useNativeSnapshot];
|
|
204
209
|
} else {
|
|
205
210
|
if ([root isKindOfClass:XCUIElement.class]) {
|
|
206
|
-
lookupScopeSnapshot = [self snapshotWithRoot:[(XCUIElement *)root application]
|
|
211
|
+
lookupScopeSnapshot = [self snapshotWithRoot:[(XCUIElement *)root application]
|
|
212
|
+
useNative:useNativeSnapshot];
|
|
207
213
|
contextRootSnapshot = [root isKindOfClass:XCUIApplication.class]
|
|
208
214
|
? nil
|
|
209
|
-
: ([(XCUIElement *)root lastSnapshot] ?: [(XCUIElement *)root
|
|
215
|
+
: ([(XCUIElement *)root lastSnapshot] ?: [self snapshotWithRoot:(XCUIElement *)root
|
|
216
|
+
useNative:useNativeSnapshot]);
|
|
210
217
|
} else {
|
|
211
218
|
lookupScopeSnapshot = (id<FBXCElementSnapshot>)root;
|
|
212
219
|
contextRootSnapshot = nil == lookupScopeSnapshot.parent ? nil : (id<FBXCElementSnapshot>)root;
|
|
@@ -483,19 +490,29 @@ static NSString *const topNodeIndexPath = @"top";
|
|
|
483
490
|
}
|
|
484
491
|
|
|
485
492
|
+ (id<FBXCElementSnapshot>)snapshotWithRoot:(id<FBElement>)root
|
|
493
|
+
useNative:(BOOL)useNative
|
|
486
494
|
{
|
|
487
495
|
if (![root isKindOfClass:XCUIElement.class]) {
|
|
488
496
|
return (id<FBXCElementSnapshot>)root;
|
|
489
497
|
}
|
|
490
498
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
499
|
+
if (useNative) {
|
|
500
|
+
return [(XCUIElement *)root fb_nativeSnapshot];
|
|
501
|
+
}
|
|
494
502
|
return [root isKindOfClass:XCUIApplication.class]
|
|
495
503
|
? [(XCUIElement *)root fb_standardSnapshot]
|
|
496
504
|
: [(XCUIElement *)root fb_customSnapshot];
|
|
497
505
|
}
|
|
498
506
|
|
|
507
|
+
+ (void)waitUntilStableWithElement:(id<FBElement>)root
|
|
508
|
+
{
|
|
509
|
+
if ([root isKindOfClass:XCUIElement.class]) {
|
|
510
|
+
// If the app is not idle state while we retrieve the visiblity state
|
|
511
|
+
// then the snapshot retrieval operation might freeze and time out
|
|
512
|
+
[[(XCUIElement *)root application] fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout];
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
499
516
|
@end
|
|
500
517
|
|
|
501
518
|
|
|
@@ -96,6 +96,52 @@
|
|
|
96
96
|
XCTAssertEqual(element2.wdIndex, 0);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
- (void)testAccessibilityTraits
|
|
100
|
+
{
|
|
101
|
+
XCUIElement *button = self.testedApplication.buttons.firstMatch;
|
|
102
|
+
XCTAssertTrue(button.exists);
|
|
103
|
+
NSArray *buttonTraits = [button.wdTraits componentsSeparatedByString:@", "];
|
|
104
|
+
NSArray *expectedButtonTraits = @[@"Button"];
|
|
105
|
+
XCTAssertEqual(buttonTraits.count, expectedButtonTraits.count, @"Button should have exactly 1 trait");
|
|
106
|
+
XCTAssertEqualObjects(buttonTraits, expectedButtonTraits);
|
|
107
|
+
XCTAssertEqualObjects(button.wdType, @"XCUIElementTypeButton");
|
|
108
|
+
|
|
109
|
+
XCUIElement *toggle = self.testedApplication.switches.firstMatch;
|
|
110
|
+
XCTAssertTrue(toggle.exists);
|
|
111
|
+
|
|
112
|
+
// iOS 17.0 specific traits if available
|
|
113
|
+
NSArray *toggleTraits = [toggle.wdTraits componentsSeparatedByString:@", "];
|
|
114
|
+
NSArray *expectedToggleTraits;
|
|
115
|
+
|
|
116
|
+
#if __clang_major__ >= 16
|
|
117
|
+
if (@available(iOS 17.0, *)) {
|
|
118
|
+
expectedToggleTraits = @[@"ToggleButton", @"Button"];
|
|
119
|
+
XCTAssertEqual(toggleTraits.count, 2, @"Toggle should have exactly 2 traits on iOS 17+");
|
|
120
|
+
}
|
|
121
|
+
#else
|
|
122
|
+
expectedToggleTraits = @[@"Button"];
|
|
123
|
+
XCTAssertEqual(toggleTraits.count, 1, @"Toggle should have exactly 1 trait on iOS < 17");
|
|
124
|
+
#endif
|
|
125
|
+
XCTAssertEqualObjects(toggleTraits, expectedToggleTraits);
|
|
126
|
+
XCTAssertEqualObjects(toggle.wdType, @"XCUIElementTypeSwitch");
|
|
127
|
+
|
|
128
|
+
XCUIElement *slider = self.testedApplication.sliders.firstMatch;
|
|
129
|
+
XCTAssertTrue(slider.exists);
|
|
130
|
+
NSArray *sliderTraits = [slider.wdTraits componentsSeparatedByString:@", "];
|
|
131
|
+
NSArray *expectedSliderTraits = @[@"Adjustable"];
|
|
132
|
+
XCTAssertEqual(sliderTraits.count, expectedSliderTraits.count, @"Slider should have exactly 1 trait");
|
|
133
|
+
XCTAssertEqualObjects(sliderTraits, expectedSliderTraits);
|
|
134
|
+
XCTAssertEqualObjects(slider.wdType, @"XCUIElementTypeSlider");
|
|
135
|
+
|
|
136
|
+
XCUIElement *picker = self.testedApplication.pickerWheels.firstMatch;
|
|
137
|
+
XCTAssertTrue(picker.exists);
|
|
138
|
+
NSArray *pickerTraits = [picker.wdTraits componentsSeparatedByString:@", "];
|
|
139
|
+
NSArray *expectedPickerTraits = @[@"Adjustable"];
|
|
140
|
+
XCTAssertEqual(pickerTraits.count, expectedPickerTraits.count, @"Picker should have exactly 1 trait");
|
|
141
|
+
XCTAssertEqualObjects(pickerTraits, expectedPickerTraits);
|
|
142
|
+
XCTAssertEqualObjects(picker.wdType, @"XCUIElementTypePickerWheel");
|
|
143
|
+
}
|
|
144
|
+
|
|
99
145
|
- (void)testTextFieldAttributes
|
|
100
146
|
{
|
|
101
147
|
XCUIElement *element = self.testedApplication.textFields[@"Value"];
|
|
@@ -461,4 +461,13 @@
|
|
|
461
461
|
XCTAssertFalse(matchingSnapshots.lastObject.fb_isVisible);
|
|
462
462
|
}
|
|
463
463
|
|
|
464
|
+
- (void)testNonHittableDescendantWithXPathQuery
|
|
465
|
+
{
|
|
466
|
+
NSArray<XCUIElement *> *matchingSnapshots = [self.testedApplication fb_descendantsMatchingXPathQuery:@"//XCUIElementTypeStaticText[@hittable='false']"
|
|
467
|
+
shouldReturnAfterFirstMatch:NO];
|
|
468
|
+
XCTAssertGreaterThan(matchingSnapshots.count, 1);
|
|
469
|
+
XCTAssertEqual(matchingSnapshots.lastObject.elementType, XCUIElementTypeStaticText);
|
|
470
|
+
XCTAssertFalse(matchingSnapshots.lastObject.fb_isVisible);
|
|
471
|
+
}
|
|
472
|
+
|
|
464
473
|
@end
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
@property (nonatomic, strong, readwrite, nullable) NSString *wdValue;
|
|
29
29
|
@property (nonatomic, readwrite, getter=isWDEnabled) BOOL wdEnabled;
|
|
30
30
|
@property (nonatomic, readwrite, getter=isWDSelected) BOOL wdSelected;
|
|
31
|
+
@property (nonatomic, readwrite, assign) CGRect wdNativeFrame;
|
|
31
32
|
@property (nonatomic, readwrite) NSUInteger wdIndex;
|
|
32
33
|
@property (nonatomic, readwrite, getter=isWDVisible) BOOL wdVisible;
|
|
33
34
|
@property (nonatomic, readwrite, getter=isWDAccessible) BOOL wdAccessible;
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
@property (copy, nonnull) NSArray *children;
|
|
38
39
|
@property (nonatomic, readwrite, assign) XCUIElementType elementType;
|
|
39
40
|
@property (nonatomic, readwrite, getter=isWDAccessibilityContainer) BOOL wdAccessibilityContainer;
|
|
41
|
+
@property (nonatomic, copy, readwrite, nullable) NSString *wdTraits;
|
|
40
42
|
|
|
41
43
|
- (void)resolve;
|
|
42
44
|
- (id _Nonnull)fb_standardSnapshot;
|
|
@@ -19,11 +19,13 @@
|
|
|
19
19
|
{
|
|
20
20
|
self = [super init];
|
|
21
21
|
if (self) {
|
|
22
|
-
self.wdFrame =
|
|
22
|
+
self.wdFrame = CGRectZero;
|
|
23
|
+
self.wdNativeFrame = CGRectZero;
|
|
23
24
|
self.wdName = @"testName";
|
|
24
25
|
self.wdLabel = @"testLabel";
|
|
25
26
|
self.wdValue = @"magicValue";
|
|
26
27
|
self.wdPlaceholderValue = @"testPlaceholderValue";
|
|
28
|
+
self.wdTraits = @"testTraits";
|
|
27
29
|
self.wdVisible = YES;
|
|
28
30
|
self.wdAccessible = YES;
|
|
29
31
|
self.wdEnabled = YES;
|
|
@@ -94,4 +96,9 @@
|
|
|
94
96
|
return self.wdUID;
|
|
95
97
|
}
|
|
96
98
|
|
|
99
|
+
- (NSString *)wdTraits
|
|
100
|
+
{
|
|
101
|
+
return self.wdTraits;
|
|
102
|
+
}
|
|
103
|
+
|
|
97
104
|
@end
|