Skip to content

Commit

Permalink
feat: Add support for excluded_attributes in JSON source hierarchy (#953
Browse files Browse the repository at this point in the history
)
  • Loading branch information
swngarg-lt authored Nov 11, 2024
1 parent 6beb1b5 commit 6112223
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 10 deletions.
6 changes: 6 additions & 0 deletions WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (NSDictionary *)fb_tree;

/**
@param excludedAttributes Set of possible attributes to be excluded i.e frame, enabled, visible, accessible, focused. If set to nil or an empty array then no attributes will be excluded from the resulting JSON
@return application elements tree in form of nested dictionaries
*/
- (NSDictionary *)fb_tree:(nullable NSSet<NSString *> *) excludedAttributes;

/**
Return application elements accessibility tree in form of nested dictionaries
*/
Expand Down
53 changes: 44 additions & 9 deletions WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,16 @@ - (BOOL)fb_deactivateWithDuration:(NSTimeInterval)duration error:(NSError **)err
}

- (NSDictionary *)fb_tree
{
return [self fb_tree:nil];
}

- (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];
return [self.class dictionaryForElement:snapshot recursive:YES excludedAttributes:excludedAttributes];
}

- (NSDictionary *)fb_accessibilityTree
Expand All @@ -167,7 +172,9 @@ - (NSDictionary *)fb_accessibilityTree
return [self.class accessibilityInfoForElement:snapshot];
}

+ (NSDictionary *)dictionaryForElement:(id<FBXCElementSnapshot>)snapshot recursive:(BOOL)recursive
+ (NSDictionary *)dictionaryForElement:(id<FBXCElementSnapshot>)snapshot
recursive:(BOOL)recursive
excludedAttributes:(nullable NSSet<NSString *> *) excludedAttributes
{
NSMutableDictionary *info = [[NSMutableDictionary alloc] init];
info[@"type"] = [FBElementTypeTransformer shortStringWithElementType:snapshot.elementType];
Expand All @@ -177,11 +184,35 @@ + (NSDictionary *)dictionaryForElement:(id<FBXCElementSnapshot>)snapshot recursi
info[@"value"] = FBValueOrNull(wrappedSnapshot.wdValue);
info[@"label"] = FBValueOrNull(wrappedSnapshot.wdLabel);
info[@"rect"] = wrappedSnapshot.wdRect;
info[@"frame"] = NSStringFromCGRect(wrappedSnapshot.wdFrame);
info[@"isEnabled"] = [@([wrappedSnapshot isWDEnabled]) stringValue];
info[@"isVisible"] = [@([wrappedSnapshot isWDVisible]) stringValue];
info[@"isAccessible"] = [@([wrappedSnapshot isWDAccessible]) stringValue];
info[@"isFocused"] = [@([wrappedSnapshot isWDFocused]) stringValue];

NSDictionary<NSString *, NSString * (^)(void)> *attributeBlocks = @{
@"frame": ^{
return NSStringFromCGRect(wrappedSnapshot.wdFrame);
},
@"enabled": ^{
return [@([wrappedSnapshot isWDEnabled]) stringValue];
},
@"visible": ^{
return [@([wrappedSnapshot isWDVisible]) stringValue];
},
@"accessible": ^{
return [@([wrappedSnapshot isWDAccessible]) stringValue];
},
@"focused": ^{
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"]) {
info[key] = value;
} else {
info[[NSString stringWithFormat:@"is%@", [key capitalizedString]]] = value;
}
}
}

if (!recursive) {
return info.copy;
Expand All @@ -191,7 +222,9 @@ + (NSDictionary *)dictionaryForElement:(id<FBXCElementSnapshot>)snapshot recursi
if ([childElements count]) {
info[@"children"] = [[NSMutableArray alloc] init];
for (id<FBXCElementSnapshot> childSnapshot in childElements) {
[info[@"children"] addObject:[self dictionaryForElement:childSnapshot recursive:YES]];
[info[@"children"] addObject:[self dictionaryForElement:childSnapshot
recursive:YES
excludedAttributes:excludedAttributes]];
}
}
return info;
Expand Down Expand Up @@ -379,7 +412,9 @@ - (BOOL)fb_dismissKeyboardWithKeyNames:(nullable NSArray<NSString *> *)keyNames
id extractedElement = extractIssueProperty(issue, @"element");

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

[resultArray addObject:@{
@"detailedDescription": extractIssueProperty(issue, @"detailedDescription") ?: @"",
Expand Down
7 changes: 6 additions & 1 deletion WebDriverAgentLib/Commands/FBDebugCommands.m
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ + (NSArray *)routes
withExcludedAttributes:excludedAttributes]
withScope:sourceScope]];
} else if ([sourceType caseInsensitiveCompare:SOURCE_FORMAT_JSON] == NSOrderedSame) {
result = application.fb_tree;
NSString *excludedAttributesString = request.parameters[@"excluded_attributes"];
NSSet<NSString *> *excludedAttributes = (excludedAttributesString == nil)
? nil
: [NSSet setWithArray:[excludedAttributesString componentsSeparatedByString:@","]];

result = [application fb_tree:excludedAttributes];
} else if ([sourceType caseInsensitiveCompare:SOURCE_FORMAT_DESCRIPTION] == NSOrderedSame) {
result = application.fb_descriptionRepresentation;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ - (void)testApplicationTree
XCTAssertNotNil(self.testedApplication.fb_accessibilityTree);
}

- (void)testApplicationTreeAttributesFiltering
{
NSDictionary *applicationTree = [self.testedApplication fb_tree:[NSSet setWithArray:@[@"visible"]]];
XCTAssertNotNil(applicationTree);
XCTAssertNil([applicationTree objectForKey:@"isVisible"], @"'isVisible' key should not be present in the application tree");
}

- (void)testDeactivateApplication
{
NSError *error;
Expand Down

0 comments on commit 6112223

Please sign in to comment.