Skip to content

Commit

Permalink
chore: Exclude element visibility and accessibility info from the acc…
Browse files Browse the repository at this point in the history
…essibility audit details (#968)
  • Loading branch information
mykola-mokhnach authored Jan 13, 2025
1 parent a1b5af6 commit f62afc3
Showing 1 changed file with 50 additions and 14 deletions.
64 changes: 50 additions & 14 deletions WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@

static NSString* const FBUnknownBundleId = @"unknown";

static NSString* const FBExclusionAttributeFrame = @"frame";
static NSString* const FBExclusionAttributeEnabled = @"enabled";
static NSString* const FBExclusionAttributeVisible = @"visible";
static NSString* const FBExclusionAttributeAccessible = @"accessible";
static NSString* const FBExclusionAttributeFocused = @"focused";


_Nullable id extractIssueProperty(id issue, NSString *propertyName) {
SEL selector = NSSelectorFromString(propertyName);
NSMethodSignature *methodSignature = [issue methodSignatureForSelector:selector];
Expand Down Expand Up @@ -88,6 +95,17 @@ _Nullable id extractIssueProperty(id issue, NSString *propertyName) {
return result;
}

NSDictionary<NSString *, NSString *> *customExclusionAttributesMap(void) {
static dispatch_once_t onceToken;
static NSDictionary *result;
dispatch_once(&onceToken, ^{
result = @{
FBExclusionAttributeVisible: FB_XCAXAIsVisibleAttributeName,
FBExclusionAttributeAccessible: FB_XCAXAIsElementAttributeName,
};
});
return result;
}

@implementation XCUIApplication (FBHelpers)

Expand Down Expand Up @@ -156,12 +174,26 @@ - (NSDictionary *)fb_tree
return [self fb_tree:nil];
}

- (NSDictionary *)fb_tree:(nullable NSSet<NSString *> *) excludedAttributes
- (NSDictionary *)fb_tree:(nullable NSSet<NSString *> *)excludedAttributes
{
id<FBXCElementSnapshot> snapshot = self.fb_isResolvedFromCache.boolValue
? self.lastSnapshot
: [self fb_snapshotWithAllAttributesAndMaxDepth:nil];
return [self.class dictionaryForElement:snapshot recursive:YES excludedAttributes:excludedAttributes];
// This set includes XCTest-specific internal attribute names,
// while the `excludedAttributes` arg contains human-readable ones
NSMutableSet* includedAttributeNames = [NSMutableSet setWithArray:FBCustomAttributeNames()];
[includedAttributeNames addObjectsFromArray:FBStandardAttributeNames()];
if (nil != excludedAttributes) {
for (NSString *attr in excludedAttributes) {
NSString *mappedName = [customExclusionAttributesMap() objectForKey:attr];
if (nil != mappedName) {
[includedAttributeNames removeObject:attr];
}
}
}
id<FBXCElementSnapshot> snapshot = nil == excludedAttributes
? [self fb_snapshotWithAllAttributesAndMaxDepth:nil]
: [self fb_snapshotWithAttributes:[includedAttributeNames allObjects] maxDepth:nil];
return [self.class dictionaryForElement:snapshot
recursive:YES
excludedAttributes:excludedAttributes];
}

- (NSDictionary *)fb_accessibilityTree
Expand All @@ -174,7 +206,7 @@ - (NSDictionary *)fb_accessibilityTree

+ (NSDictionary *)dictionaryForElement:(id<FBXCElementSnapshot>)snapshot
recursive:(BOOL)recursive
excludedAttributes:(nullable NSSet<NSString *> *) excludedAttributes
excludedAttributes:(nullable NSSet<NSString *> *)excludedAttributes
{
NSMutableDictionary *info = [[NSMutableDictionary alloc] init];
info[@"type"] = [FBElementTypeTransformer shortStringWithElementType:snapshot.elementType];
Expand All @@ -186,27 +218,27 @@ + (NSDictionary *)dictionaryForElement:(id<FBXCElementSnapshot>)snapshot
info[@"rect"] = wrappedSnapshot.wdRect;

NSDictionary<NSString *, NSString * (^)(void)> *attributeBlocks = @{
@"frame": ^{
FBExclusionAttributeFrame: ^{
return NSStringFromCGRect(wrappedSnapshot.wdFrame);
},
@"enabled": ^{
FBExclusionAttributeEnabled: ^{
return [@([wrappedSnapshot isWDEnabled]) stringValue];
},
@"visible": ^{
FBExclusionAttributeVisible: ^{
return [@([wrappedSnapshot isWDVisible]) stringValue];
},
@"accessible": ^{
FBExclusionAttributeAccessible: ^{
return [@([wrappedSnapshot isWDAccessible]) stringValue];
},
@"focused": ^{
FBExclusionAttributeFocused: ^{
return [@([wrappedSnapshot isWDFocused]) stringValue];
}
};

for (NSString *key in attributeBlocks) {
if (excludedAttributes == nil || ![excludedAttributes containsObject:key]) {
NSString *value = ((NSString * (^)(void))attributeBlocks[key])();
if ([key isEqualToString:@"frame"]) {
if ([key isEqualToString:FBExclusionAttributeFrame]) {
info[key] = value;
} else {
info[[NSString stringWithFormat:@"is%@", [key capitalizedString]]] = value;
Expand Down Expand Up @@ -396,6 +428,8 @@ - (BOOL)fb_dismissKeyboardWithKeyNames:(nullable NSArray<NSString *> *)keyNames
return nil;
}

// These custom attributes could take too long to fetch, thus excluded
NSSet *customAttributesToExclude = [NSSet setWithArray:[customExclusionAttributesMap() allKeys]];
NSMutableArray<NSDictionary *> *resultArray = [NSMutableArray array];
NSMethodSignature *methodSignature = [self methodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
Expand All @@ -411,9 +445,11 @@ - (BOOL)fb_dismissKeyboardWithKeyNames:(nullable NSArray<NSString *> *)keyNames

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

id<FBXCElementSnapshot> elementSnapshot = [extractedElement fb_takeSnapshot];
id<FBXCElementSnapshot> elementSnapshot = [extractedElement fb_cachedSnapshot] ?: [extractedElement fb_takeSnapshot];
NSDictionary *elementAttributes = elementSnapshot
? [self.class dictionaryForElement:elementSnapshot recursive:NO excludedAttributes:nil]
? [self.class dictionaryForElement:elementSnapshot
recursive:NO
excludedAttributes:customAttributesToExclude]
: @{};

[resultArray addObject:@{
Expand Down

0 comments on commit f62afc3

Please sign in to comment.