40
40
41
41
static NSString * const FBUnknownBundleId = @" unknown" ;
42
42
43
+ static NSString * const FBExclusionAttributeFrame = @" frame" ;
44
+ static NSString * const FBExclusionAttributeEnabled = @" enabled" ;
45
+ static NSString * const FBExclusionAttributeVisible = @" visible" ;
46
+ static NSString * const FBExclusionAttributeAccessible = @" accessible" ;
47
+ static NSString * const FBExclusionAttributeFocused = @" focused" ;
48
+
49
+
43
50
_Nullable id extractIssueProperty (id issue, NSString *propertyName) {
44
51
SEL selector = NSSelectorFromString (propertyName);
45
52
NSMethodSignature *methodSignature = [issue methodSignatureForSelector: selector];
@@ -88,6 +95,17 @@ _Nullable id extractIssueProperty(id issue, NSString *propertyName) {
88
95
return result;
89
96
}
90
97
98
+ NSDictionary <NSString *, NSString *> *customExclusionAttributesMap (void ) {
99
+ static dispatch_once_t onceToken;
100
+ static NSDictionary *result;
101
+ dispatch_once (&onceToken, ^{
102
+ result = @{
103
+ FBExclusionAttributeVisible: FB_XCAXAIsVisibleAttributeName,
104
+ FBExclusionAttributeAccessible: FB_XCAXAIsElementAttributeName,
105
+ };
106
+ });
107
+ return result;
108
+ }
91
109
92
110
@implementation XCUIApplication (FBHelpers)
93
111
@@ -156,12 +174,26 @@ - (NSDictionary *)fb_tree
156
174
return [self fb_tree: nil ];
157
175
}
158
176
159
- - (NSDictionary *)fb_tree : (nullable NSSet <NSString *> *) excludedAttributes
177
+ - (NSDictionary *)fb_tree : (nullable NSSet <NSString *> *)excludedAttributes
160
178
{
161
- id <FBXCElementSnapshot> snapshot = self.fb_isResolvedFromCache .boolValue
162
- ? self.lastSnapshot
163
- : [self fb_snapshotWithAllAttributesAndMaxDepth: nil ];
164
- return [self .class dictionaryForElement: snapshot recursive: YES excludedAttributes: excludedAttributes];
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 ];
194
+ return [self .class dictionaryForElement: snapshot
195
+ recursive: YES
196
+ excludedAttributes: excludedAttributes];
165
197
}
166
198
167
199
- (NSDictionary *)fb_accessibilityTree
@@ -174,7 +206,7 @@ - (NSDictionary *)fb_accessibilityTree
174
206
175
207
+ (NSDictionary *)dictionaryForElement : (id <FBXCElementSnapshot>)snapshot
176
208
recursive : (BOOL )recursive
177
- excludedAttributes : (nullable NSSet <NSString *> *) excludedAttributes
209
+ excludedAttributes : (nullable NSSet <NSString *> *)excludedAttributes
178
210
{
179
211
NSMutableDictionary *info = [[NSMutableDictionary alloc ] init ];
180
212
info[@" type" ] = [FBElementTypeTransformer shortStringWithElementType: snapshot.elementType];
@@ -186,27 +218,27 @@ + (NSDictionary *)dictionaryForElement:(id<FBXCElementSnapshot>)snapshot
186
218
info[@" rect" ] = wrappedSnapshot.wdRect ;
187
219
188
220
NSDictionary <NSString *, NSString * (^)(void )> *attributeBlocks = @{
189
- @" frame " : ^{
221
+ FBExclusionAttributeFrame : ^{
190
222
return NSStringFromCGRect(wrappedSnapshot.wdFrame );
191
223
},
192
- @" enabled " : ^{
224
+ FBExclusionAttributeEnabled : ^{
193
225
return [@([wrappedSnapshot isWDEnabled ]) stringValue ];
194
226
},
195
- @" visible " : ^{
227
+ FBExclusionAttributeVisible : ^{
196
228
return [@([wrappedSnapshot isWDVisible ]) stringValue ];
197
229
},
198
- @" accessible " : ^{
230
+ FBExclusionAttributeAccessible : ^{
199
231
return [@([wrappedSnapshot isWDAccessible ]) stringValue ];
200
232
},
201
- @" focused " : ^{
233
+ FBExclusionAttributeFocused : ^{
202
234
return [@([wrappedSnapshot isWDFocused ]) stringValue ];
203
235
}
204
236
};
205
237
206
238
for (NSString *key in attributeBlocks) {
207
239
if (excludedAttributes == nil || ![excludedAttributes containsObject: key]) {
208
240
NSString *value = ((NSString * (^)(void ))attributeBlocks[key])();
209
- if ([key isEqualToString: @" frame " ]) {
241
+ if ([key isEqualToString: FBExclusionAttributeFrame ]) {
210
242
info[key] = value;
211
243
} else {
212
244
info[[NSString stringWithFormat: @" is%@ " , [key capitalizedString ]]] = value;
@@ -396,6 +428,8 @@ - (BOOL)fb_dismissKeyboardWithKeyNames:(nullable NSArray<NSString *> *)keyNames
396
428
return nil ;
397
429
}
398
430
431
+ // These custom attributes could take too long to fetch, thus excluded
432
+ NSSet *customAttributesToExclude = [NSSet setWithArray: [customExclusionAttributesMap () allKeys ]];
399
433
NSMutableArray <NSDictionary *> *resultArray = [NSMutableArray array ];
400
434
NSMethodSignature *methodSignature = [self methodSignatureForSelector: selector];
401
435
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: methodSignature];
@@ -411,9 +445,11 @@ - (BOOL)fb_dismissKeyboardWithKeyNames:(nullable NSArray<NSString *> *)keyNames
411
445
412
446
id extractedElement = extractIssueProperty (issue, @" element" );
413
447
414
- id <FBXCElementSnapshot> elementSnapshot = [extractedElement fb_takeSnapshot ];
448
+ id <FBXCElementSnapshot> elementSnapshot = [extractedElement fb_cachedSnapshot ] ?: [extractedElement fb_takeSnapshot ];
415
449
NSDictionary *elementAttributes = elementSnapshot
416
- ? [self .class dictionaryForElement: elementSnapshot recursive: NO excludedAttributes: nil ]
450
+ ? [self .class dictionaryForElement: elementSnapshot
451
+ recursive: NO
452
+ excludedAttributes: customAttributesToExclude]
417
453
: @{};
418
454
419
455
[resultArray addObject: @{
0 commit comments