@kraken-e2e/driver-ios 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ import type { Logger } from '@kraken-e2e/contracts';
2
+ /**
3
+ * Idempotent: refreshes symlinks every start (pnpm store paths move); version
4
+ * bumps change the generated package.json, which changes its md5 and triggers
5
+ * Appium's manifest re-sync.
6
+ */
7
+ export declare function prepareAppiumHome(homeDir: string, driverPackages: readonly string[]): void;
8
+ /** Allocates an OS-assigned free port (hazard 1: appium dies on EADDRINUSE). */
9
+ export declare function allocatePort(): Promise<number>;
10
+ export interface AppiumServerHandle {
11
+ readonly port: number;
12
+ close(): Promise<void>;
13
+ }
14
+ export interface StartServerOptions {
15
+ readonly homeDir: string;
16
+ readonly driverPackages: readonly string[];
17
+ readonly logFile: string;
18
+ readonly logger: Logger;
19
+ /** Appium 3 scoped syntax, e.g. 'uiautomator2:adb_shell'. */
20
+ readonly allowInsecure?: readonly string[];
21
+ }
22
+ export declare function startAppiumServer(options: StartServerOptions): Promise<AppiumServerHandle>;
23
+ //# sourceMappingURL=appium-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appium-server.d.ts","sourceRoot":"","sources":["../src/appium-server.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAWpD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAkC1F;AAED,gFAAgF;AAChF,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAapD;AAeD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA+DhG"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Embedded Appium server lifecycle (ADR-0008, mechanism live-verified against
3
+ * appium@3.5.2):
4
+ *
5
+ * SYNTHESIZED PROJECT-MODE HOME — we generate an APPIUM_HOME whose
6
+ * package.json declares the EXACT appium+driver versions resolved from THIS
7
+ * package's own dependency tree (lockfile-governed, ADR-0001 §5.10) and
8
+ * symlink the resolved packages into its node_modules. Appium's project-mode
9
+ * manifest auto-discovers them; no `appium driver install` ever runs
10
+ * (`--source=local` is verified broken: it shells to `npm link`, which fires
11
+ * the drivers' `prepare` scripts and fails on published tarballs).
12
+ *
13
+ * Live-verified hazards handled here:
14
+ * - EADDRINUSE calls process.exit(1) even with throwInsteadOfExit → we
15
+ * allocate the port ourselves immediately before boot.
16
+ * - main() installs its own SIGINT/SIGTERM handlers that process.exit(0) →
17
+ * we strip them so the Kraken CLI owns signals (ADR-0001 §5.11).
18
+ */
19
+ import { mkdirSync, renameSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
20
+ import { createRequire } from 'node:module';
21
+ import { createServer } from 'node:net';
22
+ import { dirname, join } from 'node:path';
23
+ import { KrakenError } from '@kraken-e2e/contracts';
24
+ const require_ = createRequire(import.meta.url);
25
+ function resolvedPackage(name) {
26
+ const packageJsonPath = require_.resolve(`${name}/package.json`);
27
+ const { version } = require_(packageJsonPath);
28
+ return { dir: dirname(packageJsonPath), version };
29
+ }
30
+ /**
31
+ * Idempotent: refreshes symlinks every start (pnpm store paths move); version
32
+ * bumps change the generated package.json, which changes its md5 and triggers
33
+ * Appium's manifest re-sync.
34
+ */
35
+ export function prepareAppiumHome(homeDir, driverPackages) {
36
+ const nodeModules = join(homeDir, 'node_modules');
37
+ mkdirSync(nodeModules, { recursive: true });
38
+ const appium = resolvedPackage('appium');
39
+ const dependencies = { appium: appium.version };
40
+ for (const name of [...driverPackages, 'appium']) {
41
+ const resolved = name === 'appium' ? appium : resolvedPackage(name);
42
+ if (name !== 'appium')
43
+ dependencies[name] = resolved.version;
44
+ const linkPath = join(nodeModules, name);
45
+ mkdirSync(dirname(linkPath), { recursive: true });
46
+ // Concurrent-run-safe replace: symlink to a temp name, rename over the
47
+ // target (atomic on POSIX) — a plain rm+symlink pair races a sibling run.
48
+ const tempLink = `${linkPath}.tmp-${process.pid}`;
49
+ rmSync(tempLink, { force: true });
50
+ symlinkSync(resolved.dir, tempLink, 'dir');
51
+ rmSync(linkPath, { recursive: true, force: true });
52
+ renameSync(tempLink, linkPath);
53
+ }
54
+ writeFileSync(join(homeDir, 'package.json'), `${JSON.stringify({
55
+ name: 'kraken-appium-home',
56
+ private: true,
57
+ description: 'Generated by Kraken — appium project-mode home (ADR-0008). Do not edit.',
58
+ dependencies,
59
+ }, null, 2)}\n`);
60
+ }
61
+ /** Allocates an OS-assigned free port (hazard 1: appium dies on EADDRINUSE). */
62
+ export async function allocatePort() {
63
+ return new Promise((resolve, reject) => {
64
+ const probe = createServer();
65
+ probe.once('error', reject);
66
+ probe.listen(0, '127.0.0.1', () => {
67
+ const address = probe.address();
68
+ const port = typeof address === 'object' && address !== null ? address.port : undefined;
69
+ probe.close(() => {
70
+ if (port === undefined)
71
+ reject(new Error('could not allocate a port'));
72
+ else
73
+ resolve(port);
74
+ });
75
+ });
76
+ });
77
+ }
78
+ function stripAddedSignalHandlers(before) {
79
+ for (const signal of ['SIGINT', 'SIGTERM']) {
80
+ for (const listener of process.listeners(signal)) {
81
+ if (!before[signal].includes(listener)) {
82
+ process.removeListener(signal, listener);
83
+ }
84
+ }
85
+ }
86
+ }
87
+ export async function startAppiumServer(options) {
88
+ prepareAppiumHome(options.homeDir, options.driverPackages);
89
+ mkdirSync(dirname(options.logFile), { recursive: true });
90
+ // Import-safety rule (ADR-0001 §5.5): appium loads HERE, never at top level.
91
+ // Non-literal specifier: appium ships raw .ts type sources that explode under
92
+ // strict verbatimModuleSyntax; we type the surface we use by hand instead.
93
+ const appiumSpecifier = 'appium';
94
+ // The package is CJS — named ESM imports fail; use the default namespace.
95
+ const appiumModule = (await import(appiumSpecifier));
96
+ const main = appiumModule.default?.main ?? appiumModule.main;
97
+ if (!main) {
98
+ throw new KrakenError('KRK-DRIVER-START-FAILED', 'appium package has no main() export.');
99
+ }
100
+ // Allocate AFTER the (slow, seconds-cold) appium import so the port-reuse
101
+ // race window stays microseconds — appium process.exit(1)s on EADDRINUSE.
102
+ const port = await allocatePort();
103
+ // Hazard 2: strip the SIGINT/SIGTERM handlers main() installs.
104
+ const before = {
105
+ SIGINT: process.listeners('SIGINT'),
106
+ SIGTERM: process.listeners('SIGTERM'),
107
+ };
108
+ options.logger.info('starting embedded Appium server', {
109
+ port,
110
+ home: options.homeDir,
111
+ logFile: options.logFile,
112
+ });
113
+ let server;
114
+ try {
115
+ server = (await main({
116
+ subcommand: 'server',
117
+ port,
118
+ address: '127.0.0.1',
119
+ appiumHome: options.homeDir,
120
+ throwInsteadOfExit: true,
121
+ // Quiet console (the TUI owns stdout), full debug into the log file.
122
+ loglevel: 'error:debug',
123
+ logFile: options.logFile,
124
+ ...(options.allowInsecure !== undefined ? { allowInsecure: [...options.allowInsecure] } : {}),
125
+ }));
126
+ }
127
+ catch (cause) {
128
+ stripAddedSignalHandlers(before);
129
+ throw KrakenError.wrap(cause, 'KRK-DRIVER-START-FAILED', 'embedded Appium failed to start');
130
+ }
131
+ // Appium registers its handlers in a continuation AFTER main() resolves
132
+ // (live-verified) — wait one macrotask before stripping.
133
+ await new Promise((resolve) => setImmediate(resolve));
134
+ stripAddedSignalHandlers(before);
135
+ options.logger.info('Appium server ready', { port });
136
+ return {
137
+ port,
138
+ close: async () => {
139
+ await server.close();
140
+ options.logger.info('Appium server stopped', { port });
141
+ },
142
+ };
143
+ }
144
+ //# sourceMappingURL=appium-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appium-server.js","sourceRoot":"","sources":["../src/appium-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { DoctorCheck } from '@kraken-e2e/contracts';
2
+ /** Injectable so doctor checks are unit-testable without Xcode. */
3
+ export type CommandRunner = (command: string, args: readonly string[]) => {
4
+ status: number | null;
5
+ stdout: string;
6
+ };
7
+ export declare const spawnRunner: CommandRunner;
8
+ /**
9
+ * Kraken-specific iOS checks (ADR-0001 §5.13). These only ever run on macOS —
10
+ * on other hosts the driver is host-gated off before checks are collected.
11
+ * The classic student trap is covered explicitly: a fresh Xcode passes binary
12
+ * checks yet has ZERO simulator runtimes (separate downloads since Xcode 14).
13
+ */
14
+ export declare function iosDoctorChecks(run?: CommandRunner): readonly DoctorCheck[];
15
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,mEAAmE;AACnE,MAAM,MAAM,aAAa,GAAG,CAC1B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,KACpB;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C,eAAO,MAAM,WAAW,EAAE,aAGzB,CAAC;AAKF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,aAA2B,GAAG,SAAS,WAAW,EAAE,CAwExF"}
package/dist/doctor.js ADDED
@@ -0,0 +1,86 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ export const spawnRunner = (command, args) => {
3
+ const result = spawnSync(command, [...args], { encoding: 'utf8', timeout: 30_000 });
4
+ return { status: result.status, stdout: `${result.stdout ?? ''}${result.stderr ?? ''}` };
5
+ };
6
+ /** Xcode majors fully supported by appium-xcuitest-driver 11.x (ADR-0001 §4). */
7
+ const SUPPORTED_XCODE_MAJORS = [16, 26];
8
+ /**
9
+ * Kraken-specific iOS checks (ADR-0001 §5.13). These only ever run on macOS —
10
+ * on other hosts the driver is host-gated off before checks are collected.
11
+ * The classic student trap is covered explicitly: a fresh Xcode passes binary
12
+ * checks yet has ZERO simulator runtimes (separate downloads since Xcode 14).
13
+ */
14
+ export function iosDoctorChecks(run = spawnRunner) {
15
+ return [
16
+ {
17
+ id: 'ios.xcode',
18
+ title: `Xcode present and inside the xcuitest-driver support window (${SUPPORTED_XCODE_MAJORS.join('.x / ')}.x)`,
19
+ run: async () => {
20
+ const selected = run('xcode-select', ['-p']);
21
+ if (selected.status !== 0) {
22
+ return {
23
+ status: 'fail',
24
+ detail: 'no developer directory selected',
25
+ fix: 'Install Xcode from the App Store, then: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer',
26
+ };
27
+ }
28
+ const version = run('xcodebuild', ['-version']);
29
+ const major = Number.parseInt(/Xcode\s+(\d+)/.exec(version.stdout)?.[1] ?? '0', 10);
30
+ if (version.status !== 0 || major === 0) {
31
+ return {
32
+ status: 'fail',
33
+ detail: 'xcodebuild did not run',
34
+ fix: 'Open Xcode once to finish first-launch setup, then re-run kraken doctor.',
35
+ };
36
+ }
37
+ if (!SUPPORTED_XCODE_MAJORS.includes(major)) {
38
+ return {
39
+ status: major < 16 ? 'fail' : 'warn',
40
+ detail: `Xcode ${major} found`,
41
+ fix: `appium-xcuitest-driver 11.x fully supports the latest two Xcode majors ` +
42
+ `(${SUPPORTED_XCODE_MAJORS.join(', ')}). Upgrade/downgrade Xcode or expect breakage — ` +
43
+ 'this window moves every September (ADR-0001 §8.3).',
44
+ };
45
+ }
46
+ return { status: 'ok', detail: version.stdout.split('\n')[0] ?? `Xcode ${major}` };
47
+ },
48
+ },
49
+ {
50
+ id: 'ios.simulator-runtimes',
51
+ title: 'An iOS simulator runtime is installed (separate download since Xcode 14)',
52
+ run: async () => {
53
+ const result = run('xcrun', ['simctl', 'list', 'runtimes']);
54
+ const runtimes = result.stdout.split('\n').filter((line) => line.trim().startsWith('iOS '));
55
+ if (result.status !== 0 || runtimes.length === 0) {
56
+ return {
57
+ status: 'fail',
58
+ detail: 'no iOS simulator runtime found',
59
+ fix: 'Download one: xcodebuild -downloadPlatform iOS (or Xcode → Settings → Components). A fresh Xcode install ships with ZERO runtimes.',
60
+ };
61
+ }
62
+ return {
63
+ status: 'ok',
64
+ detail: runtimes.map((line) => line.trim().split(' (')[0]).join(', '),
65
+ };
66
+ },
67
+ },
68
+ {
69
+ id: 'ios.simulators',
70
+ title: 'At least one iPhone simulator is available',
71
+ run: async () => {
72
+ const result = run('xcrun', ['simctl', 'list', 'devices', 'available']);
73
+ const iphones = result.stdout.split('\n').filter((line) => line.includes('iPhone'));
74
+ if (result.status !== 0 || iphones.length === 0) {
75
+ return {
76
+ status: 'fail',
77
+ detail: 'no available iPhone simulators',
78
+ fix: 'Create one: xcrun simctl create "iPhone 16" (or Xcode → Devices and Simulators).',
79
+ };
80
+ }
81
+ return { status: 'ok', detail: `${iphones.length} iPhone simulator(s) available` };
82
+ },
83
+ },
84
+ ];
85
+ }
86
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export interface IosDriverOptions {
2
+ /** Default simulator for actors without a device (appium:deviceName). */
3
+ readonly deviceName?: string;
4
+ /** Default appium:platformVersion (e.g. '18.6'). */
5
+ readonly platformVersion?: string;
6
+ /**
7
+ * Prebuilt WebDriverAgent .app for simulators (appium:prebuiltWDAPath +
8
+ * usePreinstalledWDA — requires iOS 17+). Skips the slow first-session
9
+ * xcodebuild. Fetch one with: appium driver run xcuitest download-wda.
10
+ */
11
+ readonly prebuiltWDAPath?: string;
12
+ /** Appium 3 scoped insecure features. */
13
+ readonly allowInsecure?: readonly string[];
14
+ /** Extra capabilities merged into every session. */
15
+ readonly capabilities?: Readonly<Record<string, unknown>>;
16
+ }
17
+ export declare const ios: (opts?: IosDriverOptions | undefined) => import("@kraken-e2e/contracts").KrakenDriver<IosDriverOptions>;
18
+ export default ios;
19
+ export { allocatePort, prepareAppiumHome, startAppiumServer } from './appium-server.js';
20
+ export { iosDoctorChecks } from './doctor.js';
21
+ export { toIosSelector } from './locators.js';
22
+ export { manifest } from './manifest.js';
23
+ export { IosUserSession } from './wdio-session.js';
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,oDAAoD;IACpD,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,yCAAyC;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,oDAAoD;IACpD,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC3D;AAED,eAAO,MAAM,GAAG,yGAqFd,CAAC;AAEH,eAAe,GAAG,CAAC;AACnB,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,97 @@
1
+ /**
2
+ * @kraken-e2e/driver-ios — iOS driver (Appium 3 + XCUITest, ADR-0008).
3
+ *
4
+ * macOS-ONLY at runtime (Apple platform restriction — enforced by the
5
+ * registry via /manifest hostRequirements, C4b). IMPORT-SAFETY RULE
6
+ * (ADR-0001 §5.5): this entry must still be importable on every host —
7
+ * appium and webdriverio load DYNAMICALLY inside start()/createSession().
8
+ */
9
+ import { join } from 'node:path';
10
+ import { defineDriver } from '@kraken-e2e/contracts';
11
+ import { allocatePort, startAppiumServer } from './appium-server.js';
12
+ import { iosDoctorChecks } from './doctor.js';
13
+ import { manifest } from './manifest.js';
14
+ import { IosUserSession } from './wdio-session.js';
15
+ export const ios = defineDriver((opts = {}) => {
16
+ let server;
17
+ return {
18
+ manifest,
19
+ doctor: iosDoctorChecks(),
20
+ async start(host, services) {
21
+ if (server) {
22
+ // Double start would silently leak the first embedded server.
23
+ throw new Error('driver-ios: already started — call stop() first.');
24
+ }
25
+ const projectRoot = host.projectRoot ?? process.cwd();
26
+ server = await startAppiumServer({
27
+ homeDir: join(projectRoot, '.kraken', 'appium', 'ios-home'),
28
+ driverPackages: ['appium-xcuitest-driver'],
29
+ logFile: join(services.artifactsDir, 'appium-ios.log'),
30
+ logger: services.logger,
31
+ ...(opts.allowInsecure !== undefined ? { allowInsecure: opts.allowInsecure } : {}),
32
+ });
33
+ },
34
+ async createSession(actor, services) {
35
+ if (!server) {
36
+ throw new Error('driver-ios: start() must run before createSession().');
37
+ }
38
+ const config = actor.config;
39
+ // OS-assigned free ports (see driver-android note: fixed-base counters
40
+ // collide across concurrent runs on one machine).
41
+ const wdaLocalPort = await allocatePort();
42
+ const mjpegServerPort = await allocatePort();
43
+ const prebuiltWDAPath = typeof config['prebuiltWDAPath'] === 'string'
44
+ ? config['prebuiltWDAPath']
45
+ : opts.prebuiltWDAPath;
46
+ const capabilities = {
47
+ platformName: 'iOS',
48
+ 'appium:automationName': 'XCUITest',
49
+ 'appium:wdaLocalPort': wdaLocalPort,
50
+ 'appium:mjpegServerPort': mjpegServerPort,
51
+ 'appium:newCommandTimeout': 300,
52
+ // First-session xcodebuild of WDA can take minutes on a laptop.
53
+ 'appium:wdaLaunchTimeout': 120_000,
54
+ 'appium:deviceName': config['deviceName'] ?? opts.deviceName ?? 'iPhone 16',
55
+ ...(typeof config['platformVersion'] === 'string' || opts.platformVersion !== undefined
56
+ ? {
57
+ 'appium:platformVersion': config['platformVersion'] ?? opts.platformVersion,
58
+ }
59
+ : {}),
60
+ ...(typeof config['udid'] === 'string' ? { 'appium:udid': config['udid'] } : {}),
61
+ ...(typeof config['app'] === 'string' ? { 'appium:app': config['app'] } : {}),
62
+ ...(typeof config['bundleId'] === 'string'
63
+ ? { 'appium:bundleId': config['bundleId'] }
64
+ : {}),
65
+ ...(prebuiltWDAPath !== undefined
66
+ ? { 'appium:usePreinstalledWDA': true, 'appium:prebuiltWDAPath': prebuiltWDAPath }
67
+ : {}),
68
+ ...opts.capabilities,
69
+ ...(typeof config['capabilities'] === 'object' && config['capabilities'] !== null
70
+ ? config['capabilities']
71
+ : {}),
72
+ };
73
+ services.logger.info('creating iOS session', { actor: actor.id, wdaLocalPort });
74
+ const { remote } = await import('webdriverio');
75
+ const browser = await remote({
76
+ hostname: '127.0.0.1',
77
+ port: server.port,
78
+ capabilities: capabilities,
79
+ logLevel: 'error',
80
+ connectionRetryTimeout: 300_000,
81
+ connectionRetryCount: 1,
82
+ });
83
+ return new IosUserSession(browser, actor, services);
84
+ },
85
+ async stop() {
86
+ await server?.close();
87
+ server = undefined;
88
+ },
89
+ };
90
+ });
91
+ export default ios;
92
+ export { allocatePort, prepareAppiumHome, startAppiumServer } from './appium-server.js';
93
+ export { iosDoctorChecks } from './doctor.js';
94
+ export { toIosSelector } from './locators.js';
95
+ export { manifest } from './manifest.js';
96
+ export { IosUserSession } from './wdio-session.js';
97
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { TargetLocator } from '@kraken-e2e/contracts';
2
+ /**
3
+ * Portable locator strategies → XCUITest selectors (ADR-0002 D1 mapping:
4
+ * testId → accessibility identifier, a11y → accessibility identifier,
5
+ * text → label/value predicate).
6
+ */
7
+ export declare function toIosSelector(target: TargetLocator): string;
8
+ /**
9
+ * HID keyboard usages (page 0x07) for the semantic keys — the FAITHFUL iOS
10
+ * implementation (contract 2.0), live-verified on iOS 18.6: Return commits
11
+ * and dismisses the keyboard, Escape performs UIKit's hardware-Escape cancel,
12
+ * Tab behaves as hardware Tab. Injected device-level via WDA's
13
+ * performIoHidEvent — no hardware-keyboard setting required.
14
+ */
15
+ export declare const IOS_HID_KEY_USAGES: Readonly<Record<import('@kraken-e2e/contracts').SemanticKey, number>>;
16
+ //# sourceMappingURL=locators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locators.d.ts","sourceRoot":"","sources":["../src/locators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAgB3D;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CACvC,MAAM,CAAC,OAAO,uBAAuB,EAAE,WAAW,EAAE,MAAM,CAAC,CAK5D,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Portable locator strategies → XCUITest selectors (ADR-0002 D1 mapping:
3
+ * testId → accessibility identifier, a11y → accessibility identifier,
4
+ * text → label/value predicate).
5
+ */
6
+ export function toIosSelector(target) {
7
+ switch (target.by) {
8
+ case 'testId':
9
+ case 'a11y':
10
+ return `~${target.value}`;
11
+ case 'text': {
12
+ const escaped = target.value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
13
+ return target.exact
14
+ ? `-ios predicate string:label == "${escaped}" OR value == "${escaped}"`
15
+ : `-ios predicate string:label CONTAINS "${escaped}" OR value CONTAINS "${escaped}"`;
16
+ }
17
+ case 'native':
18
+ // Explicitly non-portable: any raw WebdriverIO/Appium selector string
19
+ // (class chains, predicates, xpath).
20
+ return target.value;
21
+ }
22
+ }
23
+ /**
24
+ * HID keyboard usages (page 0x07) for the semantic keys — the FAITHFUL iOS
25
+ * implementation (contract 2.0), live-verified on iOS 18.6: Return commits
26
+ * and dismisses the keyboard, Escape performs UIKit's hardware-Escape cancel,
27
+ * Tab behaves as hardware Tab. Injected device-level via WDA's
28
+ * performIoHidEvent — no hardware-keyboard setting required.
29
+ */
30
+ export const IOS_HID_KEY_USAGES = {
31
+ enter: 0x28, // Keyboard Return
32
+ escape: 0x29, // Keyboard Escape
33
+ tab: 0x2b, // Keyboard Tab
34
+ };
35
+ //# sourceMappingURL=locators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locators.js","sourceRoot":"","sources":["../src/locators.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,QAAQ,MAAM,CAAC,EAAE,EAAE,CAAC;QAClB,KAAK,QAAQ,CAAC;QACd,KAAK,MAAM;YACT,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAC5B,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACzE,OAAO,MAAM,CAAC,KAAK;gBACjB,CAAC,CAAC,mCAAmC,OAAO,kBAAkB,OAAO,GAAG;gBACxE,CAAC,CAAC,yCAAyC,OAAO,wBAAwB,OAAO,GAAG,CAAC;QACzF,CAAC;QACD,KAAK,QAAQ;YACX,sEAAsE;YACtE,qCAAqC;YACrC,OAAO,MAAM,CAAC,KAAK,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAE3B;IACF,KAAK,EAAE,IAAI,EAAE,kBAAkB;IAC/B,MAAM,EAAE,IAAI,EAAE,kBAAkB;IAChC,GAAG,EAAE,IAAI,EAAE,eAAe;CAC3B,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The /manifest subpath (ADR-0001 §5.5): ZERO heavy imports — on non-macOS
3
+ * hosts the registry reads THIS and hard-disables the driver with an explicit
4
+ * message; the main entry (and its Appium/Xcode-touching dependencies) is
5
+ * never imported there. NOTE: this package must NEVER set npm's "os" field —
6
+ * it would break `pnpm install` for non-mac teammates sharing the lockfile
7
+ * (ADR-0001 §5.10).
8
+ */
9
+ import { type DriverManifest } from '@kraken-e2e/contracts';
10
+ export declare const manifest: DriverManifest;
11
+ export default manifest;
12
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE9E,eAAO,MAAM,QAAQ,EAAE,cAetB,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The /manifest subpath (ADR-0001 §5.5): ZERO heavy imports — on non-macOS
3
+ * hosts the registry reads THIS and hard-disables the driver with an explicit
4
+ * message; the main entry (and its Appium/Xcode-touching dependencies) is
5
+ * never imported there. NOTE: this package must NEVER set npm's "os" field —
6
+ * it would break `pnpm install` for non-mac teammates sharing the lockfile
7
+ * (ADR-0001 §5.10).
8
+ */
9
+ import { CONTRACT_VERSION } from '@kraken-e2e/contracts';
10
+ export const manifest = {
11
+ kind: 'kraken-driver',
12
+ id: 'ios',
13
+ platforms: ['ios'],
14
+ version: '0.0.0',
15
+ contract: CONTRACT_VERSION,
16
+ platformLabel: 'iOS (XCUITest via Appium 3)',
17
+ hostRequirements: { platforms: ['darwin'] },
18
+ disabledFix: 'The iOS driver requires macOS: XCUITest and WebDriverAgent are Apple platform ' +
19
+ 'restrictions, not a Kraken limitation. Android and Web drivers work on this host.',
20
+ setupHints: [
21
+ 'Install Xcode (16+ / 26.x recommended) and an iOS simulator runtime',
22
+ 'Run: kraken doctor',
23
+ ],
24
+ };
25
+ export default manifest;
26
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,gBAAgB,EAAuB,MAAM,uBAAuB,CAAC;AAE9E,MAAM,CAAC,MAAM,QAAQ,GAAmB;IACtC,IAAI,EAAE,eAAe;IACrB,EAAE,EAAE,KAAK;IACT,SAAS,EAAE,CAAC,KAAK,CAAC;IAClB,OAAO,EAAE,OAAO;IAChB,QAAQ,EAAE,gBAAgB;IAC1B,aAAa,EAAE,6BAA6B;IAC5C,gBAAgB,EAAE,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE;IAC3C,WAAW,EACT,gFAAgF;QAChF,mFAAmF;IACrF,UAAU,EAAE;QACV,qEAAqE;QACrE,oBAAoB;KACrB;CACF,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { type ArtifactRef, type CoreOperation, type DriverServices, type ResolvedActor, type SemanticKey, type SessionWaitOptions, type TargetLocator, type UserSession, type WaitState } from '@kraken-e2e/contracts';
2
+ /** Same narrow WDIO slice as driver-android (kept per-driver: contracts-only edges). */
3
+ export interface WdioBrowserLike {
4
+ $(selector: string): Promise<WdioElementLike>;
5
+ execute(script: string, args?: unknown): Promise<unknown>;
6
+ takeScreenshot(): Promise<string>;
7
+ getPageSource(): Promise<string>;
8
+ deleteSession(): Promise<void>;
9
+ }
10
+ export interface WdioElementLike {
11
+ readonly error?: {
12
+ message?: string;
13
+ };
14
+ elementId?: string | undefined;
15
+ click(): Promise<void>;
16
+ setValue(text: string): Promise<void>;
17
+ getText(): Promise<string>;
18
+ isDisplayed(): Promise<boolean>;
19
+ isExisting(): Promise<boolean>;
20
+ waitForDisplayed(options?: {
21
+ timeout?: number;
22
+ interval?: number;
23
+ reverse?: boolean;
24
+ }): Promise<unknown>;
25
+ waitForExist(options?: {
26
+ timeout?: number;
27
+ interval?: number;
28
+ }): Promise<unknown>;
29
+ }
30
+ /**
31
+ * UserSession adapter for XCUITest. All 11 core operations are supported —
32
+ * pressKey included, via device-level HID keyboard events (contract 2.0):
33
+ * the M1 gate first BLOCKED on a pressKey asymmetry, the mandated research
34
+ * found the faithful mechanism, and SemanticKey was redefined (back removed —
35
+ * an Android-only concept). Governance working as designed (ADR-0001 §5.4).
36
+ */
37
+ export declare class IosUserSession implements UserSession {
38
+ #private;
39
+ private readonly browser;
40
+ private readonly services;
41
+ readonly actorId: string;
42
+ readonly driverId = "ios";
43
+ readonly platform: string;
44
+ readonly capabilities: Readonly<Record<CoreOperation, 'supported' | 'unsupported'>>;
45
+ constructor(browser: WdioBrowserLike, actor: ResolvedActor, services: DriverServices);
46
+ tap(target: TargetLocator): Promise<void>;
47
+ typeText(target: TargetLocator, text: string): Promise<void>;
48
+ readText(target: TargetLocator): Promise<string>;
49
+ waitFor(target: TargetLocator, state: WaitState, opts?: SessionWaitOptions): Promise<void>;
50
+ isDisplayed(target: TargetLocator): Promise<boolean>;
51
+ scrollIntoView(target: TargetLocator): Promise<void>;
52
+ pressKey(key: SemanticKey): Promise<void>;
53
+ navigate(destination: string): Promise<void>;
54
+ screenshot(): Promise<ArtifactRef>;
55
+ source(): Promise<string>;
56
+ dispose(): Promise<void>;
57
+ native<K extends never>(kind: K): never;
58
+ }
59
+ //# sourceMappingURL=wdio-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wdio-session.d.ts","sourceRoot":"","sources":["../src/wdio-session.ts"],"names":[],"mappings":"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"}