Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Properly update maxDepth while fetching snapshots #655

Merged
merged 15 commits into from
Jan 26, 2023
12 changes: 12 additions & 0 deletions WebDriverAgent.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,10 @@
714D88CD2733FB970074A925 /* FBXMLGenerationOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 714D88CA2733FB970074A925 /* FBXMLGenerationOptions.h */; };
714D88CE2733FB970074A925 /* FBXMLGenerationOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 714D88CB2733FB970074A925 /* FBXMLGenerationOptions.m */; };
714D88CF2733FB970074A925 /* FBXMLGenerationOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 714D88CB2733FB970074A925 /* FBXMLGenerationOptions.m */; };
714E14B829805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 714E14B629805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.h */; };
714E14B929805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 714E14B629805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.h */; };
714E14BA29805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.m in Sources */ = {isa = PBXBuildFile; fileRef = 714E14B729805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.m */; };
714E14BB29805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.m in Sources */ = {isa = PBXBuildFile; fileRef = 714E14B729805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.m */; };
714EAA0D2673FDFE005C5B47 /* FBCapabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 714EAA0B2673FDFE005C5B47 /* FBCapabilities.h */; };
714EAA0E2673FDFE005C5B47 /* FBCapabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 714EAA0B2673FDFE005C5B47 /* FBCapabilities.h */; };
714EAA0F2673FDFE005C5B47 /* FBCapabilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 714EAA0C2673FDFE005C5B47 /* FBCapabilities.m */; };
Expand Down Expand Up @@ -975,6 +979,8 @@
714CA3C61DC23186000F12C9 /* FBXPathIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBXPathIntegrationTests.m; sourceTree = "<group>"; };
714D88CA2733FB970074A925 /* FBXMLGenerationOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBXMLGenerationOptions.h; sourceTree = "<group>"; };
714D88CB2733FB970074A925 /* FBXMLGenerationOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBXMLGenerationOptions.m; sourceTree = "<group>"; };
714E14B629805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "XCAXClient_iOS+FBSnapshotReqParams.h"; sourceTree = "<group>"; };
714E14B729805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "XCAXClient_iOS+FBSnapshotReqParams.m"; sourceTree = "<group>"; };
714EAA0B2673FDFE005C5B47 /* FBCapabilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBCapabilities.h; sourceTree = "<group>"; };
714EAA0C2673FDFE005C5B47 /* FBCapabilities.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBCapabilities.m; sourceTree = "<group>"; };
7150348521A6DAD600A0F4BA /* FBImageUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBImageUtils.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1719,6 +1725,8 @@
EE0D1F601EBCDCF7006A3123 /* NSString+FBVisualLength.m */,
716E0BCC1E917E810087A825 /* NSString+FBXMLSafeString.h */,
716E0BCD1E917E810087A825 /* NSString+FBXMLSafeString.m */,
714E14B629805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.h */,
714E14B729805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.m */,
AD6C269A1CF2494200F8B5FF /* XCUIApplication+FBHelpers.h */,
AD6C269B1CF2494200F8B5FF /* XCUIApplication+FBHelpers.m */,
71C8E54F25399A6B008572C1 /* XCUIApplication+FBQuiescence.h */,
Expand Down Expand Up @@ -2284,6 +2292,7 @@
641EE64B2240C5CA00173FCB /* XCTAsyncActivity.h in Headers */,
641EE64C2240C5CA00173FCB /* XCTestMisuseObserver.h in Headers */,
641EE64D2240C5CA00173FCB /* XCTRunnerDaemonSession.h in Headers */,
714E14B929805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.h in Headers */,
64B2650B228CE4FF002A5025 /* FBTVNavigationTracker-Private.h in Headers */,
641EE64E2240C5CA00173FCB /* FBApplication.h in Headers */,
641EE64F2240C5CA00173FCB /* XCTestExpectationWaiter.h in Headers */,
Expand Down Expand Up @@ -2525,6 +2534,7 @@
6496A5D9230D6EB30087F8CB /* AXSettings.h in Headers */,
EE35AD301E3B77D600A02D78 /* XCKeyboardKeyMap.h in Headers */,
EE35AD5D1E3B77D600A02D78 /* XCTNSPredicateExpectationObject-Protocol.h in Headers */,
714E14B829805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.h in Headers */,
EE158B5F1CBD47A000A3E3F0 /* WebDriverAgentLib.h in Headers */,
EE158AC01CBD456F00A3E3F0 /* FBFindElementCommands.h in Headers */,
71D475C22538F5A8008D9401 /* XCUIApplicationProcess+FBQuiescence.h in Headers */,
Expand Down Expand Up @@ -3082,6 +3092,7 @@
641EE70F2240CE4800173FCB /* FBTVNavigationTracker.m in Sources */,
714D88CF2733FB970074A925 /* FBXMLGenerationOptions.m in Sources */,
641EE5DE2240C5CA00173FCB /* XCUIApplication+FBTouchAction.m in Sources */,
714E14BB29805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.m in Sources */,
641EE5DF2240C5CA00173FCB /* FBWebServer.m in Sources */,
641EE5E02240C5CA00173FCB /* FBTCPSocket.m in Sources */,
641EE5E12240C5CA00173FCB /* FBErrorBuilder.m in Sources */,
Expand Down Expand Up @@ -3260,6 +3271,7 @@
EE6B64FE1D0F86EF00E85F5D /* XCTestPrivateSymbols.m in Sources */,
AD76723E1D6B7CC000610457 /* XCUIElement+FBTyping.m in Sources */,
EE158AAF1CBD456F00A3E3F0 /* XCUIElement+FBAccessibility.m in Sources */,
714E14BA29805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.m in Sources */,
7150348821A6DAD600A0F4BA /* FBImageUtils.m in Sources */,
E444DCAB24913C220060D7EB /* HTTPResponseProxy.m in Sources */,
E444DC6D249131890060D7EB /* HTTPErrorResponse.m in Sources */,
Expand Down
26 changes: 26 additions & 0 deletions WebDriverAgentLib/Categories/XCAXClient_iOS+FBSnapshotReqParams.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#import <XCTest/XCTest.h>

