diff --git a/CommonLib/Config/GREYConfigKey.h b/CommonLib/Config/GREYConfigKey.h index d2bede599..982e96be2 100644 --- a/CommonLib/Config/GREYConfigKey.h +++ b/CommonLib/Config/GREYConfigKey.h @@ -185,4 +185,13 @@ GREY_EXTERN GREYConfigKey const kGREYConfigKeyAutoUntrackMDCActivityIndicators; */ GREY_EXTERN GREYConfigKey const kGREYConfigKeyAutoHideScrollViewIndicators; +/** + * Configuration that holds a list of regular expressions for bundle identifiers + * that should not be configured for EarlGrey (e.g. system apps). EarlGrey will + * skip injecting eDO arguments and resetting the host port for these apps. + * + * Accepted values: @c NSArray of valid regular expressions as @c NSString. + */ +GREY_EXTERN GREYConfigKey const kGREYConfigKeyBundleIDsExcludedFromSetup; + NS_ASSUME_NONNULL_END diff --git a/CommonLib/Config/GREYConfigKey.m b/CommonLib/Config/GREYConfigKey.m index d229210ba..e1dac7970 100644 --- a/CommonLib/Config/GREYConfigKey.m +++ b/CommonLib/Config/GREYConfigKey.m @@ -40,3 +40,5 @@ @"kGREYConfigKeyAutoUntrackMDCActivityIndicators"; GREYConfigKey const kGREYConfigKeyAutoHideScrollViewIndicators = @"GREYConfigKeyAutoHideScrollViewIndicators"; +GREYConfigKey const kGREYConfigKeyBundleIDsExcludedFromSetup = + @"GREYConfigKeyBundleIDsExcludedFromSetup"; diff --git a/TestLib/AppleInternals/GREYXCTestAppleInternals.h b/TestLib/AppleInternals/GREYXCTestAppleInternals.h index 1673d0f8d..b0dbca328 100644 --- a/TestLib/AppleInternals/GREYXCTestAppleInternals.h +++ b/TestLib/AppleInternals/GREYXCTestAppleInternals.h @@ -59,3 +59,20 @@ + (nullable id)sharedClient; @end + +/** + * XCTest class representing the active test run's configuration. + */ +@interface XCTestConfiguration : NSObject + +/** + * Returns the singleton active test configuration instance. + */ ++ (nonnull instancetype)activeTestConfiguration; + +/** + * The bundle identifier of the primary application under test. + */ +@property(copy, nullable) NSString *targetApplicationBundleID; + +@end diff --git a/TestLib/Config/GREYTestConfiguration.m b/TestLib/Config/GREYTestConfiguration.m index 2396b06d0..3d1dab68f 100644 --- a/TestLib/Config/GREYTestConfiguration.m +++ b/TestLib/Config/GREYTestConfiguration.m @@ -69,6 +69,10 @@ - (instancetype)init { [self setDefaultValue:@(kGREYAppLaunchTimeout) forConfigKey:kGREYConfigKeyAppLaunchTimeout]; [self setDefaultValue:@NO forConfigKey:kGREYConfigKeyAutoUntrackMDCActivityIndicators]; [self setDefaultValue:@NO forConfigKey:kGREYConfigKeyAutoHideScrollViewIndicators]; + [self setDefaultValue:@[ + @"^com\\.apple\\..*", + ] + forConfigKey:kGREYConfigKeyBundleIDsExcludedFromSetup]; } return self; } diff --git a/TestLib/EarlGreyImpl/XCUIApplication+GREYTest.m b/TestLib/EarlGreyImpl/XCUIApplication+GREYTest.m index 4c527a65d..e09b369b4 100644 --- a/TestLib/EarlGreyImpl/XCUIApplication+GREYTest.m +++ b/TestLib/EarlGreyImpl/XCUIApplication+GREYTest.m @@ -27,6 +27,7 @@ #import "GREYLogger.h" #import "GREYSetup.h" #import "GREYSwizzler.h" +#import "GREYXCTestAppleInternals.h" #import "GREYTestConfiguration.h" #import "XCUIApplication+GREYEnvironment.h" @@ -52,6 +53,55 @@ + (NSString *)greyTestRigName { - (void)grey_launch { [self modifyKeyboardSettings]; + static NSString *gPrimaryAppBundleID; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + @try { + gPrimaryAppBundleID = XCTestConfiguration.activeTestConfiguration.targetApplicationBundleID; + } @catch (NSException *exception) { + GREYLog(@"Failed to read targetApplicationBundleID from XCTestConfiguration: %@", exception); + } + }); + + // It is the primary app under test if the bundleID matches the static target, + // or if it is nil/empty (representing the default init rig target). + NSString *currentBundleID = self.bundleID; + BOOL isPrimaryApp = (gPrimaryAppBundleID.length == 0) || (currentBundleID.length == 0) || + [gPrimaryAppBundleID isEqualToString:currentBundleID]; + + NSArray *excludedRegexes = + GREY_CONFIG_ARRAY(kGREYConfigKeyBundleIDsExcludedFromSetup); + BOOL isExcluded = NO; + if (currentBundleID.length > 0) { + NSError *error; + for (NSString *regexStr in excludedRegexes) { + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexStr + options:0 + error:&error]; + GREYFatalAssertWithMessage(!error, @"Invalid regex:\"%@\". See error: %@", regexStr, error); + NSRange firstMatch = + [regex rangeOfFirstMatchInString:currentBundleID + options:0 + range:NSMakeRange(0, [currentBundleID length])]; + if (firstMatch.location != NSNotFound) { + isExcluded = YES; + break; + } + } + } + + if (isExcluded) { + GREYLog(@"Launching excluded application: %@. Skipping EarlGrey setup.", currentBundleID); + INVOKE_ORIGINAL_IMP(void, @selector(grey_launch)); + return; + } + + if (!isPrimaryApp) { + GREYLog(@"WARNING: Launching application: %@. Ensure it links EarlGrey " + @"AppFramework.", + currentBundleID); + } + // Setup the Launch Environments. [self grey_configureApplicationForLaunch]; // Setup the Launch Arguments for eDO. @@ -80,8 +130,8 @@ - (void)grey_launch { NSTimer *validTimer = AddTimerForLaunchTimeout(); INVOKE_ORIGINAL_IMP(void, @selector(grey_launch)); [validTimer invalidate]; - // When the identifier is @c nil or empty, it is the TestRig application being launched. - if (self.identifier.length == 0) { + + if (isPrimaryApp) { objc_setAssociatedObject([XCUIApplication class], @selector(greyTestRigName), self.label, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }