Skip to content

Commit 09bc03a

Browse files
committed
test(device): discover the booted simulator race-free
The setup's env-var handoff never reached vitest's workers in CI (global setup and workers don't share an environment), and the discovery regex missed the UDID's closing paren, so sessions saw no booted simulator. Sessions now discover the booted device themselves with a short retry; the setup boots via 'bootstatus -b' — boots if needed, returns promptly when already up — with no simulator state strings to pattern-match.
1 parent 5c9b761 commit 09bc03a

2 files changed

Lines changed: 37 additions & 23 deletions

File tree

tests/device/lib/localIos.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,28 @@ export class LocalIosSession implements DeviceSession {
5050
) {}
5151

5252
static async create(): Promise<LocalIosSession> {
53-
const udid = process.env.BN_IOS_SIMULATOR_UDID;
54-
if (!udid) {
55-
throw new Error(
56-
"BN_IOS_SIMULATOR_UDID is not set — the device-suite setup boots the " +
57-
"simulator and exports it (see lib/tunnel.ts).",
58-
);
53+
// The suite's setup (lib/tunnel.ts) boots a simulator; discover it here
54+
// rather than passing state across processes — vitest's global setup and
55+
// its workers don't share an environment.
56+
let udid: string | undefined;
57+
const deadline = Date.now() + 30_000;
58+
while (!udid) {
59+
const { stdout } = await execFileAsync("xcrun", [
60+
"simctl",
61+
"list",
62+
"devices",
63+
"available",
64+
]);
65+
udid = stdout.match(/([0-9A-F-]{36})\) \(Booted\)/)?.[1];
66+
if (!udid && Date.now() > deadline) {
67+
throw new Error(
68+
"No booted iOS simulator found — the device-suite setup should " +
69+
"have booted one (see lib/tunnel.ts).",
70+
);
71+
}
72+
if (!udid) {
73+
await new Promise((resolve) => setTimeout(resolve, 2_000));
74+
}
5975
}
6076
const driver = await new Builder()
6177
.usingServer(`http://127.0.0.1:${APPIUM_PORT}`)

tests/device/lib/tunnel.ts

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,32 +60,30 @@ async function startBrowserStackTunnel(
6060
}
6161

6262
async function startLocalIos(): Promise<() => Promise<void>> {
63-
// Pick (and if needed boot) an iPhone simulator; sessions attach to it via
64-
// BN_IOS_SIMULATOR_UDID. Headless is fine: XCUITest owns the HID stack, so
63+
// Pick (and if needed boot) an iPhone simulator; sessions discover the
64+
// booted device themselves (vitest's global setup and its workers don't
65+
// share an environment). Headless is fine: XCUITest owns the HID stack, so
6566
// the software keyboard appears without the Simulator GUI.
6667
const { stdout } = await execFileAsync("xcrun", [
6768
"simctl",
6869
"list",
6970
"devices",
7071
"available",
7172
]);
72-
let udid = stdout.match(/([0-9A-F-]{36}) \(Booted\)/)?.[1];
73-
let bootedByUs: string | undefined;
73+
// Prefer a device that is already up; otherwise take the first iPhone.
74+
// `bootstatus -b` boots if needed and returns promptly when already booted,
75+
// so there are no state-string races ("Booted", "Shutting Down", ...) to
76+
// pattern-match.
77+
const already = stdout.match(/iPhone [^(]+\(([0-9A-F-]{36})\) \(Booted\)/);
78+
const any = stdout.match(/iPhone [^(]+\(([0-9A-F-]{36})\)/);
79+
const udid = already?.[1] ?? any?.[1];
7480
if (!udid) {
75-
const device = stdout.match(/iPhone [^(]+\(([0-9A-F-]{36})\) \(Shutdown\)/);
76-
if (!device) {
77-
throw new Error(
78-
"No available iPhone simulator found (xcrun simctl list).",
79-
);
80-
}
81-
bootedByUs = device[1];
82-
udid = bootedByUs;
83-
await execFileAsync("xcrun", ["simctl", "boot", bootedByUs]);
84-
await execFileAsync("xcrun", ["simctl", "bootstatus", bootedByUs], {
85-
timeout: 180_000,
86-
});
81+
throw new Error("No available iPhone simulator found (xcrun simctl list).");
8782
}
88-
process.env.BN_IOS_SIMULATOR_UDID = udid;
83+
await execFileAsync("xcrun", ["simctl", "bootstatus", udid, "-b"], {
84+
timeout: 240_000,
85+
});
86+
const bootedByUs = already ? undefined : udid;
8987

9088
// Appium with the XCUITest driver (an npm devDependency, which Appium
9189
// discovers). Note Appium requires an even-numbered Node (see

0 commit comments

Comments
 (0)