diff --git a/.nx/version-plans/cut-xctest-permission-watchdog-polling.md b/.nx/version-plans/cut-xctest-permission-watchdog-polling.md new file mode 100644 index 00000000..8af00b5f --- /dev/null +++ b/.nx/version-plans/cut-xctest-permission-watchdog-polling.md @@ -0,0 +1,5 @@ +--- +__default__: patch +--- + +The iOS permission-dialog watchdog now uses far less CPU, and its polling interval is tunable via HARNESS_XCTEST_AGENT_TICK_INTERVAL_MS. diff --git a/apps/playground/rn-harness.config.mjs b/apps/playground/rn-harness.config.mjs index 1053d2f9..bb4badfe 100644 --- a/apps/playground/rn-harness.config.mjs +++ b/apps/playground/rn-harness.config.mjs @@ -116,6 +116,7 @@ export default { defaultRunner: 'android', platformReadyTimeout: 300000, bridgeTimeout: 120000, + testTimeout: 10000, permissions: true, detectNativeCrashes: true, diff --git a/packages/platform-ios/src/xctest-agent.ts b/packages/platform-ios/src/xctest-agent.ts index 00e3034e..fc0d657c 100644 --- a/packages/platform-ios/src/xctest-agent.ts +++ b/packages/platform-ios/src/xctest-agent.ts @@ -25,6 +25,8 @@ const xctestAgentLogger = logger.child('ios-xctest-agent'); const XCTEST_AGENT_PROJECT_NAME = 'HarnessXCTestAgent'; const XCTEST_AGENT_SCHEME_NAME = 'HarnessXCTestAgent'; const XCTEST_AGENT_PORT_ENV = 'HARNESS_XCTEST_AGENT_PORT'; +const XCTEST_AGENT_TICK_INTERVAL_MS_ENV = + 'HARNESS_XCTEST_AGENT_TICK_INTERVAL_MS'; const XCTEST_AGENT_TARGET_BUNDLE_ID_ENV = 'HARNESS_XCTEST_AGENT_TARGET_BUNDLE_ID'; const XCTEST_AGENT_XCTESTRUN_FILE_ENV = 'HARNESS_IOS_XCTESTRUN_FILE'; @@ -937,6 +939,8 @@ export const createXCTestAgentController = (options: { let processTask: Promise | null = null; const getLaunchEnvironment = (): Record => { + const tickIntervalMs = getEnvironmentPath(XCTEST_AGENT_TICK_INTERVAL_MS_ENV); + return Object.assign( {}, options.appBundleId @@ -944,6 +948,11 @@ export const createXCTestAgentController = (options: { [XCTEST_AGENT_TARGET_BUNDLE_ID_ENV]: options.appBundleId, } : {}, + tickIntervalMs + ? { + [XCTEST_AGENT_TICK_INTERVAL_MS_ENV]: tickIntervalMs, + } + : {}, ...capabilities.map( (capability) => capability.getLaunchEnvironment?.() ?? {} ) diff --git a/packages/platform-ios/xctest-agent/HarnessXCTestAgentUITests/HarnessXCTestAgentUITests.swift b/packages/platform-ios/xctest-agent/HarnessXCTestAgentUITests/HarnessXCTestAgentUITests.swift index 31abf4b7..736e52b8 100644 --- a/packages/platform-ios/xctest-agent/HarnessXCTestAgentUITests/HarnessXCTestAgentUITests.swift +++ b/packages/platform-ios/xctest-agent/HarnessXCTestAgentUITests/HarnessXCTestAgentUITests.swift @@ -180,11 +180,24 @@ private final class XCTestAgentHTTPServer { final class HarnessXCTestAgentUITests: XCTestCase { private enum Environment { static let targetBundleIdentifier = "HARNESS_XCTEST_AGENT_TARGET_BUNDLE_ID" + static let tickIntervalMs = "HARNESS_XCTEST_AGENT_TICK_INTERVAL_MS" } private enum Constants { static let defaultSessionDuration: TimeInterval = 60 * 60 - static let tickInterval: TimeInterval = 1 + static let defaultTickInterval: TimeInterval = 1 + } + + private static func resolveTickInterval() -> TimeInterval { + guard + let rawValue = ProcessInfo.processInfo.environment[Environment.tickIntervalMs], + let milliseconds = Int(rawValue), + milliseconds > 0 + else { + return Constants.defaultTickInterval + } + + return TimeInterval(milliseconds) / 1000 } private let state = HarnessXCTestAgentState( @@ -194,6 +207,7 @@ final class HarnessXCTestAgentUITests: XCTestCase { private let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") private var capabilities: [AgentCapability] = [] private var httpServer: XCTestAgentHTTPServer? + private let tickInterval = HarnessXCTestAgentUITests.resolveTickInterval() private func log(_ message: String) { NSLog("[HarnessXCTestAgent] %@", message) @@ -309,7 +323,7 @@ final class HarnessXCTestAgentUITests: XCTestCase { } RunLoop.current.run( - until: Date().addingTimeInterval(Constants.tickInterval) + until: Date().addingTimeInterval(tickInterval) ) } diff --git a/packages/platform-ios/xctest-agent/HarnessXCTestAgentUITests/PermissionPromptWatchdog.swift b/packages/platform-ios/xctest-agent/HarnessXCTestAgentUITests/PermissionPromptWatchdog.swift index 7b0631f8..8a732266 100644 --- a/packages/platform-ios/xctest-agent/HarnessXCTestAgentUITests/PermissionPromptWatchdog.swift +++ b/packages/platform-ios/xctest-agent/HarnessXCTestAgentUITests/PermissionPromptWatchdog.swift @@ -54,6 +54,14 @@ final class PermissionPromptWatchdog: AgentCapability { return } + let guardQuery = springboard.buttons.matching( + NSPredicate(format: "label IN %@", Constants.knownPositiveButtonLabels) + ).firstMatch + + guard guardQuery.exists else { + return + } + for label in Constants.knownPositiveButtonLabels { let button = springboard.buttons[label].firstMatch