#import "XCAXClient_iOS.h"

NS_ASSUME_NONNULL_BEGIN

extern NSString *const FBSnapshotMaxDepthKey;

void FBSetCustomParameterForElementSnapshot (NSString* name, id value);

id __nullable FBGetCustomParameterForElementSnapshot (NSString *name);

@interface XCAXClient_iOS (FBSnapshotReqParams)

@end

NS_ASSUME_NONNULL_END
90 changes: 90 additions & 0 deletions WebDriverAgentLib/Categories/XCAXClient_iOS+FBSnapshotReqParams.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#import "XCAXClient_iOS+FBSnapshotReqParams.h"

#import <objc/runtime.h>

/**
Available parameters with their default values for XCTest:
@"maxChildren" : (int)2147483647
@"traverseFromParentsToChildren" : YES
@"maxArrayCount" : (int)2147483647
@"snapshotKeyHonorModalViews" : NO
@"maxDepth" : (int)2147483647
*/
NSString *const FBSnapshotMaxDepthKey = @"maxDepth";

static id (*original_defaultParameters)(id, SEL);
static id (*original_snapshotParameters)(id, SEL);
static NSDictionary *defaultRequestParameters;
static NSDictionary *defaultAdditionalRequestParameters;
static NSMutableDictionary *customRequestParameters;

void FBSetCustomParameterForElementSnapshot (NSString *name, id value)
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
customRequestParameters = [NSMutableDictionary new];
});
customRequestParameters[name] = value;
}

id FBGetCustomParameterForElementSnapshot (NSString *name)
{
return customRequestParameters[name];
}

static id swizzledDefaultParameters(id self, SEL _cmd)
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:original_defaultParameters(self, _cmd)];
[params addEntriesFromDictionary:defaultAdditionalRequestParameters];
defaultRequestParameters = params.copy;
});
if (nil == defaultRequestParameters) {
Dan-Maor marked this conversation as resolved.
Show resolved Hide resolved
return original_defaultParameters(self, _cmd);
}
NSMutableDictionary *result = [NSMutableDictionary dictionaryWithDictionary:defaultRequestParameters];
if (nil != customRequestParameters && customRequestParameters.count > 0) {
[result addEntriesFromDictionary:customRequestParameters];
}
return result.copy;
}

static id swizzledSnapshotParameters(id self, SEL _cmd)
{
NSDictionary *result = original_snapshotParameters(self, _cmd);
Dan-Maor marked this conversation as resolved.
Show resolved Hide resolved
if (nil == defaultAdditionalRequestParameters) {
defaultAdditionalRequestParameters = result;
}
return result;
}


@implementation XCAXClient_iOS (FBSnapshotReqParams)

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-load-method"

+ (void)load
{
Method original_defaultParametersMethod = class_getInstanceMethod(self.class, @selector(defaultParameters));
IMP swizzledDefaultParametersImp = (IMP)swizzledDefaultParameters;
original_defaultParameters = (id (*)(id, SEL)) method_setImplementation(original_defaultParametersMethod, swizzledDefaultParametersImp);

Method original_snapshotParametersMethod = class_getInstanceMethod(NSClassFromString(@"XCTElementQuery"), NSSelectorFromString(@"snapshotParameters"));
IMP swizzledSnapshotParametersImp = (IMP)swizzledSnapshotParameters;
original_snapshotParameters = (id (*)(id, SEL)) method_setImplementation(original_snapshotParametersMethod, swizzledSnapshotParametersImp);
}

#pragma clang diagnostic pop

