Skip to content

Commit

Permalink
Remove custom stuff for good
Browse files Browse the repository at this point in the history
  • Loading branch information
mykola-mokhnach committed Jan 15, 2025
1 parent 66f471d commit a36c190
Show file tree
Hide file tree
Showing 16 changed files with 102 additions and 186 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,14 @@ NS_ASSUME_NONNULL_BEGIN
@param attribute attribute's accessibility identifier. Can be one of
`XC_kAXXCAttribute`-prefixed attribute names.
@return value for given accessibility property identifier
@param timeout The maximum time is flota seconds to wait until XCTest/Accessbility framework
returns the value of the requested attribute
@param error Error instance in case of a failure
@return value for given accessibility property identifier or nil in case of failure
*/
- (nullable id)fb_attributeValue:(NSString *)attribute;
- (nullable id)fb_attributeValue:(NSString *)attribute
timeout:(NSTimeInterval)timeout
error:(NSError **)error;

/**
Method used to determine whether given element matches receiver by comparing it's parameters except frame.
Expand Down
19 changes: 15 additions & 4 deletions WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#import "XCUIElement+FBWebDriverAttributes.h"
#import "XCUIHitPointResult.h"

#define VisibleFrameFetchTimeout 0.3

inline static BOOL isSnapshotTypeAmongstGivenTypes(id<FBXCElementSnapshot> snapshot,
NSArray<NSNumber *> *types);

Expand Down Expand Up @@ -65,10 +67,17 @@ - (NSString *)fb_description
}

- (id)fb_attributeValue:(NSString *)attribute
timeout:(NSTimeInterval)timeout
error:(NSError **)error
{
BOOL isTimeoutSet = [FBXCAXClientProxy.sharedClient setAXTimeout:timeout error:nil];
NSDictionary *result = [FBXCAXClientProxy.sharedClient attributesForElement:[self accessibilityElement]
attributes:@[attribute]];
return result[attribute];
attributes:@[attribute]
error:error];
if (isTimeoutSet) {
[FBXCAXClientProxy.sharedClient setAXTimeout:FBDefaultAxTimeout error:nil];
}
return [result objectForKey:attribute];
}

inline static BOOL areValuesEqual(id value1, id value2);
Expand Down Expand Up @@ -146,8 +155,10 @@ - (CGRect)fb_visibleFrameWithFallback
if (!CGRectIsEmpty(thisVisibleFrame)) {
return thisVisibleFrame;
}

NSDictionary *visibleFrameDict = (NSDictionary*)[self fb_attributeValue:@"XC_kAXXCAttributeVisibleFrame"];

NSDictionary *visibleFrameDict = [self fb_attributeValue:FB_XCAXAVisibleFrameAttributeName
timeout:VisibleFrameFetchTimeout
error:nil];
if (visibleFrameDict == nil) {
return thisVisibleFrame;
}
Expand Down
19 changes: 2 additions & 17 deletions WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m
Original file line number Diff line number Diff line change
Expand Up @@ -176,30 +176,15 @@ - (NSDictionary *)fb_tree

- (NSDictionary *)fb_tree:(nullable NSSet<NSString *> *)excludedAttributes
{
// This set includes XCTest-specific internal attribute names,
// while the `excludedAttributes` arg contains human-readable ones
NSMutableSet* includedAttributeNames = [NSMutableSet setWithArray:FBCustomAttributeNames()];
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_snapshotWithAllAttributes:YES]
: [self fb_snapshotWithCustomAttributes:[includedAttributeNames allObjects]
exludingStandardAttributes:NO
inDepth:YES];
id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:YES];
return [self.class dictionaryForElement:snapshot
recursive:YES
excludedAttributes:excludedAttributes];
}

- (NSDictionary *)fb_accessibilityTree
{
id<FBXCElementSnapshot> snapshot = [self fb_snapshotWithAllAttributes:YES];
id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:YES];
return [self.class accessibilityInfoForElement:snapshot];
}

Expand Down
19 changes: 14 additions & 5 deletions WebDriverAgentLib/Categories/XCUIElement+FBAccessibility.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
#import "XCUIElement+FBUtilities.h"
#import "FBXCElementSnapshotWrapper+Helpers.h"

#define AX_FETCH_TIMEOUT 0.3

@implementation XCUIElement (FBAccessibility)

- (BOOL)fb_isAccessibilityElement
{
id<FBXCElementSnapshot> snapshot = [self fb_snapshotWithCustomAttributes:@[FB_XCAXAIsElementAttributeName]
exludingStandardAttributes:YES
inDepth:NO];
id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:NO];
return [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_isAccessibilityElement;
}

Expand All @@ -34,8 +34,17 @@ - (BOOL)fb_isAccessibilityElement
if (nil != isAccessibilityElement) {
return isAccessibilityElement.boolValue;
}

return [(NSNumber *)[self fb_attributeValue:FB_XCAXAIsElementAttributeName] boolValue];

NSError *error = nil;
NSNumber *attributeValue = [self fb_attributeValue:FB_XCAXAIsElementAttributeName
timeout:AX_FETCH_TIMEOUT
error:&error];
if (nil != attributeValue && nil == error) {
return [attributeValue boolValue];
}

NSLog(@"Cannot determine element accessibility: %@", error.description);
return NO;
}

@end
50 changes: 39 additions & 11 deletions WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,68 @@

#import "XCUIElement+FBIsVisible.h"

#import "FBConfiguration.h"
#import "FBElementUtils.h"
#import "FBMathUtils.h"
#import "FBActiveAppDetectionPoint.h"
#import "FBSession.h"
#import "FBXCAccessibilityElement.h"
#import "FBXCodeCompatibility.h"
#import "FBXCElementSnapshotWrapper+Helpers.h"
#import "XCUIElement+FBUtilities.h"
#import "XCUIElement+FBUID.h"
#import "XCTestPrivateSymbols.h"

#define AX_FETCH_TIMEOUT 0.3

NSNumber* _Nullable fetchSnapshotVisibility(id<FBXCElementSnapshot> snapshot)
{
return nil == snapshot.additionalAttributes ? nil : snapshot.additionalAttributes[FB_XCAXAIsVisibleAttribute];
}

@implementation XCUIElement (FBIsVisible)

- (BOOL)fb_isVisible
{
id<FBXCElementSnapshot> snapshot = [self fb_snapshotWithCustomAttributes:@[FB_XCAXAIsVisibleAttributeName]
exludingStandardAttributes:YES
inDepth:NO];
id<FBXCElementSnapshot> snapshot = [self fb_takeSnapshot:NO];
return [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_isVisible;
}

@end

@implementation FBXCElementSnapshotWrapper (FBIsVisible)

- (BOOL)fb_hasVisibleAncestorsOrDescendants
{
if (nil != [self fb_parentMatchingOneOfTypes:@[@(XCUIElementTypeAny)]
filter:^BOOL(id<FBXCElementSnapshot> _Nonnull parent) {
return [fetchSnapshotVisibility(parent) boolValue];
}]) {
return YES;
}
for (id<FBXCElementSnapshot> descendant in (self._allDescendants ?: @[])) {
if ([fetchSnapshotVisibility(descendant) boolValue]) {
return YES;
}
}
return NO;
}

- (BOOL)fb_isVisible
{
NSNumber *isVisible = self.additionalAttributes[FB_XCAXAIsVisibleAttribute];
NSNumber *isVisible = fetchSnapshotVisibility(self);
if (isVisible != nil) {
return isVisible.boolValue;
}

return [(NSNumber *)[self fb_attributeValue:FB_XCAXAIsVisibleAttributeName] boolValue];
if ([self fb_hasVisibleAncestorsOrDescendants]) {
return YES;
}

NSError *error = nil;
NSNumber *attributeValue = [self fb_attributeValue:FB_XCAXAIsVisibleAttributeName
timeout:AX_FETCH_TIMEOUT
error:&error];
if (nil != attributeValue && nil == error) {
return [attributeValue boolValue];
}

NSLog(@"Cannot determine element visibility: %@", error.description);
return nil != [self fb_hitPoint];
}

@end
32 changes: 0 additions & 32 deletions WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,38 +37,6 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable id<FBXCElementSnapshot>)fb_cachedSnapshot;

/**
Gets the most recent snapshot of the current element and already resolves the accessibility attributes
needed for creating the page source of this element. No additional calls to the accessibility layer
are required.
Calls to this method mutate the `lastSnapshot` instance property.
@param inDepth Whether to resolve snapshot parents and children
@return The recent snapshot of the element with all attributes resolved or a snapshot with default
attributes resolved if there was a failure while resolving additional attributes
@throws FBStaleElementException if the element is not present in DOM and thus no snapshot could be made
*/
- (nullable id<FBXCElementSnapshot>)fb_snapshotWithAllAttributes:(BOOL)inDepth;

