@delacour/warden-e2e 0.6.0 → 0.8.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.
- package/{chunk-yb1hcjqm.mjs → chunk-vs5npy59.mjs} +3370 -218
- package/index.mjs +247 -16
- package/package.json +2 -2
- package/preload.mjs +8264 -2387
- package/types/core/src/a11y/a11y.config.d.ts +47 -0
- package/types/core/src/affected/affected.schema.d.ts +142 -1
- package/types/core/src/allocate.d.ts +2 -1
- package/types/core/src/android-keyguard.d.ts +36 -0
- package/types/core/src/batch/preset.schema.d.ts +13 -1
- package/types/core/src/biometrics.d.ts +15 -0
- package/types/core/src/builds/app-option.schema.d.ts +1 -1
- package/types/core/src/builds/builds.defaults.d.ts +15 -0
- package/types/core/src/builds/config.d.ts +5 -1
- package/types/core/src/builds/config.schema.d.ts +275 -2
- package/types/core/src/builds/define-config.d.ts +159 -0
- package/types/core/src/builds/install-device.d.ts +37 -0
- package/types/core/src/builds/install.d.ts +17 -3
- package/types/core/src/builds/kinds.d.ts +21 -3
- package/types/core/src/builds/lock.d.ts +38 -0
- package/types/core/src/builds/resolve.d.ts +12 -2
- package/types/core/src/camera-mode.d.ts +17 -0
- package/types/core/src/camera-placeholder.d.ts +9 -0
- package/types/core/src/camera-profile.d.ts +12 -0
- package/types/core/src/claim-errors.d.ts +34 -0
- package/types/core/src/conditions/a11y-keys.d.ts +45 -0
- package/types/core/src/conditions/camera-media.d.ts +30 -0
- package/types/core/src/conditions/conditions.config.d.ts +141 -0
- package/types/core/src/conditions/conditions.d.ts +22 -0
- package/types/core/src/conditions/conditions.types.d.ts +171 -0
- package/types/core/src/conditions/inject-state.d.ts +13 -0
- package/types/core/src/conditions/launch-settings.d.ts +14 -0
- package/types/core/src/conditions/network.presets.d.ts +42 -0
- package/types/core/src/conditions/text-size.d.ts +19 -0
- package/types/core/src/golden/android-biometrics.d.ts +35 -0
- package/types/core/src/ios-runner/build.d.ts +28 -0
- package/types/core/src/ios-runner/cache.d.ts +44 -0
- package/types/core/src/ios-runner/classify.d.ts +7 -0
- package/types/core/src/ios-runner/pack.d.ts +17 -0
- package/types/core/src/ios-runner/runner-build.types.d.ts +76 -0
- package/types/core/src/ios-runner/signing.d.ts +40 -0
- package/types/core/src/ios-runner/sim-build.d.ts +36 -0
- package/types/core/src/ios-runner/stage.d.ts +26 -0
- package/types/core/src/lease-events.d.ts +126 -0
- package/types/core/src/netproxy/control.d.ts +75 -0
- package/types/core/src/netproxy/decide.d.ts +22 -0
- package/types/core/src/netproxy/handle-file.d.ts +12 -0
- package/types/core/src/netproxy/lease-proxy.d.ts +53 -0
- package/types/core/src/netproxy/netproxy.main.d.ts +40 -0
- package/types/core/src/netproxy/pipe.d.ts +37 -0
- package/types/core/src/netproxy/proxy.d.ts +48 -0
- package/types/core/src/netproxy/shaping.d.ts +43 -0
- package/types/core/src/ownership.d.ts +44 -0
- package/types/core/src/providers/android.d.ts +46 -2
- package/types/core/src/providers/provider.types.d.ts +9 -0
- package/types/core/src/queue.d.ts +43 -0
- package/types/core/src/store.d.ts +61 -5
- package/types/core/src/types.d.ts +57 -0
- package/types/core/src/xcode.d.ts +22 -0
- package/types/e2e/src/a11y/a11y-target.d.ts +23 -0
- package/types/e2e/src/a11y/a11y.types.d.ts +81 -0
- package/types/e2e/src/a11y/announcements.d.ts +24 -0
- package/types/e2e/src/a11y/audit.d.ts +22 -0
- package/types/e2e/src/a11y/native/atf.d.ts +51 -0
- package/types/e2e/src/a11y/native/xcuitest.d.ts +60 -0
- package/types/e2e/src/a11y/order.d.ts +5 -0
- package/types/e2e/src/a11y/rules/duplicate-name.d.ts +6 -0
- package/types/e2e/src/a11y/rules/hidden-focusable.d.ts +3 -0
- package/types/e2e/src/a11y/rules/image-no-name.d.ts +6 -0
- package/types/e2e/src/a11y/rules/label-in-name.d.ts +7 -0
- package/types/e2e/src/a11y/rules/missing-name.d.ts +3 -0
- package/types/e2e/src/a11y/rules/role-in-name.d.ts +3 -0
- package/types/e2e/src/a11y/rules/rule.context.d.ts +22 -0
- package/types/e2e/src/a11y/rules/target-size.d.ts +21 -0
- package/types/e2e/src/a11y/rules/text-clipped.d.ts +9 -0
- package/types/e2e/src/a11y/speech.d.ts +26 -0
- package/types/e2e/src/a11y/talkback-log.d.ts +13 -0
- package/types/e2e/src/alert-buttons.d.ts +9 -0
- package/types/e2e/src/app.d.ts +3 -2
- package/types/e2e/src/conditions/condition-events.d.ts +68 -0
- package/types/e2e/src/conditions/device-conditions.d.ts +198 -0
- package/types/e2e/src/conditions/geo.d.ts +15 -0
- package/types/e2e/src/conditions/gpx.d.ts +8 -0
- package/types/e2e/src/conditions/lease-recorder.d.ts +27 -0
- package/types/e2e/src/conditions/lease-store.d.ts +9 -0
- package/types/e2e/src/conditions/location-plan.d.ts +17 -0
- package/types/e2e/src/conditions/location-scenarios.data.d.ts +17 -0
- package/types/e2e/src/conditions/route-ticker.d.ts +53 -0
- package/types/e2e/src/conditions/scheduler.d.ts +83 -0
- package/types/e2e/src/device-a11y.d.ts +97 -0
- package/types/e2e/src/device.d.ts +67 -4
- package/types/e2e/src/driver/a11y-events.d.ts +30 -0
- package/types/e2e/src/driver/a11y-read.d.ts +12 -0
- package/types/e2e/src/driver/android/android-animations.d.ts +7 -0
- package/types/e2e/src/driver/android/android-app.d.ts +4 -0
- package/types/e2e/src/driver/android/android-argv.d.ts +21 -0
- package/types/e2e/src/driver/android/android-camera-host.d.ts +23 -0
- package/types/e2e/src/driver/android/android-camera.d.ts +28 -0
- package/types/e2e/src/driver/android/android-clock.d.ts +28 -0
- package/types/e2e/src/driver/android/android-device.d.ts +8 -0
- package/types/e2e/src/driver/android/android-driver.d.ts +22 -0
- package/types/e2e/src/driver/android/android-network.d.ts +66 -0
- package/types/e2e/src/driver/android/android-phone.d.ts +47 -0
- package/types/e2e/src/driver/android/android-screen-reader.d.ts +23 -0
- package/types/e2e/src/driver/android/android-settings.d.ts +41 -0
- package/types/e2e/src/driver/android/android-spoken.d.ts +18 -0
- package/types/e2e/src/driver/android/android-state.d.ts +10 -0
- package/types/e2e/src/driver/android/android-talkback.d.ts +57 -0
- package/types/e2e/src/driver/android/atf-device.d.ts +23 -0
- package/types/e2e/src/driver/android/atf-dex.generated.d.ts +7 -0
- package/types/e2e/src/driver/android/uiad-dex.generated.d.ts +5 -5
- package/types/e2e/src/driver/android/uiad-ops.d.ts +27 -1
- package/types/e2e/src/driver/android/uiad-protocol.d.ts +8 -0
- package/types/e2e/src/driver/android/uiad-screen-reader.d.ts +33 -0
- package/types/e2e/src/driver/clock-recorder.d.ts +9 -0
- package/types/e2e/src/driver/device-settings.d.ts +10 -0
- package/types/e2e/src/driver/driver.types.d.ts +242 -1
- package/types/e2e/src/driver/element-actions.d.ts +16 -0
- package/types/e2e/src/driver/ios/device/capabilities.d.ts +3 -0
- package/types/e2e/src/driver/ios/device/device-driver.d.ts +49 -0
- package/types/e2e/src/driver/ios/device/devicectl.d.ts +38 -0
- package/types/e2e/src/driver/ios/device/runner-protocol.d.ts +21 -0
- package/types/e2e/src/driver/ios/hid-recovery.d.ts +15 -0
- package/types/e2e/src/driver/ios/inject.d.ts +124 -0
- package/types/e2e/src/driver/ios/ios-a11y.d.ts +73 -0
- package/types/e2e/src/driver/ios/ios-audit.d.ts +36 -0
- package/types/e2e/src/driver/ios/ios-driver.d.ts +50 -1
- package/types/e2e/src/driver/ios/ios-network.d.ts +51 -0
- package/types/e2e/src/driver/ios/ios-settings.d.ts +44 -0
- package/types/e2e/src/driver/ios/sim-runner.d.ts +41 -0
- package/types/e2e/src/driver/ios/simctl.d.ts +41 -1
- package/types/e2e/src/driver/ios/simd-transport.d.ts +11 -2
- package/types/e2e/src/driver/ios/type-budget.d.ts +6 -1
- package/types/e2e/src/driver/native-audit.d.ts +26 -0
- package/types/e2e/src/driver/network-proxy.d.ts +52 -0
- package/types/e2e/src/driver/open.d.ts +20 -0
- package/types/e2e/src/driver/physical-conditions.d.ts +11 -0
- package/types/e2e/src/driver/requirements.d.ts +14 -0
- package/types/e2e/src/driver/screen-reader.d.ts +26 -0
- package/types/e2e/src/driver/typing.d.ts +1 -1
- package/types/e2e/src/env.d.ts +47 -0
- package/types/e2e/src/expect/a11y-matchers.d.ts +33 -0
- package/types/e2e/src/expect/expect.d.ts +7 -2
- package/types/e2e/src/expect/matchers.d.ts +14 -0
- package/types/e2e/src/fixture-session.d.ts +4 -0
- package/types/e2e/src/fixtures.d.ts +6 -1
- package/types/e2e/src/index.d.ts +6 -0
- package/types/e2e/src/runner/callsite.d.ts +3 -1
- package/types/e2e/src/runner/scope.d.ts +1 -0
- package/types/e2e/src/runner/test.d.ts +6 -0
- package/types/e2e/src/screen/render.d.ts +8 -0
- package/types/e2e/src/traced-device.d.ts +2 -1
|
@@ -10,6 +10,23 @@ import type { AppFramework } from "./native-ids";
|
|
|
10
10
|
*/
|
|
11
11
|
export type BuildKind = "dev" | "simulator" | "release";
|
|
12
12
|
export declare const BUILD_KINDS: readonly ["dev", "simulator", "release"];
|
|
13
|
+
/**
|
|
14
|
+
* What a build runs on, separate from its kind: `simulator` builds (every kind so far) run on simulators and
|
|
15
|
+
* emulators, `device` builds are signed for a physical iPhone. v1: only `dev` and `release` have a device build.
|
|
16
|
+
*/
|
|
17
|
+
export type BuildTarget = "simulator" | "device";
|
|
18
|
+
/**
|
|
19
|
+
* A device-target build's identity: the signing `team` and a `salt` (the team, plus a hash of the bundle id
|
|
20
|
+
* override when `projects[].ios.device.bundleIdentifier` is set) that goes into the cache key and the cache path.
|
|
21
|
+
*/
|
|
22
|
+
export type DeviceTarget = {
|
|
23
|
+
team: string;
|
|
24
|
+
salt: string;
|
|
25
|
+
};
|
|
26
|
+
/** The device target of `project` signed by `team`: a changed team or bundle id override is a different build. */
|
|
27
|
+
export declare function deviceTarget(project: Project, team: string): DeviceTarget;
|
|
28
|
+
/** `project` with the bundle id a device build installs under (`projects[].ios.device.bundleIdentifier`, else its own). */
|
|
29
|
+
export declare function withDeviceBundleId(project: Project): Project;
|
|
13
30
|
/** The kind `warden e2e` installs when the suite's `app` names none. */
|
|
14
31
|
export declare const DEFAULT_E2E_KIND: BuildKind;
|
|
15
32
|
/** The kind `warden ui open` / `warden dev` use when no `--kind` is given. */
|
|
@@ -48,9 +65,10 @@ export declare function kindBuildCommand(kind: BuildKind, platform: Platform, fr
|
|
|
48
65
|
* (`fingerprint.command`, `build.cache` and `build.prebuiltReactNative` still apply: they are not about the kind).
|
|
49
66
|
* JS inputs: `kinds.<kind>.jsInputs`, else `DEFAULT_JS_INPUTS` (all tracked files but `ios/`, `android/`, `node_modules`).
|
|
50
67
|
*/
|
|
51
|
-
export declare function resolveKind(project: Project, kind: BuildKind): KindSettings;
|
|
68
|
+
export declare function resolveKind(project: Project, kind: BuildKind, device?: DeviceTarget): KindSettings;
|
|
52
69
|
/**
|
|
53
70
|
* `project` as `kind` builds it: the build commands, configuration and env of `resolveKind`, and `jsInputs` set only
|
|
54
|
-
* when the kind's cache key covers the JS (`release`), so `runLocalBuild` / `computeCacheKey` run unchanged.
|
|
71
|
+
* when the kind's cache key covers the JS (`release`), so `runLocalBuild` / `computeCacheKey` run unchanged. With a
|
|
72
|
+
* `device` target the project builds for a physical iPhone: the signed `xcodebuild` command, the device bundle id.
|
|
55
73
|
*/
|
|
56
|
-
export declare function projectForKind(project: Project, kind: BuildKind): Project;
|
|
74
|
+
export declare function projectForKind(project: Project, kind: BuildKind, device?: DeviceTarget): Project;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type AsyncResult } from "../../../types/src/result";
|
|
2
|
+
import { type PidAlive } from "../liveness";
|
|
3
|
+
import type { Store } from "../store";
|
|
4
|
+
import { type BuildResource, type Lease, type Owner, type Platform } from "../types";
|
|
5
|
+
/** Lease key serialising work on one (project, platform, fingerprint). */
|
|
6
|
+
export declare function buildLockKey(projectKey: string, platform: Platform, hash: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Lease key serialising local builds in one checkout: a build writes the working tree (prebuild, Pods, build/), so two
|
|
9
|
+
* builds of any fingerprints in one `root` clobber each other, and a fingerprint read while one runs is of a half-written
|
|
10
|
+
* native dir. `root` should be a realpath, so two spellings of one checkout share it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildTreeLockKey(root: string, platform: Platform): string;
|
|
13
|
+
export declare function buildResource(key: string): BuildResource;
|
|
14
|
+
export type BuildLockDeps = {
|
|
15
|
+
store: Store;
|
|
16
|
+
owner: Owner;
|
|
17
|
+
/** pid recorded on the lock — the lock lives while this process does */
|
|
18
|
+
pid: number;
|
|
19
|
+
now: () => number;
|
|
20
|
+
pidAlive: PidAlive;
|
|
21
|
+
sleep: (ms: number) => Promise<void>;
|
|
22
|
+
log?: (line: string) => void;
|
|
23
|
+
/** the one line logged when this starts waiting, given the holder (default: "another warden (…) is fetching/building this app — waiting") */
|
|
24
|
+
waitLine?: (holder: string) => string;
|
|
25
|
+
/** called with the holder's lease on every poll while another owner holds the lock (progress, log tailing) */
|
|
26
|
+
onWait?: (held: Lease) => void;
|
|
27
|
+
pollMs?: number;
|
|
28
|
+
waitMs?: number;
|
|
29
|
+
ttlMs?: number;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Run `fn` holding the build lease for `key`. While another live owner holds it, poll (up to
|
|
33
|
+
* `waitMs`); callers re-check the cache inside `fn`, so a waiter ends up with the holder's result
|
|
34
|
+
* instead of downloading/building again. The lease is always released.
|
|
35
|
+
*/
|
|
36
|
+
export declare function withBuildLock<T>(deps: BuildLockDeps, key: string, fn: () => AsyncResult<T>): AsyncResult<T>;
|
|
37
|
+
/** Keys of build leases currently alive (prune never deletes these). */
|
|
38
|
+
export declare function liveBuildLocks(store: Store, now: number, pidAlive: PidAlive): Set<string>;
|
|
@@ -41,10 +41,20 @@ export type EasStepOutcome = {
|
|
|
41
41
|
kind: "miss";
|
|
42
42
|
reason: string;
|
|
43
43
|
};
|
|
44
|
+
/** What the local build step produced: its own build, or (after waiting on the checkout) another warden's, from the cache. */
|
|
45
|
+
export type BuildStepOutcome = {
|
|
46
|
+
kind: "built";
|
|
47
|
+
path: string;
|
|
48
|
+
} | {
|
|
49
|
+
kind: "cached";
|
|
50
|
+
path: string;
|
|
51
|
+
};
|
|
44
52
|
/** What the device probe found: is the app there, and (iOS) its container so `matches` need not ask again. */
|
|
45
53
|
export type InstalledApp = {
|
|
46
54
|
present: boolean;
|
|
47
55
|
container?: string;
|
|
56
|
+
/** a physical iPhone: the `CFBundleVersion` devicectl reports for the installed app */
|
|
57
|
+
version?: string;
|
|
48
58
|
};
|
|
49
59
|
/** Device half of the resolver — absent when only the artifact is wanted. */
|
|
50
60
|
export type DeviceSteps = {
|
|
@@ -84,8 +94,8 @@ export type ResolveSteps = {
|
|
|
84
94
|
flightKey?: string;
|
|
85
95
|
/** EAS: download into the cache, or miss */
|
|
86
96
|
eas?: () => AsyncResult<EasStepOutcome>;
|
|
87
|
-
/** local build into the cache
|
|
88
|
-
build?: () => AsyncResult<
|
|
97
|
+
/** local build into the cache (or the build another warden just made in this checkout) */
|
|
98
|
+
build?: () => AsyncResult<BuildStepOutcome>;
|
|
89
99
|
log: (line: string) => void;
|
|
90
100
|
/** progress: where this resolve is (see `AppPhase`) */
|
|
91
101
|
onPhase?: (phase: AppPhase) => void;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type CameraFacing } from "./conditions/conditions.types";
|
|
2
|
+
/**
|
|
3
|
+
* Which cameras of an Android `+cam` emulator play a video: facing → the video file's name in the camera dir
|
|
4
|
+
* (`back.mp4`). A facing left out plays `<facing>.png`. The source kind is fixed when the emulator launches, so
|
|
5
|
+
* this file records what the RUNNING emulator was launched with; the next launch reads it.
|
|
6
|
+
*/
|
|
7
|
+
export type CameraMode = Partial<Record<CameraFacing, string>>;
|
|
8
|
+
export declare function cameraModePath(dir: string): string;
|
|
9
|
+
/** The recorded mode; a missing or unreadable file is all-image. */
|
|
10
|
+
export declare function readCameraMode(dir: string): CameraMode;
|
|
11
|
+
/** Record `mode` atomically; an all-image mode removes the file. */
|
|
12
|
+
export declare function writeCameraMode(dir: string, mode: CameraMode): void;
|
|
13
|
+
export declare function clearCameraMode(dir: string): void;
|
|
14
|
+
export declare function usesVideo(mode: CameraMode): boolean;
|
|
15
|
+
export declare function sameCameraMode(a: CameraMode, b: CameraMode): boolean;
|
|
16
|
+
/** The emulator's `-camera-back` / `-camera-front` values for `mode`. */
|
|
17
|
+
export declare function cameraSources(dir: string, mode: CameraMode): Record<CameraFacing, string>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** A 64x48 neutral grey PNG: what a camera emulator's cameras show until a feed is set. */
|
|
2
|
+
export declare const PLACEHOLDER_PNG: Buffer<ArrayBuffer>;
|
|
3
|
+
/**
|
|
4
|
+
* Put a device's feeds back to the placeholders: both PNGs rewritten atomically (temp + rename, the emulator may be
|
|
5
|
+
* reading), the staged videos and `mode.json` removed. The emulator itself keeps whatever source it launched with.
|
|
6
|
+
*/
|
|
7
|
+
export declare function resetCameraFeeds(dir: string): void;
|
|
8
|
+
/** Seed `back.png` and `front.png` in `dir` with the grey placeholder, leaving any existing file alone. */
|
|
9
|
+
export declare function seedCameraPlaceholders(dir: string): void;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Camera profiles. An Android profile with `camera: true` is a different device identity from the same profile
|
|
3
|
+
* without it: the emulator's camera source is fixed at launch (`-camera-back imagefile:…`), so a camera emulator
|
|
4
|
+
* is never reused as a plain one. The identity is the profile plus `+cam`, after `+bio` when both apply
|
|
5
|
+
* (`<avd>+bio+cam`); callers that split `+bio` strip `+cam` first.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CAMERA_PROFILE_SUFFIX = "+cam";
|
|
8
|
+
export declare function cameraProfile(profile: string, camera: boolean): string;
|
|
9
|
+
export declare function splitCameraProfile(profile: string): {
|
|
10
|
+
profile: string;
|
|
11
|
+
camera: boolean;
|
|
12
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The machine codes a failed device claim carries, with the exit code the CLI returns for each and a short fix.
|
|
3
|
+
* A claim error travels as a string (`Result<…, string>`) through every claim caller, so the code rides at its
|
|
4
|
+
* front (`NO_DEVICE: …`, `NO_CAPACITY[ram-budget]: …`) and `parseClaimError` reads it back where it is reported.
|
|
5
|
+
*/
|
|
6
|
+
/** Why the host has no room for the boots a claim needs. */
|
|
7
|
+
export type CapacityReason = "ram-budget" | "cpu-budget" | "memory-pressure" | "host-load";
|
|
8
|
+
export type ClaimErrorCode = "QUEUE_TIMEOUT" | "NO_CAPACITY" | "NO_DEVICE" | "REQUESTER_LIMIT" | "RUNTIME_MISSING" | "HEALTH_FAILED" | "LEASE_LOST";
|
|
9
|
+
/** What a claim error says: its code, and for `NO_CAPACITY` which resource ran out. */
|
|
10
|
+
export type ClaimErrorKind = {
|
|
11
|
+
code: "NO_CAPACITY";
|
|
12
|
+
capacityReason: CapacityReason;
|
|
13
|
+
} | {
|
|
14
|
+
code: Exclude<ClaimErrorCode, "NO_CAPACITY">;
|
|
15
|
+
};
|
|
16
|
+
export type ClaimErrorEntry = {
|
|
17
|
+
exit: number;
|
|
18
|
+
hint: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Exit codes 5-11 are claim failures; 1 stays the generic failure, 2 someone else's device / an ambiguous pick,
|
|
22
|
+
* 3 a missing tool, 4 a stale ref, 124 a timed-out job and 130 an interrupt.
|
|
23
|
+
*/
|
|
24
|
+
export declare const CLAIM_ERRORS: Record<ClaimErrorCode, ClaimErrorEntry>;
|
|
25
|
+
/** `NO_DEVICE: <message>` / `NO_CAPACITY[ram-budget]: <message>`. */
|
|
26
|
+
export declare function claimError(kind: ClaimErrorKind, message: string): string;
|
|
27
|
+
/** A claim error read back from its message: the code, its exit code and hint, and the message without the tag. */
|
|
28
|
+
export type ParsedClaimError = ClaimErrorKind & ClaimErrorEntry & {
|
|
29
|
+
message: string;
|
|
30
|
+
};
|
|
31
|
+
/** The coded claim error at the front of `error`, or undefined for an uncoded failure. */
|
|
32
|
+
export declare function parseClaimError(error: string): ParsedClaimError | undefined;
|
|
33
|
+
/** Is this provider error a missing runtime / AVD (`RUNTIME_MISSING`)? */
|
|
34
|
+
export declare const isRuntimeMissing: (error: string) => boolean;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { A11yCondition } from "./conditions.types";
|
|
2
|
+
/**
|
|
3
|
+
* Accessibility settings that live in `defaults` / `settings` rather than `simctl ui` or `font_scale`. Shared by the
|
|
4
|
+
* e2e driver (apply) and condition undo (reset), so the two can never name different keys.
|
|
5
|
+
*/
|
|
6
|
+
export declare const IOS_A11Y_DOMAIN = "com.apple.Accessibility";
|
|
7
|
+
/** Condition field to the `com.apple.Accessibility` key it sets on a simulator (applied live, no relaunch). */
|
|
8
|
+
export declare const IOS_A11Y_DEFAULTS: {
|
|
9
|
+
readonly reduceMotion: "ReduceMotionEnabled";
|
|
10
|
+
readonly boldText: "EnhancedTextLegibilityEnabled";
|
|
11
|
+
readonly reduceTransparency: "EnhancedBackgroundContrastEnabled";
|
|
12
|
+
readonly buttonShapes: "ButtonShapesEnabled";
|
|
13
|
+
readonly differentiateWithoutColor: "DifferentiateWithoutColor";
|
|
14
|
+
readonly onOffLabels: "IncreaseButtonLegibilityEnabled";
|
|
15
|
+
readonly screenReader: "VoiceOverTouchEnabled";
|
|
16
|
+
};
|
|
17
|
+
export type IosDefaultsField = keyof typeof IOS_A11Y_DEFAULTS;
|
|
18
|
+
export declare const IOS_DEFAULTS_FIELDS: IosDefaultsField[];
|
|
19
|
+
/**
|
|
20
|
+
* One `simctl spawn <udid> defaults write` per entry. Not batched through `sh -c`: `simctl spawn` runs the
|
|
21
|
+
* simulator's own `defaults` only when it resolves the bare name itself (verified on iOS 26: `/usr/bin/defaults` and a
|
|
22
|
+
* shell both fail with "Could not write domain" / a dyld abort).
|
|
23
|
+
*/
|
|
24
|
+
export declare function iosDefaultsWriteArgvs(udid: string, entries: readonly (readonly [IosDefaultsField, boolean])[]): string[][];
|
|
25
|
+
/** `defaults delete` per field; a key that is not there exits 1, which the caller must tolerate (`iosDefaultsMissing`). */
|
|
26
|
+
export declare function iosDefaultsDeleteArgvs(udid: string, fields: readonly IosDefaultsField[]): string[][];
|
|
27
|
+
/**
|
|
28
|
+
* `defaults delete` of a key that is not there exits 1: "does not exist" (older Xcode), "Could not find key" (Xcode
|
|
29
|
+
* 27), or "Domain not found" when the whole domain is empty. Already as wanted.
|
|
30
|
+
*/
|
|
31
|
+
export declare const iosDefaultsMissing: (stderr: string) => boolean;
|
|
32
|
+
/** The defaults-backed fields a recorded condition holds, i.e. the keys warden wrote (and may delete). */
|
|
33
|
+
export declare function iosDefaultsFields(record: A11yCondition): IosDefaultsField[];
|
|
34
|
+
/** `settings put` argvs (no `adb shell` prefix) that undo the Android-only fields a recorded condition holds. */
|
|
35
|
+
export declare function androidA11yResets(record: A11yCondition): string[][];
|
|
36
|
+
/** Android setting names TalkBack mode writes. */
|
|
37
|
+
export declare const ANDROID_SERVICES_KEY = "enabled_accessibility_services";
|
|
38
|
+
export declare const ANDROID_A11Y_ENABLED_KEY = "accessibility_enabled";
|
|
39
|
+
/** The `settings` argv (no `adb shell` prefix) that sets a secure key to `value`, or deletes it when it was unset. */
|
|
40
|
+
export declare function androidSecureRestoreArgv(key: string, value: string | null): string[];
|
|
41
|
+
/**
|
|
42
|
+
* TalkBack mode on Android: put back the accessibility services and master switch that were there before. Nothing
|
|
43
|
+
* when the record has no `screenReaderPrevious` (warden did not turn a screen reader on, so it has nothing to restore).
|
|
44
|
+
*/
|
|
45
|
+
export declare function androidScreenReaderResets(record: A11yCondition): string[][];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Result } from "../../../types/src/result";
|
|
2
|
+
import type { CameraFacing, CameraFeed } from "./conditions.types";
|
|
3
|
+
export type CameraMediaKind = CameraFeed["kind"];
|
|
4
|
+
export type CameraMediaExt = "png" | "jpg" | "heic" | "mp4" | "mov";
|
|
5
|
+
export type CameraMediaError = {
|
|
6
|
+
code: "E_CAMERA_NOT_FOUND" | "E_CAMERA_MEDIA";
|
|
7
|
+
message: string;
|
|
8
|
+
};
|
|
9
|
+
/** The kind of a camera asset from its leading bytes (the extension is ignored): png / jpg / heic image, mp4 / mov video. */
|
|
10
|
+
export declare function sniffCameraMedia(path: string): Result<{
|
|
11
|
+
kind: CameraMediaKind;
|
|
12
|
+
ext: CameraMediaExt;
|
|
13
|
+
}, CameraMediaError>;
|
|
14
|
+
/** Where a device's staged camera feeds live; the simulator / emulator reads them straight off the host filesystem. */
|
|
15
|
+
export declare function cameraFeedDir(wardenHome: string, udid: string): string;
|
|
16
|
+
export type StageCameraFeedInput = {
|
|
17
|
+
wardenHome: string;
|
|
18
|
+
udid: string;
|
|
19
|
+
facing: CameraFacing;
|
|
20
|
+
source: string;
|
|
21
|
+
/** video only: play again from the start at the end (default true where the caller has no opinion) */
|
|
22
|
+
loop: boolean;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Copy a camera asset to `<camera dir>/<facing>-<content hash>.<ext>`. The name changes with the content, so a
|
|
26
|
+
* consumer that compares paths (the iOS dylib, the Android swap) sees every new asset as new.
|
|
27
|
+
*/
|
|
28
|
+
export declare function stageCameraFeed(input: StageCameraFeedInput): Result<CameraFeed, CameraMediaError>;
|
|
29
|
+
/** Remove every staged feed of a device (release / reset). Missing dir is fine. */
|
|
30
|
+
export declare function clearCameraFeeds(wardenHome: string, udid: string): void;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { type Result } from "../../../types/src/result";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { type A11yCondition, type ClockCondition, type LocationCondition, type NetworkCondition, type NetworkPreset, type PermissionName, type PermissionState } from "./conditions.types";
|
|
4
|
+
/** `network: { latencyMs, ... }`: the same fields as a `custom` network condition, without its `kind`. */
|
|
5
|
+
declare const customNetworkSchema: z.ZodObject<{
|
|
6
|
+
latencyMs: z.ZodOptional<z.ZodNumber>;
|
|
7
|
+
jitterMs: z.ZodOptional<z.ZodNumber>;
|
|
8
|
+
downKbps: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
upKbps: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
lossPct: z.ZodOptional<z.ZodNumber>;
|
|
11
|
+
}, z.core.$strict>;
|
|
12
|
+
/**
|
|
13
|
+
* `conditions` (top level, or per `e2e.<suite>`): what every spec of the suite starts from. `network`, `location`
|
|
14
|
+
* and `clock` are applied before the app launches and put back after each spec, as are `permissions`, `locale`,
|
|
15
|
+
* `timezone` and `a11y`.
|
|
16
|
+
*/
|
|
17
|
+
export declare const conditionsConfigSchema: z.ZodObject<{
|
|
18
|
+
network: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
19
|
+
edge: "edge";
|
|
20
|
+
"3g": "3g";
|
|
21
|
+
"4g": "4g";
|
|
22
|
+
lte: "lte";
|
|
23
|
+
wifi: "wifi";
|
|
24
|
+
slow: "slow";
|
|
25
|
+
lossy: "lossy";
|
|
26
|
+
online: "online";
|
|
27
|
+
offline: "offline";
|
|
28
|
+
}>, z.ZodObject<{
|
|
29
|
+
latencyMs: z.ZodOptional<z.ZodNumber>;
|
|
30
|
+
jitterMs: z.ZodOptional<z.ZodNumber>;
|
|
31
|
+
downKbps: z.ZodOptional<z.ZodNumber>;
|
|
32
|
+
upKbps: z.ZodOptional<z.ZodNumber>;
|
|
33
|
+
lossPct: z.ZodOptional<z.ZodNumber>;
|
|
34
|
+
}, z.core.$strict>]>>;
|
|
35
|
+
location: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
36
|
+
"city-run": "city-run";
|
|
37
|
+
"city-bike": "city-bike";
|
|
38
|
+
freeway: "freeway";
|
|
39
|
+
}>, z.ZodObject<{
|
|
40
|
+
lat: z.ZodNumber;
|
|
41
|
+
lon: z.ZodNumber;
|
|
42
|
+
altM: z.ZodOptional<z.ZodNumber>;
|
|
43
|
+
}, z.core.$strict>]>>;
|
|
44
|
+
clock: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
45
|
+
at: z.ZodString;
|
|
46
|
+
frozen: z.ZodOptional<z.ZodBoolean>;
|
|
47
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
48
|
+
offset: z.ZodString;
|
|
49
|
+
}, z.core.$strict>]>>;
|
|
50
|
+
permissions: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
|
|
51
|
+
location: "location";
|
|
52
|
+
locationAlways: "locationAlways";
|
|
53
|
+
camera: "camera";
|
|
54
|
+
photos: "photos";
|
|
55
|
+
photosAdd: "photosAdd";
|
|
56
|
+
contacts: "contacts";
|
|
57
|
+
contactsLimited: "contactsLimited";
|
|
58
|
+
notifications: "notifications";
|
|
59
|
+
microphone: "microphone";
|
|
60
|
+
calendar: "calendar";
|
|
61
|
+
reminders: "reminders";
|
|
62
|
+
motion: "motion";
|
|
63
|
+
mediaLibrary: "mediaLibrary";
|
|
64
|
+
siri: "siri";
|
|
65
|
+
}> & z.core.$partial, z.ZodEnum<{
|
|
66
|
+
granted: "granted";
|
|
67
|
+
denied: "denied";
|
|
68
|
+
unset: "unset";
|
|
69
|
+
}>>>;
|
|
70
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
71
|
+
timezone: z.ZodOptional<z.ZodString>;
|
|
72
|
+
a11y: z.ZodOptional<z.ZodObject<{
|
|
73
|
+
textSize: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
74
|
+
"extra-small": "extra-small";
|
|
75
|
+
small: "small";
|
|
76
|
+
medium: "medium";
|
|
77
|
+
large: "large";
|
|
78
|
+
"extra-large": "extra-large";
|
|
79
|
+
"extra-extra-large": "extra-extra-large";
|
|
80
|
+
"extra-extra-extra-large": "extra-extra-extra-large";
|
|
81
|
+
"accessibility-medium": "accessibility-medium";
|
|
82
|
+
"accessibility-large": "accessibility-large";
|
|
83
|
+
"accessibility-extra-large": "accessibility-extra-large";
|
|
84
|
+
"accessibility-extra-extra-large": "accessibility-extra-extra-large";
|
|
85
|
+
"accessibility-extra-extra-extra-large": "accessibility-extra-extra-extra-large";
|
|
86
|
+
}>, z.ZodNumber]>>;
|
|
87
|
+
boldText: z.ZodOptional<z.ZodBoolean>;
|
|
88
|
+
contrast: z.ZodOptional<z.ZodEnum<{
|
|
89
|
+
increased: "increased";
|
|
90
|
+
normal: "normal";
|
|
91
|
+
}>>;
|
|
92
|
+
reduceMotion: z.ZodOptional<z.ZodBoolean>;
|
|
93
|
+
}, z.core.$strict>>;
|
|
94
|
+
}, z.core.$strict>;
|
|
95
|
+
export type ConditionsConfig = z.input<typeof conditionsConfigSchema>;
|
|
96
|
+
/**
|
|
97
|
+
* A suite's `camera` key: the asset each facing plays from the first `app.open()` on. A path, or `{ path, loop }`
|
|
98
|
+
* (`loop` applies to a video, default true). Paths are relative to the config file.
|
|
99
|
+
*/
|
|
100
|
+
export declare const cameraConfigSchema: z.ZodObject<{
|
|
101
|
+
back: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
102
|
+
path: z.ZodString;
|
|
103
|
+
loop: z.ZodOptional<z.ZodBoolean>;
|
|
104
|
+
}, z.core.$strict>]>>;
|
|
105
|
+
front: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
106
|
+
path: z.ZodString;
|
|
107
|
+
loop: z.ZodOptional<z.ZodBoolean>;
|
|
108
|
+
}, z.core.$strict>]>>;
|
|
109
|
+
}, z.core.$strict>;
|
|
110
|
+
export type CameraConfig = z.input<typeof cameraConfigSchema>;
|
|
111
|
+
/** A suite's camera with absolute paths and a loop flag per facing: what `WARDEN_CAMERA_FEEDS` carries. */
|
|
112
|
+
export type CameraSuiteFeeds = Partial<Record<"back" | "front", {
|
|
113
|
+
path: string;
|
|
114
|
+
loop: boolean;
|
|
115
|
+
}>>;
|
|
116
|
+
/** `camera` as absolute paths (against `baseDir`, the config file's directory) with `loop` defaulted to true. */
|
|
117
|
+
export declare function resolveCameraConfig(config: CameraConfig, baseDir: string): CameraSuiteFeeds;
|
|
118
|
+
/** `WARDEN_CAMERA_FEEDS`: the JSON of a suite's resolved camera, checked again on the spec side. */
|
|
119
|
+
export declare function parseCameraFeedsEnv(raw: string): Result<CameraSuiteFeeds>;
|
|
120
|
+
/** What a spec's `device.network.set` takes: a condition, or its word. */
|
|
121
|
+
export type NetworkInput = NetworkCondition | "online" | "offline" | NetworkPreset;
|
|
122
|
+
/** A word, a custom shape (config) or a ready condition, as a `NetworkCondition`. */
|
|
123
|
+
export declare function toNetworkCondition(input: NetworkInput | z.infer<typeof customNetworkSchema>): Result<NetworkCondition>;
|
|
124
|
+
export type SuiteConditions = {
|
|
125
|
+
network?: NetworkCondition;
|
|
126
|
+
location?: LocationCondition;
|
|
127
|
+
clock?: ClockCondition;
|
|
128
|
+
permissions?: Partial<Record<PermissionName, PermissionState>>;
|
|
129
|
+
locale?: string;
|
|
130
|
+
timezone?: string;
|
|
131
|
+
a11y?: A11yCondition;
|
|
132
|
+
};
|
|
133
|
+
/** A config as conditions: shaped values, with a text size resolved. */
|
|
134
|
+
export declare function normalizeConditions(config: ConditionsConfig): Result<{
|
|
135
|
+
conditions: SuiteConditions;
|
|
136
|
+
}>;
|
|
137
|
+
/** The suite's `conditions` over the top-level ones, per area; undefined when neither sets any. */
|
|
138
|
+
export declare function mergeConditionsConfig(top: ConditionsConfig | undefined, own: ConditionsConfig | undefined): ConditionsConfig | undefined;
|
|
139
|
+
/** `WARDEN_CONDITIONS`: the JSON of a suite's config, checked again on the spec side. */
|
|
140
|
+
export declare function parseConditionsEnv(raw: string): Result<ConditionsConfig>;
|
|
141
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type Result } from "../../../types/src/result";
|
|
2
|
+
import type { Store } from "../store";
|
|
3
|
+
import { type ConditionArea, type ConditionRecord, type ConditionValues, type OwnedProcess } from "./conditions.types";
|
|
4
|
+
export type ConditionRow = {
|
|
5
|
+
area: ConditionArea;
|
|
6
|
+
json: string;
|
|
7
|
+
owned: string;
|
|
8
|
+
set_at: number;
|
|
9
|
+
};
|
|
10
|
+
export declare function toConditionRecord(row: ConditionRow): ConditionRecord;
|
|
11
|
+
/**
|
|
12
|
+
* Persist what a lease has set on its device so release, gc and a crashed process can undo it. One
|
|
13
|
+
* slot per area: recording again replaces the value. `owned` (processes undo must stop) is kept as
|
|
14
|
+
* is when omitted and replaced when given — a caller swapping a proxy kills the old one itself.
|
|
15
|
+
*/
|
|
16
|
+
export declare function recordCondition<A extends ConditionArea>(store: Store, leaseId: string, area: A, value: ConditionValues[A], now: number, owned?: readonly OwnedProcess[]): Result<ConditionRecord>;
|
|
17
|
+
/** Forget one area of a lease; false when it was not set. */
|
|
18
|
+
export declare function clearCondition(store: Store, leaseId: string, area: ConditionArea): boolean;
|
|
19
|
+
/** Forget every area of a lease; returns how many were set. */
|
|
20
|
+
export declare function clearConditions(store: Store, leaseId: string): number;
|
|
21
|
+
/** What a lease currently has set, in `CONDITION_AREAS` order. */
|
|
22
|
+
export declare function activeConditions(store: Store, leaseId: string): ConditionRecord[];
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
export type NetworkPreset = "edge" | "3g" | "4g" | "lte" | "wifi" | "slow" | "lossy";
|
|
2
|
+
export type NetworkCondition = {
|
|
3
|
+
kind: "online";
|
|
4
|
+
} | {
|
|
5
|
+
kind: "offline";
|
|
6
|
+
} | {
|
|
7
|
+
kind: "preset";
|
|
8
|
+
preset: NetworkPreset;
|
|
9
|
+
} | {
|
|
10
|
+
kind: "custom";
|
|
11
|
+
latencyMs?: number;
|
|
12
|
+
jitterMs?: number;
|
|
13
|
+
downKbps?: number;
|
|
14
|
+
upKbps?: number;
|
|
15
|
+
lossPct?: number;
|
|
16
|
+
} | {
|
|
17
|
+
kind: "flap";
|
|
18
|
+
upMs: number;
|
|
19
|
+
downMs: number;
|
|
20
|
+
jitterPct?: number;
|
|
21
|
+
base?: NetworkCondition;
|
|
22
|
+
};
|
|
23
|
+
/** A per-host fault the lease's shaping proxy applies; `match` is a host glob. */
|
|
24
|
+
export type HostFault = {
|
|
25
|
+
match: string;
|
|
26
|
+
action: {
|
|
27
|
+
kind: "status";
|
|
28
|
+
code: number;
|
|
29
|
+
} | {
|
|
30
|
+
kind: "reset";
|
|
31
|
+
} | {
|
|
32
|
+
kind: "delay";
|
|
33
|
+
ms: number;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "blackhole";
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
export type LatLon = {
|
|
39
|
+
lat: number;
|
|
40
|
+
lon: number;
|
|
41
|
+
};
|
|
42
|
+
export type LocationScenario = "city-run" | "city-bike" | "freeway";
|
|
43
|
+
export type LocationCondition = {
|
|
44
|
+
kind: "point";
|
|
45
|
+
lat: number;
|
|
46
|
+
lon: number;
|
|
47
|
+
altM?: number;
|
|
48
|
+
} | {
|
|
49
|
+
kind: "route";
|
|
50
|
+
points: readonly LatLon[];
|
|
51
|
+
speedMps?: number;
|
|
52
|
+
intervalS?: number;
|
|
53
|
+
loop?: boolean;
|
|
54
|
+
} | {
|
|
55
|
+
kind: "gpx";
|
|
56
|
+
path: string;
|
|
57
|
+
speedMps?: number;
|
|
58
|
+
} | {
|
|
59
|
+
kind: "scenario";
|
|
60
|
+
name: LocationScenario;
|
|
61
|
+
} | {
|
|
62
|
+
kind: "clear";
|
|
63
|
+
};
|
|
64
|
+
export type ClockCondition = {
|
|
65
|
+
kind: "real";
|
|
66
|
+
} | {
|
|
67
|
+
kind: "offset";
|
|
68
|
+
ms: number;
|
|
69
|
+
} | {
|
|
70
|
+
kind: "fixed";
|
|
71
|
+
at: string;
|
|
72
|
+
} | {
|
|
73
|
+
kind: "frozen";
|
|
74
|
+
at: string;
|
|
75
|
+
};
|
|
76
|
+
export type PermissionState = "granted" | "denied" | "unset";
|
|
77
|
+
/** The permission names a spec, `warden ui permission` and a suite's `conditions.permissions` use; each maps to platform services in the driver. */
|
|
78
|
+
export declare const PERMISSION_NAMES: readonly ["location", "locationAlways", "camera", "photos", "photosAdd", "contacts", "contactsLimited", "notifications", "microphone", "calendar", "reminders", "motion", "mediaLibrary", "siri"];
|
|
79
|
+
export type PermissionName = (typeof PERMISSION_NAMES)[number];
|
|
80
|
+
export declare const isPermissionName: (v: string) => v is PermissionName;
|
|
81
|
+
/** Runtime permission grants applied to apps on the device. */
|
|
82
|
+
export type PermissionCondition = {
|
|
83
|
+
grants: readonly {
|
|
84
|
+
bundleId: string;
|
|
85
|
+
permission: PermissionName;
|
|
86
|
+
state: PermissionState;
|
|
87
|
+
}[];
|
|
88
|
+
};
|
|
89
|
+
/** Locale applies to one app (`bundleId`); timezone to the device (Android) or the next launch (iOS). */
|
|
90
|
+
export type LocaleCondition = {
|
|
91
|
+
locale?: string;
|
|
92
|
+
timezone?: string;
|
|
93
|
+
bundleId?: string;
|
|
94
|
+
/** Android: the timezone before the first change, put back on release */
|
|
95
|
+
previousTimezone?: string;
|
|
96
|
+
};
|
|
97
|
+
/** A named text size (iOS content size categories) or a font scale where 1 is the default. */
|
|
98
|
+
export type TextSize = (typeof TEXT_SIZE_NAMES)[number] | number;
|
|
99
|
+
export declare const TEXT_SIZE_NAMES: readonly ["extra-small", "small", "medium", "large", "extra-large", "extra-extra-large", "extra-extra-extra-large", "accessibility-medium", "accessibility-large", "accessibility-extra-large", "accessibility-extra-extra-large", "accessibility-extra-extra-extra-large"];
|
|
100
|
+
export type A11yCondition = {
|
|
101
|
+
textSize?: TextSize;
|
|
102
|
+
/** resolved font scale of `textSize` (1 = default) */
|
|
103
|
+
fontScale?: number;
|
|
104
|
+
reduceMotion?: boolean;
|
|
105
|
+
boldText?: boolean;
|
|
106
|
+
contrast?: "increased" | "normal";
|
|
107
|
+
reduceTransparency?: boolean;
|
|
108
|
+
buttonShapes?: boolean;
|
|
109
|
+
differentiateWithoutColor?: boolean;
|
|
110
|
+
onOffLabels?: boolean;
|
|
111
|
+
highContrastText?: boolean;
|
|
112
|
+
colorInversion?: boolean;
|
|
113
|
+
screenReader?: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Android TalkBack: the `enabled_accessibility_services` and `accessibility_enabled` values (`null` = unset) the
|
|
116
|
+
* device had before warden turned TalkBack on, so undo puts back exactly those and never drops a service warden
|
|
117
|
+
* did not add. Present only while `screenReader` is true on Android.
|
|
118
|
+
*/
|
|
119
|
+
screenReaderPrevious?: {
|
|
120
|
+
services: string | null;
|
|
121
|
+
enabled: string | null;
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
/** `cosmetic`: the status bar says so, the OS and the app still see the real battery (iOS simulators) */
|
|
125
|
+
export type BatteryCondition = {
|
|
126
|
+
level?: number;
|
|
127
|
+
charging?: boolean;
|
|
128
|
+
cosmetic?: boolean;
|
|
129
|
+
};
|
|
130
|
+
export type CameraFacing = "back" | "front";
|
|
131
|
+
export declare const CAMERA_FACINGS: readonly CameraFacing[];
|
|
132
|
+
/** A staged asset the simulated camera plays; `path` is the staged copy under the device's camera dir. */
|
|
133
|
+
export type CameraFeed = {
|
|
134
|
+
kind: "image";
|
|
135
|
+
path: string;
|
|
136
|
+
} | {
|
|
137
|
+
kind: "video";
|
|
138
|
+
path: string;
|
|
139
|
+
loop: boolean;
|
|
140
|
+
};
|
|
141
|
+
/** The simulated camera per facing; a facing left out has no camera (iOS) or the emulator's default (Android). */
|
|
142
|
+
export type CameraCondition = Partial<Record<CameraFacing, CameraFeed>>;
|
|
143
|
+
/** Everything a lease can have set on its device, one slot per area. */
|
|
144
|
+
export type ConditionValues = {
|
|
145
|
+
network: NetworkCondition;
|
|
146
|
+
location: LocationCondition;
|
|
147
|
+
clock: ClockCondition;
|
|
148
|
+
permission: PermissionCondition;
|
|
149
|
+
locale: LocaleCondition;
|
|
150
|
+
a11y: A11yCondition;
|
|
151
|
+
battery: BatteryCondition;
|
|
152
|
+
camera: CameraCondition;
|
|
153
|
+
};
|
|
154
|
+
export type ConditionArea = keyof ConditionValues;
|
|
155
|
+
/** Display/iteration order; also the order undo resets areas in. */
|
|
156
|
+
export declare const CONDITION_AREAS: readonly ConditionArea[];
|
|
157
|
+
/** A process warden spawned to hold a condition (shaping proxy, route ticker); undo kills it. */
|
|
158
|
+
export type OwnedProcess = {
|
|
159
|
+
kind: "pid";
|
|
160
|
+
pid: number;
|
|
161
|
+
};
|
|
162
|
+
/** One active condition on a lease, discriminated by `area`. */
|
|
163
|
+
export type ConditionRecord = {
|
|
164
|
+
[A in ConditionArea]: {
|
|
165
|
+
area: A;
|
|
166
|
+
value: ConditionValues[A];
|
|
167
|
+
/** processes undo must stop */
|
|
168
|
+
owned: readonly OwnedProcess[];
|
|
169
|
+
setAt: number;
|
|
170
|
+
};
|
|
171
|
+
}[ConditionArea];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The state file an iOS app launched with `libwarden-inject.dylib` watches (offline flag, wall-clock offset /
|
|
3
|
+
* freeze). The e2e driver owns the full format (`packages/e2e/src/driver/ios/inject.ts`); core only knows where it
|
|
4
|
+
* lives and how to put it back to neutral on release, so a still-running injected app stops seeing the lease's
|
|
5
|
+
* offline or shifted clock.
|
|
6
|
+
*/
|
|
7
|
+
export declare function injectStatePath(wardenHome: string, udid: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Write `{ seq: previous + 1, offline: false, clockOffsetMs: 0, camera: {} }` (no freeze, no camera feeds) when a state file exists; the dylib
|
|
10
|
+
* applies any higher `seq`. No file = no injected app was ever launched on the device: nothing to do.
|
|
11
|
+
* Returns an error message, or undefined.
|
|
12
|
+
*/
|
|
13
|
+
export declare function neutralizeInjectState(path: string): string | undefined;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the next launch of an app on an iOS simulator should carry: a simulator has no per-device timezone or
|
|
3
|
+
* locale, so both ride on the app's launch (`TZ` env, `-AppleLanguages` / `-AppleLocale` args). `warden ui` sets
|
|
4
|
+
* them in one process and launches in another, so they are staged in a file per device; release removes it.
|
|
5
|
+
*/
|
|
6
|
+
export type LaunchSettings = {
|
|
7
|
+
timezone?: string;
|
|
8
|
+
locale?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function launchSettingsPath(wardenHome: string, udid: string): string;
|
|
11
|
+
/** The staged settings; none (or an unreadable file) is `{}`. */
|
|
12
|
+
export declare function readLaunchSettings(path: string): LaunchSettings;
|
|
13
|
+
/** Replace the staged settings; an empty one removes the file. Returns an error message, or undefined. */
|
|
14
|
+
export declare function writeLaunchSettings(path: string, settings: LaunchSettings): string | undefined;
|