Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
__default__: patch
---

The iOS XCTest permission agent now starts building while the simulator boots instead of waiting for the boot to finish first, cutting startup time for simulator runs that need permission auto-acceptance—especially on a cold build cache.
2 changes: 1 addition & 1 deletion apps/playground/rn-harness.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export default {
}),
],
defaultRunner: 'android',
platformReadyTimeout: 300000,
platformReadyTimeout: 480000,
bridgeTimeout: 120000,
testTimeout: 10000,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,11 @@ describe('iOS XCTest agent runner integration', () => {
},
signal: initSignal,
});
expect(mocks.prepare).not.toHaveBeenCalled();
expect(mocks.prepare).toHaveBeenCalledTimes(1);
expect(mocks.ensureStarted).toHaveBeenCalledTimes(1);
expect(
mocks.prepare.mock.invocationCallOrder[0]
).toBeLessThan(mocks.ensureStarted.mock.invocationCallOrder[0]);
expect(mocks.dispose).toHaveBeenCalledTimes(1);
});

Expand Down Expand Up @@ -168,6 +171,7 @@ describe('iOS XCTest agent runner integration', () => {
);

expect(mocks.createXCTestAgentController).not.toHaveBeenCalled();
expect(mocks.prepare).not.toHaveBeenCalled();
expect(mocks.ensureStarted).not.toHaveBeenCalled();
});
});
40 changes: 28 additions & 12 deletions packages/platform-ios/src/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,33 @@ export const getAppleSimulatorPlatformInstance = async (
throw new DeviceNotFoundError(getDeviceName(config.device));
}

const xctestAgent = permissionsEnabled
? createXCTestAgentController({
appBundleId: config.bundleId,
target: {
kind: 'simulator',
id: udid,
},
capabilities: [createPermissionPromptAutoAcceptCapability()],
signal: init.signal,
})
: null;

// The XCTest agent build (build-for-testing, destination
// "generic/platform=iOS Simulator") does not need a booted device, so
// kick it off now to overlap with the boot/waitForBoot sequence below.
// It is awaited (not raced) inside the try block further down so build
// errors are still surfaced; the .catch here only prevents an
// unhandled-rejection warning if boot fails first and this promise is
// left to settle unobserved in the meantime.
const preparePromise = xctestAgent?.prepare();
preparePromise?.catch((error: unknown) => {
iosInstanceLogger.debug(
'XCTest agent prepare failed while overlapping with simulator boot (surfaced later): %s',
error
);
});

const simulatorStatus = await simctl.getSimulatorStatus(udid);
let startedByHarness = false;

Expand Down Expand Up @@ -127,20 +154,9 @@ export const getAppleSimulatorPlatformInstance = async (
`localhost:${harnessConfig.metroPort}`
);

const xctestAgent = permissionsEnabled
? createXCTestAgentController({
appBundleId: config.bundleId,
target: {
kind: 'simulator',
id: udid,
},
capabilities: [createPermissionPromptAutoAcceptCapability()],
signal: init.signal,
})
: null;

let agentStarted = false;
try {
await preparePromise;
await xctestAgent?.ensureStarted();
agentStarted = true;
} finally {
Expand Down
Loading