/**
Gets the most recent snapshot of the current element with given attributes resolved.
No additional calls to the accessibility layer are required.
Calls to this method mutate the `lastSnapshot` instance property.
@param customAttributeNames The list of custom attribute names to resolve. Must be one of
FB_...Name values exported by XCTestPrivateSymbols.h module.
`nil` value means that only the default attributes must be extracted
@param inDepth Whether to resolve snapshot parents and children
@return The recent snapshot of the element with the given attributes resolved or a snapshot with default
attributes resolved if there was a failure while resolving additional attributes
@throws FBStaleElementException if the element is not present in DOM and thus no snapshot could be made
*/
- (nullable id<FBXCElementSnapshot>)fb_snapshotWithCustomAttributes:(nullable NSArray<NSString *> *)customAttributeNames
exludingStandardAttributes:(BOOL)exludingStandardAttributes
inDepth:(BOOL)inDepth;

/**
Filters elements by matching them to snapshots from the corresponding array
Expand Down
76 changes: 0 additions & 76 deletions WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@
#import "XCUIScreen.h"
#import "XCUIElement+FBResolve.h"

#define DEFAULT_AX_TIMEOUT 60.

@implementation XCUIElement (FBUtilities)

- (id<FBXCElementSnapshot>)fb_takeSnapshot:(BOOL)inDepth
Expand Down Expand Up @@ -72,80 +70,6 @@ @implementation XCUIElement (FBUtilities)
return [self.query fb_cachedSnapshot];
}

- (nullable id<FBXCElementSnapshot>)fb_snapshotWithAllAttributes:(BOOL)inDepth
{
return [self fb_snapshotWithCustomAttributes:FBCustomAttributeNames()
exludingStandardAttributes:NO
inDepth:inDepth];
}

- (nullable id<FBXCElementSnapshot>)fb_snapshotWithCustomAttributes:(NSArray<NSString *> *)customAttributeNames
exludingStandardAttributes:(BOOL)exludingStandardAttributes
inDepth:(BOOL)inDepth
{
NSTimeInterval axTimeout = FBConfiguration.customSnapshotTimeout;
if (nil == customAttributeNames
|| [customAttributeNames count] == 0
|| axTimeout < DBL_EPSILON) {
// return the "normal" element snapshot if no custom attributes are requested
return [self fb_takeSnapshot:inDepth];
}

BOOL isSelfApplicationElement = [self isKindOfClass:XCUIApplication.class];
id<FBXCAccessibilityElement> axElement = isSelfApplicationElement
? [(XCUIApplication *)self accessibilityElement]
: [[self fb_takeSnapshot:inDepth] accessibilityElement];
if (nil == axElement) {
return nil;
}

NSError *setTimeoutError;
BOOL isTimeoutSet = [FBXCAXClientProxy.sharedClient setAXTimeout:axTimeout
error:&setTimeoutError];
if (!isTimeoutSet) {
[FBLogger logFmt:@"Cannot set snapshoting timeout to %.1fs. Original error: %@",
axTimeout, setTimeoutError.localizedDescription];
}

NSError *error;
NSMutableArray *attributeNames = [NSMutableArray arrayWithArray:exludingStandardAttributes ? @[] : FBStandardAttributeNames()];
[attributeNames addObjectsFromArray:customAttributeNames ?: @[]];
BOOL requiresFullTreeSnapshot = isSelfApplicationElement || inDepth;
id<FBXCAccessibilityElement> appAxElement = isSelfApplicationElement ? axElement : self.application.accessibilityElement;
id<FBXCElementSnapshot> snapshotWithAttributes = [FBXCAXClientProxy.sharedClient snapshotForElement:requiresFullTreeSnapshot ? appAxElement : axElement
attributes:attributeNames.copy
inDepth:requiresFullTreeSnapshot
error:&error];
NSString *axElementUid = [FBElementUtils uidWithAccessibilityElement:axElement];
if (nil != snapshotWithAttributes && nil != axElementUid && !isSelfApplicationElement) {
NSArray *matches = [snapshotWithAttributes descendantsByFilteringWithBlock:^BOOL(id<FBXCElementSnapshot> _Nonnull snapshot) {
return [[FBElementUtils uidWithAccessibilityElement:snapshot.accessibilityElement] isEqualToString:axElementUid];
}];
if ([matches count] > 0) {
snapshotWithAttributes = [matches objectAtIndex:0];
}
}
if (nil == snapshotWithAttributes) {
if (isSelfApplicationElement || !inDepth) {
[self fb_takeSnapshot:YES];
}
NSString *description = [FBXCElementSnapshotWrapper ensureWrapped:self.lastSnapshot].fb_description;
[FBLogger logFmt:@"Cannot take a snapshot with attribute(s) %@ of '%@' after %.2f seconds",
attributeNames, description, axTimeout];
[FBLogger logFmt:@"This timeout could be customized via '%@' setting", FB_SETTING_CUSTOM_SNAPSHOT_TIMEOUT];
[FBLogger logFmt:@"Internal error: %@", error.localizedDescription];
[FBLogger logFmt:@"Falling back to the default snapshotting mechanism for the element '%@' (some attribute values, like visibility or accessibility might not be precise though)", description];
snapshotWithAttributes = self.lastSnapshot;
} else {
self.lastSnapshot = snapshotWithAttributes;
}

if (isTimeoutSet) {
[FBXCAXClientProxy.sharedClient setAXTimeout:DEFAULT_AX_TIMEOUT error:nil];
}
return snapshotWithAttributes;
}

- (NSArray<XCUIElement *> *)fb_filterDescendantsWithSnapshots:(NSArray<id<FBXCElementSnapshot>> *)snapshots
selfUID:(NSString *)selfUID
onlyChildren:(BOOL)onlyChildren
Expand Down
21 changes: 2 additions & 19 deletions WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,6 @@ @implementation XCUIElement (WebDriverAttributesForwarding)
BOOL inDepth = [name isEqualToString:FBStringify(XCUIElement, isWDAccessible)]
|| [name isEqualToString:FBStringify(XCUIElement, isWDAccessibilityContainer)]
|| [name isEqualToString:FBStringify(XCUIElement, wdIndex)];

// These attributes are special, because we can only retrieve them from
// the snapshot if we explicitly ask XCTest to include them into the query while taking it.
// That is why fb_snapshotWithAllAttributes method must be used instead of the default snapshot
// call
if ([name isEqualToString:FBStringify(XCUIElement, isWDVisible)]) {
return [self fb_snapshotWithCustomAttributes:@[FB_XCAXAIsVisibleAttributeName]
exludingStandardAttributes:YES
inDepth:inDepth];
}
if ([name isEqualToString:FBStringify(XCUIElement, isWDAccessible)]
|| [name isEqualToString:FBStringify(XCUIElement, isWDAccessibilityContainer)]) {
return [self fb_snapshotWithCustomAttributes:@[FB_XCAXAIsElementAttributeName]
exludingStandardAttributes:NO
inDepth:inDepth];
}

return [self fb_takeSnapshot:inDepth];
}

Expand Down Expand Up @@ -186,8 +169,8 @@ - (BOOL)isWDAccessible
// In the scenario when table provides Search results controller, table could be marked as accessible element, even though it isn't
// As it is highly unlikely that table view should ever be an accessibility element itself,
// for now we work around that by skipping Table View in container checks
if ([FBXCElementSnapshotWrapper ensureWrapped:parentSnapshot].fb_isAccessibilityElement
&& parentSnapshot.elementType != XCUIElementTypeTable) {
if (parentSnapshot.elementType != XCUIElementTypeTable
&& [FBXCElementSnapshotWrapper ensureWrapped:parentSnapshot].fb_isAccessibilityElement) {
return NO;
}
parentSnapshot = parentSnapshot.parent;
Expand Down
7 changes: 5 additions & 2 deletions WebDriverAgentLib/Utilities/FBXCAXClientProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#import <XCTest/XCTest.h>
#import "FBXCElementSnapshot.h"

extern const NSTimeInterval FBDefaultAxTimeout;

@protocol FBXCAccessibilityElement;

NS_ASSUME_NONNULL_BEGIN
Expand Down Expand Up @@ -39,8 +41,9 @@ NS_ASSUME_NONNULL_BEGIN
- (void)notifyWhenNoAnimationsAreActiveForApplication:(XCUIApplication *)application
reply:(void (^)(void))reply;

- (NSDictionary *)attributesForElement:(id<FBXCAccessibilityElement>)element
attributes:(NSArray *)attributes;
- (nullable NSDictionary *)attributesForElement:(id<FBXCAccessibilityElement>)element
attributes:(NSArray *)attributes
error:(NSError**)error;

- (XCUIApplication *)monitoredApplicationWithProcessIdentifier:(int)pid;

Expand Down
Loading

0 comments on commit a36c190

Please sign in to comment.