@delacour/warden-e2e 0.0.0-stage → 0.1.1
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.
- package/LICENSE +21 -0
- package/chunk-qtkmfjbq.mjs +4585 -0
- package/index.d.ts +1 -0
- package/index.mjs +998 -0
- package/package.json +49 -4
- package/preload.d.ts +1 -0
- package/preload.mjs +5512 -0
- package/types/core/src/allocate.d.ts +23 -0
- package/types/core/src/builds/app-option.schema.d.ts +37 -0
- package/types/core/src/builds/install.d.ts +95 -0
- package/types/core/src/builds/resolve.d.ts +74 -0
- package/types/core/src/config.defaults.d.ts +25 -0
- package/types/core/src/exec.d.ts +18 -0
- package/types/core/src/liveness.d.ts +12 -0
- package/types/core/src/providers/android.d.ts +124 -0
- package/types/core/src/providers/health.d.ts +45 -0
- package/types/core/src/providers/provider.types.d.ts +56 -0
- package/types/core/src/store.d.ts +91 -0
- package/types/core/src/types.d.ts +106 -0
- package/types/e2e/src/alert-buttons.d.ts +41 -0
- package/types/e2e/src/alert-reader.d.ts +25 -0
- package/types/e2e/src/app.d.ts +62 -0
- package/types/e2e/src/device-devtools.d.ts +26 -0
- package/types/e2e/src/device-link.d.ts +43 -0
- package/types/e2e/src/device.d.ts +82 -0
- package/types/e2e/src/devtools/cdp.d.ts +65 -0
- package/types/e2e/src/devtools/console.d.ts +59 -0
- package/types/e2e/src/devtools/devtools.types.d.ts +169 -0
- package/types/e2e/src/devtools/facet.d.ts +28 -0
- package/types/e2e/src/devtools/inspector.d.ts +48 -0
- package/types/e2e/src/devtools/jsonl.d.ts +4 -0
- package/types/e2e/src/devtools/network.d.ts +33 -0
- package/types/e2e/src/devtools/network.script.d.ts +24 -0
- package/types/e2e/src/devtools/session.d.ts +82 -0
- package/types/e2e/src/devtools/tree.d.ts +23 -0
- package/types/e2e/src/devtools/tree.script.d.ts +33 -0
- package/types/e2e/src/driver/alerts.d.ts +29 -0
- package/types/e2e/src/driver/android/adb-session.d.ts +52 -0
- package/types/e2e/src/driver/android/android-alert.d.ts +4 -0
- package/types/e2e/src/driver/android/android-animations.d.ts +29 -0
- package/types/e2e/src/driver/android/android-app.d.ts +32 -0
- package/types/e2e/src/driver/android/android-argv.d.ts +122 -0
- package/types/e2e/src/driver/android/android-device.d.ts +44 -0
- package/types/e2e/src/driver/android/android-driver.d.ts +60 -0
- package/types/e2e/src/driver/android/android-dump.d.ts +46 -0
- package/types/e2e/src/driver/android/android-state.d.ts +69 -0
- package/types/e2e/src/driver/android/uiad-backend.d.ts +63 -0
- package/types/e2e/src/driver/android/uiad-client.d.ts +60 -0
- package/types/e2e/src/driver/android/uiad-device.d.ts +70 -0
- package/types/e2e/src/driver/android/uiad-dex.generated.d.ts +8 -0
- package/types/e2e/src/driver/android/uiad-ops.d.ts +62 -0
- package/types/e2e/src/driver/android/uiad-protocol.d.ts +209 -0
- package/types/e2e/src/driver/android/uiautomator.d.ts +33 -0
- package/types/e2e/src/driver/driver.types.d.ts +231 -0
- package/types/e2e/src/driver/errors.d.ts +13 -0
- package/types/e2e/src/driver/gesture-geometry.d.ts +48 -0
- package/types/e2e/src/driver/ios/ios-driver.d.ts +63 -0
- package/types/e2e/src/driver/ios/ios-session.d.ts +30 -0
- package/types/e2e/src/driver/ios/locate-helper.d.ts +38 -0
- package/types/e2e/src/driver/ios/normalize.d.ts +11 -0
- package/types/e2e/src/driver/ios/simctl.d.ts +87 -0
- package/types/e2e/src/driver/ios/simd-client.d.ts +68 -0
- package/types/e2e/src/driver/ios/simd-protocol.d.ts +433 -0
- package/types/e2e/src/driver/ios/simd-transport.d.ts +43 -0
- package/types/e2e/src/driver/ios/type-budget.d.ts +6 -0
- package/types/e2e/src/driver/observation-cache.d.ts +66 -0
- package/types/e2e/src/driver/open.d.ts +29 -0
- package/types/e2e/src/driver/settle.d.ts +43 -0
- package/types/e2e/src/driver/span-detail.d.ts +12 -0
- package/types/e2e/src/driver/traced-driver.d.ts +14 -0
- package/types/e2e/src/driver/typing.d.ts +48 -0
- package/types/e2e/src/driver/unwrap.d.ts +13 -0
- package/types/e2e/src/env.d.ts +61 -0
- package/types/e2e/src/errors.d.ts +26 -0
- package/types/e2e/src/expect/expect.d.ts +27 -0
- package/types/e2e/src/expect/matchers.d.ts +72 -0
- package/types/e2e/src/fixture-session.d.ts +34 -0
- package/types/e2e/src/fixtures.d.ts +14 -0
- package/types/e2e/src/index.d.ts +8 -0
- package/types/e2e/src/preload.d.ts +29 -0
- package/types/e2e/src/runner/artifacts.d.ts +13 -0
- package/types/e2e/src/runner/attempt.d.ts +63 -0
- package/types/e2e/src/runner/callsite.d.ts +2 -0
- package/types/e2e/src/runner/failure.d.ts +28 -0
- package/types/e2e/src/runner/fixtures.types.d.ts +60 -0
- package/types/e2e/src/runner/results.d.ts +48 -0
- package/types/e2e/src/runner/scope.d.ts +62 -0
- package/types/e2e/src/runner/span.d.ts +40 -0
- package/types/e2e/src/runner/step.d.ts +7 -0
- package/types/e2e/src/runner/test.d.ts +52 -0
- package/types/e2e/src/runner/trace.d.ts +87 -0
- package/types/e2e/src/screen/actions.d.ts +93 -0
- package/types/e2e/src/screen/context.d.ts +134 -0
- package/types/e2e/src/screen/field.d.ts +121 -0
- package/types/e2e/src/screen/locator.d.ts +233 -0
- package/types/e2e/src/screen/nodes.d.ts +53 -0
- package/types/e2e/src/screen/poll.d.ts +57 -0
- package/types/e2e/src/screen/queries.d.ts +34 -0
- package/types/e2e/src/screen/query.d.ts +60 -0
- package/types/e2e/src/screen/react-locator.d.ts +30 -0
- package/types/e2e/src/screen/render.d.ts +42 -0
- package/types/e2e/src/screen/roles.d.ts +24 -0
- package/types/e2e/src/screen/screen.d.ts +61 -0
- package/types/e2e/src/screen/selector.d.ts +38 -0
- package/types/e2e/src/screen/text.d.ts +13 -0
- package/types/e2e/src/session.d.ts +105 -0
- package/types/e2e/src/traced-device.d.ts +9 -0
- package/types/e2e/src/version.d.ts +7 -0
- package/types/types/src/result.d.ts +12 -0
- package/README.md +0 -3
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Result } from "../../../types/src/result";
|
|
2
|
+
import type { DriverError, GestureOptions, Point, TouchPath, TwoFingerOptions } from "./driver.types";
|
|
3
|
+
/**
|
|
4
|
+
* Touch-path geometry shared by both drivers: `gesture`, `pinch` and `rotate` all become a `GesturePlan`, one
|
|
5
|
+
* frame per ~16 ms on a shared timeline, which `warden-simd` (`gesture` op) and `warden-uiad` (`gesture` op)
|
|
6
|
+
* only replay. Fingers go down together on the first frame and lift together after the last one (the iOS
|
|
7
|
+
* transports carry one phase for both contacts), so every path has the same frame count.
|
|
8
|
+
*/
|
|
9
|
+
export declare const GESTURE_FRAME_MS = 16;
|
|
10
|
+
export declare const GESTURE_MAX_FRAMES = 1000;
|
|
11
|
+
export declare const GESTURE_MAX_MS = 60000;
|
|
12
|
+
export declare const GESTURE_MAX_POINTERS = 2;
|
|
13
|
+
export declare const DEFAULT_GESTURE_MS = 300;
|
|
14
|
+
export declare const DEFAULT_PINCH_MS = 400;
|
|
15
|
+
export declare const DEFAULT_ROTATE_MS = 500;
|
|
16
|
+
/** finger distance from the centre: points on iOS; Android multiplies by the screen scale */
|
|
17
|
+
export declare const DEFAULT_RADIUS = 100;
|
|
18
|
+
/** two-finger gestures rest at their end before lifting, so recognisers read ~0 velocity */
|
|
19
|
+
export declare const TWO_FINGER_RELEASE_MS = 50;
|
|
20
|
+
/** What the native servers replay: frame `k` of every path is `holdMs + k * frameMs` after touch-down. */
|
|
21
|
+
export type GesturePlan = {
|
|
22
|
+
paths: Point[][];
|
|
23
|
+
frameMs: number;
|
|
24
|
+
holdMs: number;
|
|
25
|
+
releaseMs: number;
|
|
26
|
+
totalMs: number;
|
|
27
|
+
};
|
|
28
|
+
export type TwoFingerSpec = {
|
|
29
|
+
radius: number;
|
|
30
|
+
angle?: number;
|
|
31
|
+
scale?: number;
|
|
32
|
+
degrees?: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Validates 1–2 finger paths and resamples them onto one timeline. Bad input is `E_BAD_REQUEST`; more fingers
|
|
36
|
+
* than the driver takes is `E_UNSUPPORTED`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function planGesture(paths: readonly TouchPath[], opts: GestureOptions | undefined, maxPointers: 0 | 1 | 2): Result<GesturePlan, DriverError>;
|
|
39
|
+
/**
|
|
40
|
+
* Two fingers `radius` either side of `center` on an axis at `angle` degrees (0 = horizontal; finger 1 on the
|
|
41
|
+
* negative side), spreading to `radius * scale` and turning `degrees` clockwise (screen space, y down) over
|
|
42
|
+
* `durationMs`. A turn is sampled every few degrees so the fingers follow the arc.
|
|
43
|
+
*/
|
|
44
|
+
export declare function twoFingerPaths(center: Point, spec: TwoFingerSpec, durationMs: number): [TouchPath, TouchPath];
|
|
45
|
+
/** Two fingers spreading (`scale` > 1) or closing (< 1) around `center`. */
|
|
46
|
+
export declare function pinchPlan(center: Point, scale: number, opts: TwoFingerOptions | undefined, defaultRadius: number): Result<GesturePlan, DriverError>;
|
|
47
|
+
/** Two fingers turning `degrees` around `center`; positive is clockwise on screen. */
|
|
48
|
+
export declare function rotatePlan(center: Point, degrees: number, opts: TwoFingerOptions | undefined, defaultRadius: number): Result<GesturePlan, DriverError>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { Exec } from "../../../../core/src/exec";
|
|
2
|
+
import type { E2eEnv } from "../../env";
|
|
3
|
+
import type { ProbesFrontmost, ReadsAlertOn } from "../alerts";
|
|
4
|
+
import type { Driver, DriverResult, KeyName, Logger } from "../driver.types";
|
|
5
|
+
import type { SelectsAll } from "../typing";
|
|
6
|
+
import { type SwappableClient } from "./ios-session";
|
|
7
|
+
import { type Simctl } from "./simctl";
|
|
8
|
+
import { type SimdClient } from "./simd-client";
|
|
9
|
+
import type { SimdSpawn } from "./simd-transport";
|
|
10
|
+
/**
|
|
11
|
+
* The iOS `Driver`: input and AX through `warden-simd` (socket when `WARDEN_SIMD_SOCKET` is set, else a
|
|
12
|
+
* helper spawned on stdio), app lifecycle / clipboard / appearance through `xcrun simctl`. Fallbacks:
|
|
13
|
+
* `typeText` pastes what the HID keyboard map cannot type, `settle` polls snapshot hashes when the
|
|
14
|
+
* helper has no native quiescence, `screenshot` uses `simctl io` when the helper cannot.
|
|
15
|
+
*/
|
|
16
|
+
export type IosDriverEnv = Pick<E2eEnv, "simd" | "simdSocket" | "helperDir">;
|
|
17
|
+
/** The iOS driver is a `Driver` plus the optional capabilities of `driver/alerts.ts`. */
|
|
18
|
+
export type IosDriver = Driver & SelectsAll & ReadsAlertOn & ProbesFrontmost;
|
|
19
|
+
export type OpenIosDriverOptions = {
|
|
20
|
+
udid: string;
|
|
21
|
+
env?: IosDriverEnv;
|
|
22
|
+
exec: Exec;
|
|
23
|
+
spawn?: SimdSpawn;
|
|
24
|
+
log?: Logger;
|
|
25
|
+
/** explicit helper binary (skips {@link locateHelper}) */
|
|
26
|
+
helperPath?: string;
|
|
27
|
+
/** explicit helper socket (wins over `env.simdSocket`) */
|
|
28
|
+
socketPath?: string;
|
|
29
|
+
/**
|
|
30
|
+
* An already connected (handshaken) helper client: used instead of connecting, so a caller that just
|
|
31
|
+
* connected to learn the helper was up does not connect twice. The driver owns it from here (`close()`
|
|
32
|
+
* closes it); a restart still reconnects through the socket / spawn path.
|
|
33
|
+
*/
|
|
34
|
+
client?: SimdClient;
|
|
35
|
+
now?: () => number;
|
|
36
|
+
sleep?: (ms: number) => Promise<void>;
|
|
37
|
+
/** for `locateHelper` / `$WARDEN_HOME/simd/<version>`; defaults read the process */
|
|
38
|
+
version?: string;
|
|
39
|
+
wardenHome?: string;
|
|
40
|
+
execPath?: string;
|
|
41
|
+
importDir?: string;
|
|
42
|
+
exists?: (path: string) => boolean;
|
|
43
|
+
realpath?: (path: string) => string;
|
|
44
|
+
/** per-request default in ms, 10 s */
|
|
45
|
+
defaultTimeoutMs?: number;
|
|
46
|
+
/** log each helper op and simctl call with its duration (`WARDEN_E2E_DEBUG=1`) */
|
|
47
|
+
debug?: boolean;
|
|
48
|
+
/** CoreSimulator devices directory for the host-side `AutomationEnabled` check (default `~/Library/Developer/CoreSimulator/Devices`) */
|
|
49
|
+
devicesRoot?: string;
|
|
50
|
+
};
|
|
51
|
+
/** USB HID keyboard-page usage ids for the keys `Driver.key` offers. */
|
|
52
|
+
export declare const KEY_USAGE: Readonly<Record<KeyName, number>>;
|
|
53
|
+
export declare function createIosDriver(swap: SwappableClient, simctl: Simctl, opts: {
|
|
54
|
+
udid: string;
|
|
55
|
+
now: () => number;
|
|
56
|
+
sleep: (ms: number) => Promise<void>;
|
|
57
|
+
log?: Logger;
|
|
58
|
+
}): IosDriver;
|
|
59
|
+
/**
|
|
60
|
+
* Open the iOS driver for `udid`. Writes `AutomationEnabled` (best effort) while the helper starts.
|
|
61
|
+
* `E_HELPER_MISSING` (with the `warden doctor` hint) when no helper binary can be found.
|
|
62
|
+
*/
|
|
63
|
+
export declare function openIosDriver(o: OpenIosDriverOptions): DriverResult<Driver>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Result } from "../../../../types/src/result";
|
|
2
|
+
import type { DriverError, Logger } from "../driver.types";
|
|
3
|
+
import type { SimdClient } from "./simd-client";
|
|
4
|
+
/** The slice of {@link SimdClient} the iOS driver uses; the driver holds this, never a raw client. */
|
|
5
|
+
export type DriverClient = Pick<SimdClient, "request" | "ready" | "close">;
|
|
6
|
+
export type Reopen = () => Promise<Result<SimdClient, DriverError>>;
|
|
7
|
+
export type SwappableClient = {
|
|
8
|
+
client: DriverClient;
|
|
9
|
+
/** bumps on every restart, so a caller can tell "someone already restarted it" from "still the stale one" */
|
|
10
|
+
generation(): number;
|
|
11
|
+
/**
|
|
12
|
+
* Replace the helper: ask the current one to `shutdown`, drop it, `reopen()` (socket first, else a
|
|
13
|
+
* fresh stdio spawn). Single-flight; a caller whose `seenGeneration` is already stale just returns ok.
|
|
14
|
+
* `crashed`: the helper (or the connection to it) is already gone, so nothing is asked of it; asking
|
|
15
|
+
* would only make a stdio client respawn a helper to shut it down.
|
|
16
|
+
*/
|
|
17
|
+
restart(seenGeneration: number, o?: {
|
|
18
|
+
crashed?: boolean;
|
|
19
|
+
}): Promise<Result<void, DriverError>>;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Wraps the helper client so it can be swapped at runtime (bridge-stale recovery) and so every
|
|
23
|
+
* request's latency can be logged (`debug`, driven by `WARDEN_E2E_DEBUG=1`): `[ios] op snapshot 31 ms`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function swappableClient(initial: SimdClient, o: {
|
|
26
|
+
now: () => number;
|
|
27
|
+
log?: Logger;
|
|
28
|
+
debug?: boolean;
|
|
29
|
+
reopen?: Reopen;
|
|
30
|
+
}): SwappableClient;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Result } from "../../../../types/src/result";
|
|
2
|
+
import type { DriverError } from "../driver.types";
|
|
3
|
+
import type { OpenIosDriverOptions } from "./ios-driver";
|
|
4
|
+
export declare const HELPER_NAME = "warden-simd";
|
|
5
|
+
export type LocateHelperInput = {
|
|
6
|
+
/** `WARDEN_SIMD` (a file) and `WARDEN_HELPER_DIR` (a directory holding `warden-simd`) are read from here */
|
|
7
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
8
|
+
/** `process.execPath`: a compiled `warden` ships the helper next to itself */
|
|
9
|
+
execPath: string;
|
|
10
|
+
/** directory of this module (`packages/e2e/src/driver/ios`), anchors the source-checkout build output */
|
|
11
|
+
importDir: string;
|
|
12
|
+
/** `$WARDEN_HOME` (resolved), where `warden doctor` / installs stage `simd/<version>/warden-simd` */
|
|
13
|
+
wardenHome: string;
|
|
14
|
+
/** warden version for the staged copy; without it that lookup step is skipped */
|
|
15
|
+
version?: string;
|
|
16
|
+
/** file existence, injected */
|
|
17
|
+
exists: (path: string) => boolean;
|
|
18
|
+
/** symlink resolution, injected; defaults to identity */
|
|
19
|
+
realpath?: (path: string) => string;
|
|
20
|
+
};
|
|
21
|
+
export type HelperLocation = {
|
|
22
|
+
path: string;
|
|
23
|
+
source: "WARDEN_SIMD" | "WARDEN_HELPER_DIR" | "execPath" | "source-build" | "warden-home";
|
|
24
|
+
};
|
|
25
|
+
export declare const DOCTOR_HINT = "run `warden doctor` to check the iOS driver helper, or set WARDEN_SIMD=/path/to/warden-simd";
|
|
26
|
+
/**
|
|
27
|
+
* Find the `warden-simd` binary. Order: `WARDEN_SIMD` (file) → `WARDEN_HELPER_DIR/warden-simd` →
|
|
28
|
+
* next to the real path of the running executable → `<packages/e2e>/native/dist/warden-simd` →
|
|
29
|
+
* `$WARDEN_HOME/simd/<version>/warden-simd`. An explicitly set env var that points at nothing is an
|
|
30
|
+
* error, not a fall-through (a stale override should not silently pick another binary).
|
|
31
|
+
*/
|
|
32
|
+
export declare function locateHelper(input: LocateHelperInput): Result<HelperLocation, DriverError>;
|
|
33
|
+
/**
|
|
34
|
+
* The helper binary: the explicit `helperPath`, else `locateHelper` over the env / install locations. Lives here,
|
|
35
|
+
* not in `ios-driver.ts`, so a caller that only needs the path (`warden ui` spawning or replacing the helper)
|
|
36
|
+
* does not load the driver and its protocol schemas.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveHelper(o: OpenIosDriverOptions): Result<string, DriverError>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Element, ScreenInfo, Snapshot } from "../driver.types";
|
|
2
|
+
import type { SnapshotData, WireElement } from "./simd-protocol";
|
|
3
|
+
/** Wire → `Element`: strips `null`s, fills what the helper may omit (`id` as the preorder path, `depth`, `normFrame`, `traits`, `enabled`, `children`). */
|
|
4
|
+
export type Normalized = {
|
|
5
|
+
elements: Element[];
|
|
6
|
+
flat: Element[];
|
|
7
|
+
};
|
|
8
|
+
export declare function normalizeElements(wire: readonly WireElement[], screen: ScreenInfo, prefix?: string, depth?: number): Normalized;
|
|
9
|
+
/** One element out of `elementAtPoint` (no siblings, so depth/path are 0). */
|
|
10
|
+
export declare function normalizeElement(wire: WireElement, screen: ScreenInfo): Element;
|
|
11
|
+
export declare function toSnapshot(data: SnapshotData, takenAt: number): Snapshot;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { type ResetFs } from "../../../../core/src/builds/install";
|
|
2
|
+
import { type Exec, type ExecResult } from "../../../../core/src/exec";
|
|
3
|
+
import type { DriverError, DriverResult, LaunchOptions } from "../driver.types";
|
|
4
|
+
export declare const SIMCTL_CHILD_PREFIX = "SIMCTL_CHILD_";
|
|
5
|
+
/** `xcrun simctl launch [--terminate-running-process] <udid> <bundle> <args…>` (env goes through `SIMCTL_CHILD_*`, see {@link launchEnv}). */
|
|
6
|
+
export declare function launchArgv(udid: string, bundleId: string, opts?: LaunchOptions): string[];
|
|
7
|
+
/** simctl forwards `SIMCTL_CHILD_<NAME>` from its own environment to the launched app as `<NAME>`. */
|
|
8
|
+
export declare function launchEnv(env: Record<string, string> | undefined): Record<string, string>;
|
|
9
|
+
export declare const terminateArgv: (udid: string, bundleId: string) => string[];
|
|
10
|
+
export declare const openUrlArgv: (udid: string, url: string) => string[];
|
|
11
|
+
export declare const installArgv: (udid: string, appPath: string) => string[];
|
|
12
|
+
export declare const uninstallArgv: (udid: string, bundleId: string) => string[];
|
|
13
|
+
/** Exit 0 and a path on stdout when installed; non-zero when not. */
|
|
14
|
+
export declare const appContainerArgv: (udid: string, bundleId: string) => string[];
|
|
15
|
+
/** Lists launchd jobs inside the simulator; a running app shows up as `UIKitApplication:<bundle>[…]` with a PID. */
|
|
16
|
+
export declare const launchctlListArgv: (udid: string) => string[];
|
|
17
|
+
export declare const pbpasteArgv: (udid: string) => string[];
|
|
18
|
+
export declare const appearanceArgv: (udid: string, set?: "light" | "dark") => string[];
|
|
19
|
+
export declare const screenshotArgv: (udid: string, path: string) => string[];
|
|
20
|
+
/** `AutomationEnabled` lets the AX bridge attach without the runner app; written once per open. */
|
|
21
|
+
export declare const automationArgv: (udid: string) => string[];
|
|
22
|
+
/** Where CoreSimulator keeps every simulator's data directory on the host. */
|
|
23
|
+
export declare const defaultDevicesRoot: () => string;
|
|
24
|
+
/**
|
|
25
|
+
* The simulator's Accessibility preferences, readable from the host without booting anything through `xcrun`
|
|
26
|
+
* (`simctl spawn` costs 300-500 ms, a `plutil` read about 10 ms).
|
|
27
|
+
*/
|
|
28
|
+
export declare const automationPlistPath: (devicesRoot: string, udid: string) => string;
|
|
29
|
+
/** `plutil -extract AutomationEnabled raw -o - <plist>` prints `true` once the default is written. */
|
|
30
|
+
export declare const automationReadArgv: (plist: string) => string[];
|
|
31
|
+
export type StatusBarOverrides = {
|
|
32
|
+
time?: string;
|
|
33
|
+
batteryLevel?: number;
|
|
34
|
+
batteryState?: "charged" | "charging" | "discharging";
|
|
35
|
+
wifiBars?: number;
|
|
36
|
+
cellularBars?: number;
|
|
37
|
+
};
|
|
38
|
+
/** Clean 9:41 status bar by default (stable screenshots); pass `undefined` fields to drop them. */
|
|
39
|
+
export declare function statusBarOverrideArgv(udid: string, o?: StatusBarOverrides): string[];
|
|
40
|
+
export declare const statusBarClearArgv: (udid: string) => string[];
|
|
41
|
+
/**
|
|
42
|
+
* `simctl pbcopy` reads stdin and `Exec` has none, so the text rides as `$1` of a tiny `sh -c`
|
|
43
|
+
* (never interpolated into the script): `printf %s "$1" | xcrun simctl pbcopy "$2"`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function pbcopyArgv(udid: string, text: string): string[];
|
|
46
|
+
/** `launchctl list` rows are `PID STATUS LABEL`; PID is `-` for loaded-but-not-running jobs. */
|
|
47
|
+
export declare function parseRunning(launchctlOutput: string, bundleId: string): boolean;
|
|
48
|
+
/** Map a failed simctl run to a `DriverError`. `appCommand` marks launch-like calls where "not installed" means the app, not the device. */
|
|
49
|
+
export declare function simctlFailure(argv: readonly string[], res: ExecResult, appCommand?: boolean): DriverError;
|
|
50
|
+
export type SimctlDeps = {
|
|
51
|
+
udid: string;
|
|
52
|
+
exec: Exec;
|
|
53
|
+
/** forwarded to core's installer helpers (resolves `adb`; unused on iOS but part of their deps) */
|
|
54
|
+
env?: Record<string, string | undefined>;
|
|
55
|
+
/** app data wipe filesystem; defaults to node fs */
|
|
56
|
+
resetFs?: ResetFs;
|
|
57
|
+
/** where the screenshot fallback writes before reading back; defaults to a fresh `os.tmpdir()` dir */
|
|
58
|
+
scratchDir?: () => Promise<string>;
|
|
59
|
+
readFile?: (path: string) => Promise<Uint8Array>;
|
|
60
|
+
rmDir?: (path: string) => Promise<void>;
|
|
61
|
+
/** CoreSimulator's devices directory, for the host-side `AutomationEnabled` check; defaults to `~/Library/...` */
|
|
62
|
+
devicesRoot?: string;
|
|
63
|
+
};
|
|
64
|
+
export type Simctl = {
|
|
65
|
+
launch(bundleId: string, opts?: LaunchOptions): DriverResult<void>;
|
|
66
|
+
terminate(bundleId: string): DriverResult<void>;
|
|
67
|
+
openUrl(url: string): DriverResult<void>;
|
|
68
|
+
install(path: string): DriverResult<void>;
|
|
69
|
+
uninstall(bundleId: string): DriverResult<void>;
|
|
70
|
+
isInstalled(bundleId: string): DriverResult<boolean>;
|
|
71
|
+
isRunning(bundleId: string): DriverResult<boolean>;
|
|
72
|
+
clearData(bundleId: string, opts?: {
|
|
73
|
+
keychain?: boolean;
|
|
74
|
+
}): DriverResult<void>;
|
|
75
|
+
pbcopy(text: string): DriverResult<void>;
|
|
76
|
+
pbpaste(): DriverResult<string>;
|
|
77
|
+
appearance(set?: "light" | "dark"): DriverResult<"light" | "dark">;
|
|
78
|
+
statusBar(overrides?: StatusBarOverrides | "clear"): DriverResult<void>;
|
|
79
|
+
/** `simctl io screenshot` to `path`, or (no path) to a scratch file read back as PNG bytes */
|
|
80
|
+
screenshot(path?: string): DriverResult<{
|
|
81
|
+
path?: string;
|
|
82
|
+
png?: Uint8Array;
|
|
83
|
+
}>;
|
|
84
|
+
/** `defaults write com.apple.Accessibility AutomationEnabled -bool true` inside the sim */
|
|
85
|
+
enableAutomation(): DriverResult<void>;
|
|
86
|
+
};
|
|
87
|
+
export declare function createSimctl(deps: SimctlDeps): Simctl;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Result } from "../../../../types/src/result";
|
|
2
|
+
import type { DriverError, DriverResult, Logger } from "../driver.types";
|
|
3
|
+
import { type LogEvent, type OpData, type ReadyEvent } from "./simd-protocol";
|
|
4
|
+
import { type SimdSpawn, type TransportFactory } from "./simd-transport";
|
|
5
|
+
/**
|
|
6
|
+
* NDJSON client for `warden-simd`, over the helper's stdio (`spawnSimd`, by-hand runs) or its unix
|
|
7
|
+
* socket (`connectSimd`, the pre-warmed daemon). Multiplexes requests by id (responses may arrive out
|
|
8
|
+
* of order), enforces per-op timeouts, forwards `log` events, maps `fatal` to a `DriverError`, and in
|
|
9
|
+
* stdio mode respawns the helper on the call after a crash.
|
|
10
|
+
*/
|
|
11
|
+
export type SimdEventMap = {
|
|
12
|
+
ready: ReadyEvent;
|
|
13
|
+
log: LogEvent;
|
|
14
|
+
/** the helper reported it cannot continue (also fails every in-flight request) */
|
|
15
|
+
fatal: DriverError;
|
|
16
|
+
/** the helper process / connection went away */
|
|
17
|
+
exit: {
|
|
18
|
+
exitCode: number | null;
|
|
19
|
+
expected: boolean;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export type RequestOptions = {
|
|
23
|
+
timeoutMs?: number;
|
|
24
|
+
};
|
|
25
|
+
export type SimdClient = {
|
|
26
|
+
/** the handshake of the current helper process (refreshed after a respawn) */
|
|
27
|
+
readonly ready: ReadyEvent;
|
|
28
|
+
request<Op extends string>(op: Op, params?: Record<string, unknown>, opts?: RequestOptions): DriverResult<OpData<Op>>;
|
|
29
|
+
/** subscribe; returns the unsubscribe function */
|
|
30
|
+
on<E extends keyof SimdEventMap>(event: E, handler: (payload: SimdEventMap[E]) => void): () => void;
|
|
31
|
+
close(): Promise<void>;
|
|
32
|
+
};
|
|
33
|
+
export type ClientOptions = {
|
|
34
|
+
log?: Logger;
|
|
35
|
+
/** default per-request timeout, 10 s */
|
|
36
|
+
defaultTimeoutMs?: number;
|
|
37
|
+
/** how long to wait for `ready`, 15 s */
|
|
38
|
+
readyTimeoutMs?: number;
|
|
39
|
+
/**
|
|
40
|
+
* respawns allowed in a row after unexpected exits (stdio default 1, socket 0). The budget refills
|
|
41
|
+
* as soon as the helper answers anything, so each crash gets one respawn but a helper that dies
|
|
42
|
+
* before answering is not retried forever.
|
|
43
|
+
*/
|
|
44
|
+
maxRespawns?: number;
|
|
45
|
+
/** ask the helper to `shutdown` on close (stdio: yes; a shared socket daemon: no) */
|
|
46
|
+
shutdownOnClose?: boolean;
|
|
47
|
+
};
|
|
48
|
+
/** Shared client engine; the transport decides stdio vs socket. */
|
|
49
|
+
export declare function createSimdClient(factory: TransportFactory, options?: ClientOptions): Promise<Result<SimdClient, DriverError>>;
|
|
50
|
+
export type SpawnSimdOptions = ClientOptions & {
|
|
51
|
+
helperPath: string;
|
|
52
|
+
udid: string;
|
|
53
|
+
/** `--resources <dir>`: where the in-sim AX bridge guest lives */
|
|
54
|
+
resources?: string;
|
|
55
|
+
/** extra helper arguments after the standard ones (e.g. `--hid indigo`) */
|
|
56
|
+
args?: readonly string[];
|
|
57
|
+
/** injectable process spawn (tests); defaults to `Bun.spawn` */
|
|
58
|
+
spawn?: SimdSpawn;
|
|
59
|
+
/** grace period for `close()` before the helper is killed */
|
|
60
|
+
graceMs?: number;
|
|
61
|
+
};
|
|
62
|
+
/** Stdio mode: own a helper process for this client (by-hand runs). Crashes are retried by one respawn. */
|
|
63
|
+
export declare function spawnSimd(options: SpawnSimdOptions): Promise<Result<SimdClient, DriverError>>;
|
|
64
|
+
export type ConnectSimdOptions = ClientOptions & {
|
|
65
|
+
socketPath: string;
|
|
66
|
+
};
|
|
67
|
+
/** Socket mode: attach to a running (pre-warmed) helper daemon. `close()` only disconnects; the daemon idles out. */
|
|
68
|
+
export declare function connectSimd(options: ConnectSimdOptions): Promise<Result<SimdClient, DriverError>>;
|