Skip to content

Commit 14bb537

Browse files
committed
fix: bound iOS simulator focus timeout
1 parent 7747761 commit 14bb537

3 files changed

Lines changed: 37 additions & 2 deletions

File tree

src/platforms/ios/__tests__/index.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
captureSimulatorScreenshotWithFallback,
2525
resolveSimulatorRunnerScreenshotCandidatePaths,
2626
} from '../screenshot.ts';
27+
import { focusIosSimulatorWindow } from '../simulator.ts';
2728
import type { DeviceInfo } from '../../../utils/device.ts';
2829
import { withDiagnosticsScope } from '../../../utils/diagnostics.ts';
2930
import { AppError } from '../../../utils/errors.ts';
@@ -260,6 +261,31 @@ test('captureSimulatorScreenshotWithFallback emits fallback diagnostic before us
260261
}
261262
});
262263

264+
test('focusIosSimulatorWindow times out instead of hanging indefinitely', async () => {
265+
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'agent-device-ios-focus-timeout-test-'));
266+
const openPath = path.join(tmpDir, 'open');
267+
await fs.writeFile(openPath, '#!/bin/sh\nsleep 10\n', 'utf8');
268+
await fs.chmod(openPath, 0o755);
269+
270+
const previousPath = process.env.PATH;
271+
process.env.PATH = `${tmpDir}${path.delimiter}${previousPath ?? ''}`;
272+
273+
try {
274+
await assert.rejects(
275+
() => focusIosSimulatorWindow(),
276+
(error: unknown) => {
277+
assert.equal(error instanceof AppError, true);
278+
assert.equal((error as AppError).code, 'COMMAND_FAILED');
279+
assert.match((error as AppError).message, /open timed out after 5000ms/);
280+
return true;
281+
},
282+
);
283+
} finally {
284+
process.env.PATH = previousPath;
285+
await fs.rm(tmpDir, { recursive: true, force: true });
286+
}
287+
});
288+
263289
async function waitForFileText(filePath: string, attempts = 20): Promise<string> {
264290
let lastError: unknown;
265291
for (let attempt = 0; attempt < attempts; attempt += 1) {

src/platforms/ios/config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ export const IOS_DEVICECTL_TIMEOUT_MS = resolveTimeoutMs(
2525
1_000,
2626
);
2727

28+
export const IOS_SIMULATOR_FOCUS_TIMEOUT_MS = resolveTimeoutMs(
29+
process.env.AGENT_DEVICE_IOS_SIMULATOR_FOCUS_TIMEOUT_MS,
30+
5_000,
31+
1_000,
32+
);
33+
2834
export const IOS_SIMULATOR_SCREENSHOT_TIMEOUT_MS = resolveTimeoutMs(
2935
process.env.AGENT_DEVICE_IOS_SIMULATOR_SCREENSHOT_TIMEOUT_MS,
3036
20_000,

src/platforms/ios/simulator.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { runCmd } from '../../utils/exec.ts';
44
import { Deadline, retryWithPolicy } from '../../utils/retry.ts';
55
import { bootFailureHint, classifyBootFailure } from '../boot-diagnostics.ts';
66

7-
import { IOS_BOOT_TIMEOUT_MS, IOS_SIMCTL_LIST_TIMEOUT_MS } from './config.ts';
7+
import { IOS_BOOT_TIMEOUT_MS, IOS_SIMCTL_LIST_TIMEOUT_MS, IOS_SIMULATOR_FOCUS_TIMEOUT_MS } from './config.ts';
88
import { buildSimctlArgs, buildSimctlArgsForDevice } from './simctl.ts';
99

1010
export function ensureSimulator(device: DeviceInfo, command: string): void {
@@ -14,7 +14,10 @@ export function ensureSimulator(device: DeviceInfo, command: string): void {
1414
}
1515

1616
export async function focusIosSimulatorWindow(): Promise<void> {
17-
await runCmd('open', ['-a', 'Simulator'], { allowFailure: true });
17+
await runCmd('open', ['-a', 'Simulator'], {
18+
allowFailure: true,
19+
timeoutMs: IOS_SIMULATOR_FOCUS_TIMEOUT_MS,
20+
});
1821
}
1922

2023
export async function ensureBootedSimulator(device: DeviceInfo): Promise<void> {

0 commit comments

Comments
 (0)