@end
7 changes: 0 additions & 7 deletions WebDriverAgentLib/Utilities/FBConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,6 @@ typedef NS_ENUM(NSInteger, FBConfigurationKeyboardPreference) {
*/
+ (int)snapshotMaxDepth;

/**
Returns parameters for traversing elements tree from parents to children while requesting XCElementSnapshot.

@return dictionary with parameters for element's snapshot request
*/
+ (NSDictionary *)snapshotRequestParameters;

/**
* Whether to use fast search result matching while searching for elements.
* By default this is disabled due to https://github.com/appium/appium/issues/10101
Expand Down
19 changes: 4 additions & 15 deletions WebDriverAgentLib/Utilities/FBConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "TargetConditionals.h"
#import "FBXCodeCompatibility.h"
#import "XCAXClient_iOS+FBSnapshotReqParams.h"
#import "XCTestPrivateSymbols.h"
#import "XCTestConfiguration.h"
#import "XCUIApplication+FBUIInterruptions.h"
Expand All @@ -30,7 +31,6 @@

static BOOL FBShouldUseTestManagerForVisibilityDetection = NO;
static BOOL FBShouldUseSingletonTestManager = YES;
NSString *const FBSnapshotMaxDepthKey = @"maxDepth";

static NSUInteger FBMjpegScalingFactor = 100;
static NSUInteger FBMjpegServerScreenshotQuality = 25;
Expand All @@ -53,17 +53,11 @@
#if !TARGET_OS_TV
static UIInterfaceOrientation FBScreenshotOrientation;
#endif
static NSMutableDictionary *FBSnapshotRequestParameters;

@implementation FBConfiguration

+ (void)initialize
{
FBSnapshotRequestParameters = [NSMutableDictionary dictionaryWithDictionary:@{
@"maxArrayCount": @INT_MAX,
@"maxChildren": @INT_MAX,
@"traverseFromParentsToChildren": @1
}];
[FBConfiguration resetSessionSettings];
}

Expand Down Expand Up @@ -341,17 +335,12 @@ + (NSTimeInterval)customSnapshotTimeout

+ (void)setSnapshotMaxDepth:(int)maxDepth
{
FBSnapshotRequestParameters[FBSnapshotMaxDepthKey] = @(maxDepth);
FBSetCustomParameterForElementSnapshot(FBSnapshotMaxDepthKey, @(maxDepth));
}

+ (int)snapshotMaxDepth
{
return [FBSnapshotRequestParameters[FBSnapshotMaxDepthKey] intValue];
}

+ (NSDictionary *)snapshotRequestParameters
{
return FBSnapshotRequestParameters;
return [FBGetCustomParameterForElementSnapshot(FBSnapshotMaxDepthKey) intValue];
}

+ (void)setUseFirstMatch:(BOOL)enabled
Expand Down Expand Up @@ -468,7 +457,7 @@ + (void)resetSessionSettings
FBWaitForIdleTimeout = 10.;
FBAnimationCoolOffTimeout = 2.;
// 50 should be enough for the majority of the cases. The performance is acceptable for values up to 100.
FBSnapshotRequestParameters[FBSnapshotMaxDepthKey] = @50;
FBSetCustomParameterForElementSnapshot(FBSnapshotMaxDepthKey, @50);
#if !TARGET_OS_TV
FBScreenshotOrientation = UIInterfaceOrientationUnknown;
#endif
Expand Down
43 changes: 2 additions & 41 deletions WebDriverAgentLib/Utilities/FBXCAXClientProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,47 +9,14 @@

#import "FBXCAXClientProxy.h"

#import <objc/runtime.h>

#import "FBXCAccessibilityElement.h"
#import "FBConfiguration.h"
#import "FBLogger.h"
#import "FBMacros.h"
#import "FBReflectionUtils.h"
#import "XCAXClient_iOS.h"
#import "XCAXClient_iOS+FBSnapshotReqParams.h"
#import "XCUIDevice.h"

static id FBAXClient = nil;

@implementation XCAXClient_iOS (WebDriverAgent)

/**
Parameters for traversing elements tree from parents to children while requesting XCElementSnapshot.

@return dictionary with parameters for element's snapshot request
*/
- (NSDictionary *)fb_getParametersForElementSnapshot
{
return FBConfiguration.snapshotRequestParameters;
}

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-load-method"

+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL originalParametersSelector = @selector(defaultParameters);
SEL swizzledParametersSelector = @selector(fb_getParametersForElementSnapshot);
FBReplaceMethod([self class], originalParametersSelector, swizzledParametersSelector);
});
}

#pragma clang diagnostic pop

@end

@implementation FBXCAXClientProxy

+ (instancetype)sharedClient
Expand All @@ -73,14 +40,8 @@ - (BOOL)setAXTimeout:(NSTimeInterval)timeout error:(NSError **)error
maxDepth:(nullable NSNumber *)maxDepth
error:(NSError **)error
{
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
// Mimicking XCTest framework behavior (this attribute is added by default unless it is an excludingNonModalElements query)
// See https://github.com/appium/WebDriverAgent/pull/523
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"13.0")) {
KazuCocoa marked this conversation as resolved.
Show resolved Hide resolved
parameters[@"snapshotKeyHonorModalViews"] = @(NO);
}
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithDictionary:self.defaultParameters];
if (nil != maxDepth) {
[parameters addEntriesFromDictionary:self.defaultParameters];
parameters[FBSnapshotMaxDepthKey] = maxDepth;
}

Expand Down