Skip to content
Merged
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
50 changes: 50 additions & 0 deletions src/core/interactors/__tests__/apple-watchos-sentinel.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { test, expect } from 'vitest';
import { createAppleInteractor } from '../apple.ts';
import type { DeviceInfo } from '../../../kernel/device.ts';
import type { RunnerContext } from '../../interactor-types.ts';
import { AppError } from '../../../kernel/errors.ts';

// watchOS is an explicit unsupported sentinel: XCUITest cannot drive watchOS UI,
// so a `appleOs: 'watchos'` device must be rejected at interactor creation (the
// admission seam) rather than silently falling through to the iOS runner.
const watchOsDevice: DeviceInfo = {
platform: 'ios',
id: 'watch-1',
name: 'Apple Watch Series 10',
kind: 'device',
appleOs: 'watchos',
};

test('createAppleInteractor rejects a watchOS device as UNSUPPORTED_PLATFORM', () => {
// The guard throws before touching runnerContext, so an empty context is fine.
const create = () => createAppleInteractor(watchOsDevice, {} as RunnerContext);
expect(create).toThrow(AppError);
try {
create();
expect.unreachable('expected createAppleInteractor to throw for watchOS');
} catch (error) {
expect(error).toBeInstanceOf(AppError);
expect((error as AppError).code).toBe('UNSUPPORTED_PLATFORM');
expect((error as AppError).message).toMatch(/watchOS/i);
}
});

test('a non-watchOS appleOs does not trigger the watchOS sentinel', () => {
// A tvOS device must not throw the watchOS-specific rejection. (It may still
// fail later on the empty runner context, so we only assert it is not the
// watchOS sentinel error.)
const tvOsDevice: DeviceInfo = {
platform: 'ios',
id: 'tv-1',
name: 'Apple TV 4K',
kind: 'simulator',
target: 'tv',
appleOs: 'tvos',
booted: true,
};
try {
createAppleInteractor(tvOsDevice, {} as RunnerContext);
} catch (error) {
expect((error as AppError).message ?? '').not.toMatch(/watchOS/i);
}
});
10 changes: 10 additions & 0 deletions src/core/interactors/apple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ export function createAppleInteractor(
device: DeviceInfo,
runnerContext: RunnerContext,
): Interactor {
// watchOS unsupported sentinel: XCUITest cannot drive watchOS UI (no
// XCUIApplication), so a watchOS device has no runner backend. Reject it
// explicitly here rather than letting `appleOs: 'watchos'` silently fall
// through to the iOS runner profile (see resolveRunnerPlatformNameForAppleOs).
if (device.appleOs === 'watchos') {
throw new AppError(
'UNSUPPORTED_PLATFORM',
'watchOS is not supported: XCUITest cannot drive watchOS UI, so this device has no runner backend.',
);
}
const { overrides, runnerOpts } = iosRunnerOverrides(device, runnerContext);
return {
open: (app, options) =>
Expand Down
Loading