@delacour/warden-e2e 0.5.0 → 0.7.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.
Files changed (88) hide show
  1. package/{chunk-j9b17ade.mjs → chunk-empqr9n0.mjs} +1366 -55
  2. package/index.mjs +34 -4
  3. package/package.json +2 -2
  4. package/preload.mjs +4008 -335
  5. package/types/core/src/affected/affected.schema.d.ts +93 -0
  6. package/types/core/src/allocate.d.ts +2 -1
  7. package/types/core/src/android-keyguard.d.ts +34 -0
  8. package/types/core/src/batch/preset.schema.d.ts +1 -0
  9. package/types/core/src/biometrics.d.ts +15 -0
  10. package/types/core/src/builds/builds.defaults.d.ts +15 -0
  11. package/types/core/src/builds/config.d.ts +5 -1
  12. package/types/core/src/builds/config.schema.d.ts +182 -0
  13. package/types/core/src/builds/define-config.d.ts +104 -0
  14. package/types/core/src/builds/install-device.d.ts +37 -0
  15. package/types/core/src/builds/install.d.ts +17 -3
  16. package/types/core/src/builds/kinds.d.ts +21 -3
  17. package/types/core/src/builds/lock.d.ts +38 -0
  18. package/types/core/src/builds/resolve.d.ts +12 -2
  19. package/types/core/src/conditions/conditions.config.d.ts +117 -0
  20. package/types/core/src/conditions/conditions.d.ts +22 -0
  21. package/types/core/src/conditions/conditions.types.d.ts +141 -0
  22. package/types/core/src/conditions/inject-state.d.ts +13 -0
  23. package/types/core/src/conditions/launch-settings.d.ts +14 -0
  24. package/types/core/src/conditions/network.presets.d.ts +42 -0
  25. package/types/core/src/conditions/text-size.d.ts +19 -0
  26. package/types/core/src/golden/android-biometrics.d.ts +35 -0
  27. package/types/core/src/ios-runner/classify.d.ts +7 -0
  28. package/types/core/src/ios-runner/runner-build.types.d.ts +76 -0
  29. package/types/core/src/netproxy/control.d.ts +75 -0
  30. package/types/core/src/netproxy/decide.d.ts +22 -0
  31. package/types/core/src/netproxy/handle-file.d.ts +12 -0
  32. package/types/core/src/netproxy/lease-proxy.d.ts +53 -0
  33. package/types/core/src/netproxy/netproxy.main.d.ts +40 -0
  34. package/types/core/src/netproxy/pipe.d.ts +37 -0
  35. package/types/core/src/netproxy/proxy.d.ts +48 -0
  36. package/types/core/src/netproxy/shaping.d.ts +43 -0
  37. package/types/core/src/providers/android.d.ts +36 -1
  38. package/types/core/src/types.d.ts +47 -0
  39. package/types/e2e/src/alert-buttons.d.ts +9 -0
  40. package/types/e2e/src/app.d.ts +3 -1
  41. package/types/e2e/src/conditions/condition-events.d.ts +63 -0
  42. package/types/e2e/src/conditions/device-conditions.d.ts +170 -0
  43. package/types/e2e/src/conditions/geo.d.ts +15 -0
  44. package/types/e2e/src/conditions/gpx.d.ts +8 -0
  45. package/types/e2e/src/conditions/lease-recorder.d.ts +27 -0
  46. package/types/e2e/src/conditions/lease-store.d.ts +9 -0
  47. package/types/e2e/src/conditions/location-plan.d.ts +17 -0
  48. package/types/e2e/src/conditions/location-scenarios.data.d.ts +17 -0
  49. package/types/e2e/src/conditions/route-ticker.d.ts +53 -0
  50. package/types/e2e/src/conditions/scheduler.d.ts +83 -0
  51. package/types/e2e/src/device.d.ts +57 -3
  52. package/types/e2e/src/driver/android/android-app.d.ts +4 -0
  53. package/types/e2e/src/driver/android/android-argv.d.ts +19 -0
  54. package/types/e2e/src/driver/android/android-clock.d.ts +28 -0
  55. package/types/e2e/src/driver/android/android-device.d.ts +8 -0
  56. package/types/e2e/src/driver/android/android-driver.d.ts +17 -0
  57. package/types/e2e/src/driver/android/android-network.d.ts +66 -0
  58. package/types/e2e/src/driver/android/android-phone.d.ts +47 -0
  59. package/types/e2e/src/driver/android/android-settings.d.ts +34 -0
  60. package/types/e2e/src/driver/android/android-state.d.ts +10 -0
  61. package/types/e2e/src/driver/clock-recorder.d.ts +9 -0
  62. package/types/e2e/src/driver/device-settings.d.ts +10 -0
  63. package/types/e2e/src/driver/driver.types.d.ts +176 -1
  64. package/types/e2e/src/driver/ios/device/capabilities.d.ts +3 -0
  65. package/types/e2e/src/driver/ios/device/device-driver.d.ts +49 -0
  66. package/types/e2e/src/driver/ios/device/devicectl.d.ts +38 -0
  67. package/types/e2e/src/driver/ios/device/runner-protocol.d.ts +21 -0
  68. package/types/e2e/src/driver/ios/hid-recovery.d.ts +15 -0
  69. package/types/e2e/src/driver/ios/inject.d.ts +110 -0
  70. package/types/e2e/src/driver/ios/ios-driver.d.ts +29 -0
  71. package/types/e2e/src/driver/ios/ios-network.d.ts +46 -0
  72. package/types/e2e/src/driver/ios/ios-settings.d.ts +44 -0
  73. package/types/e2e/src/driver/ios/simctl.d.ts +41 -1
  74. package/types/e2e/src/driver/ios/type-budget.d.ts +6 -1
  75. package/types/e2e/src/driver/network-proxy.d.ts +52 -0
  76. package/types/e2e/src/driver/open.d.ts +20 -0
  77. package/types/e2e/src/driver/physical-conditions.d.ts +11 -0
  78. package/types/e2e/src/driver/requirements.d.ts +14 -0
  79. package/types/e2e/src/driver/typing.d.ts +1 -1
  80. package/types/e2e/src/env.d.ts +32 -0
  81. package/types/e2e/src/fixture-session.d.ts +4 -0
  82. package/types/e2e/src/fixtures.d.ts +6 -1
  83. package/types/e2e/src/index.d.ts +2 -0
  84. package/types/e2e/src/runner/scope.d.ts +1 -0
  85. package/types/e2e/src/runner/test.d.ts +6 -0
  86. package/types/e2e/src/screen/field.d.ts +5 -3
  87. package/types/e2e/src/screen/locator.d.ts +3 -2
  88. package/types/e2e/src/traced-device.d.ts +2 -1
@@ -39,12 +39,19 @@ export declare const e2eMetroSchema: z.ZodObject<{
39
39
  prewarm: z.ZodDefault<z.ZodBoolean>;
40
40
  readyTimeout: z.ZodDefault<z.ZodString>;
41
41
  }, z.core.$strict>;
42
+ /** `physical` on a suite or leg: `true` = any ready physical device, `{ ids }` = exactly these (adb serials / CoreDevice UDIDs). Never booted, created or arranged. */
43
+ export declare const physicalSchema: z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
44
+ ids: z.ZodArray<z.ZodString>;
45
+ }, z.core.$strict>]>;
42
46
  /** `e2e.<suite>.devices[]`: one leg of the run, with its own device pool. */
43
47
  export declare const e2eDeviceLegSchema: z.ZodObject<{
44
48
  profile: z.ZodString;
45
49
  count: z.ZodDefault<z.ZodNumber>;
46
50
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
47
51
  default: z.ZodDefault<z.ZodBoolean>;
52
+ physical: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
53
+ ids: z.ZodArray<z.ZodString>;
54
+ }, z.core.$strict>]>>;
48
55
  }, z.core.$strict>;
49
56
  /** `perf` (top level, or per `e2e.<suite>`): ceilings `device.perf.stop()` holds the report to. Each is lower-is-better. */
50
57
  export declare const perfConfigSchema: z.ZodObject<{
@@ -92,6 +99,9 @@ export declare const e2eSuiteSchema: z.ZodObject<{
92
99
  count: z.ZodDefault<z.ZodNumber>;
93
100
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
94
101
  default: z.ZodDefault<z.ZodBoolean>;
102
+ physical: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
103
+ ids: z.ZodArray<z.ZodString>;
104
+ }, z.core.$strict>]>>;
95
105
  }, z.core.$strict>>>;
96
106
  metro: z.ZodOptional<z.ZodObject<{
97
107
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -108,6 +118,9 @@ export declare const e2eSuiteSchema: z.ZodObject<{
108
118
  ios: "ios";
109
119
  android: "android";
110
120
  }>>;
121
+ physical: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
122
+ ids: z.ZodArray<z.ZodString>;
123
+ }, z.core.$strict>]>>;
111
124
  base: z.ZodDefault<z.ZodString>;
112
125
  maxDepth: z.ZodOptional<z.ZodNumber>;
113
126
  runAll: z.ZodDefault<z.ZodArray<z.ZodString>>;
@@ -152,6 +165,7 @@ export declare const e2eSuiteSchema: z.ZodObject<{
152
165
  except: z.ZodOptional<z.ZodArray<z.ZodString>>;
153
166
  keep: z.ZodOptional<z.ZodArray<z.ZodString>>;
154
167
  }, z.core.$strict>]>>;
168
+ biometrics: z.ZodOptional<z.ZodBoolean>;
155
169
  warmRunners: z.ZodOptional<z.ZodUndefined>;
156
170
  warmDrivers: z.ZodOptional<z.ZodBoolean>;
157
171
  headless: z.ZodOptional<z.ZodBoolean>;
@@ -164,6 +178,84 @@ export declare const e2eSuiteSchema: z.ZodObject<{
164
178
  peakMemoryMb: z.ZodOptional<z.ZodNumber>;
165
179
  }, z.core.$strict>>;
166
180
  }, z.core.$strict>>;
181
+ conditions: z.ZodOptional<z.ZodObject<{
182
+ network: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
183
+ edge: "edge";
184
+ "3g": "3g";
185
+ "4g": "4g";
186
+ lte: "lte";
187
+ wifi: "wifi";
188
+ slow: "slow";
189
+ lossy: "lossy";
190
+ online: "online";
191
+ offline: "offline";
192
+ }>, z.ZodObject<{
193
+ latencyMs: z.ZodOptional<z.ZodNumber>;
194
+ jitterMs: z.ZodOptional<z.ZodNumber>;
195
+ downKbps: z.ZodOptional<z.ZodNumber>;
196
+ upKbps: z.ZodOptional<z.ZodNumber>;
197
+ lossPct: z.ZodOptional<z.ZodNumber>;
198
+ }, z.core.$strict>]>>;
199
+ location: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
200
+ "city-run": "city-run";
201
+ "city-bike": "city-bike";
202
+ freeway: "freeway";
203
+ }>, z.ZodObject<{
204
+ lat: z.ZodNumber;
205
+ lon: z.ZodNumber;
206
+ altM: z.ZodOptional<z.ZodNumber>;
207
+ }, z.core.$strict>]>>;
208
+ clock: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
209
+ at: z.ZodString;
210
+ frozen: z.ZodOptional<z.ZodBoolean>;
211
+ }, z.core.$strict>, z.ZodObject<{
212
+ offset: z.ZodString;
213
+ }, z.core.$strict>]>>;
214
+ permissions: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
215
+ location: "location";
216
+ locationAlways: "locationAlways";
217
+ camera: "camera";
218
+ photos: "photos";
219
+ photosAdd: "photosAdd";
220
+ contacts: "contacts";
221
+ contactsLimited: "contactsLimited";
222
+ notifications: "notifications";
223
+ microphone: "microphone";
224
+ calendar: "calendar";
225
+ reminders: "reminders";
226
+ motion: "motion";
227
+ mediaLibrary: "mediaLibrary";
228
+ siri: "siri";
229
+ }> & z.core.$partial, z.ZodEnum<{
230
+ granted: "granted";
231
+ denied: "denied";
232
+ unset: "unset";
233
+ }>>>;
234
+ locale: z.ZodOptional<z.ZodString>;
235
+ timezone: z.ZodOptional<z.ZodString>;
236
+ a11y: z.ZodOptional<z.ZodObject<{
237
+ textSize: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
238
+ "extra-small": "extra-small";
239
+ small: "small";
240
+ medium: "medium";
241
+ large: "large";
242
+ "extra-large": "extra-large";
243
+ "extra-extra-large": "extra-extra-large";
244
+ "extra-extra-extra-large": "extra-extra-extra-large";
245
+ "accessibility-medium": "accessibility-medium";
246
+ "accessibility-large": "accessibility-large";
247
+ "accessibility-extra-large": "accessibility-extra-large";
248
+ "accessibility-extra-extra-large": "accessibility-extra-extra-large";
249
+ "accessibility-extra-extra-extra-large": "accessibility-extra-extra-extra-large";
250
+ }>, z.ZodNumber]>>;
251
+ boldText: z.ZodOptional<z.ZodBoolean>;
252
+ contrast: z.ZodOptional<z.ZodEnum<{
253
+ increased: "increased";
254
+ normal: "normal";
255
+ }>>;
256
+ reduceMotion: z.ZodOptional<z.ZodBoolean>;
257
+ }, z.core.$strict>>;
258
+ }, z.core.$strict>>;
167
259
  required: z.ZodDefault<z.ZodBoolean>;
168
260
  specs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
169
261
  entries: z.ZodDefault<z.ZodArray<z.ZodString>>;
@@ -178,6 +270,7 @@ export declare const e2eSuiteSchema: z.ZodObject<{
178
270
  }, z.core.$strict>;
179
271
  export type E2eSpecConfig = z.infer<typeof e2eSpecSchema>;
180
272
  export type E2eMetroConfig = z.infer<typeof e2eMetroSchema>;
273
+ export type E2ePhysical = z.infer<typeof physicalSchema>;
181
274
  export type E2eDeviceLeg = z.infer<typeof e2eDeviceLegSchema>;
182
275
  export type E2eSpecEntryConfig = z.infer<typeof e2eSpecEntrySchema>;
183
276
  export type E2eSlimConfig = z.infer<typeof slimConfigSchema>;
@@ -18,6 +18,7 @@ export declare function compareRuntimeDesc(a: InventoryDevice, b: InventoryDevic
18
18
  /**
19
19
  * Pure allocation: which devices satisfy `request` given current leases. Free warden devices first
20
20
  * (booted before shutdown, newest runtime first), then pool growth up to `max`. Foreign devices are
21
- * only considered with `adopt`. Stale leases are ignored and returned for reclaim.
21
+ * only considered with `adopt`. Physical devices are never considered, even with `adopt`, unless
22
+ * `request.physical` asks for them: then only ready ones, no profile match, and nothing is created. Stale leases are ignored and returned for reclaim.
22
23
  */
23
24
  export declare function allocate({ inventory, leases, request, now, pidAlive, skip }: AllocateInput): AllocationPlan;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Android emulator keyguard + readiness for biometrics (`+bio`) devices. Fingerprint enrollment needs a secure
3
+ * lock (a PIN), so an enrolled emulator boots behind a lock screen and the app cannot resolve its launcher until
4
+ * the user is unlocked. A restored snapshot can also come back with a black, unresponsive SystemUI that ignores
5
+ * wake / dismiss / PIN input until SystemUI is restarted. Emulator serials only: never run on a foreign device.
6
+ */
7
+ import { type AsyncResult } from "../../types/src/result";
8
+ import type { Exec } from "./exec";
9
+ /** Keep the screen on and never time out, so the unlocked device does not lock again. */
10
+ export declare const STAY_AWAKE_COMMAND = "svc power stayon true; settings put system screen_off_timeout 2147483647";
11
+ /** Crashing SystemUI makes the system restart it with a fresh, responsive lock screen. */
12
+ export declare const SYSTEMUI_RESTART_COMMAND = "am crash com.android.systemui";
13
+ /** Wake, swipe the lock screen up to the PIN bouncer, type the PIN. */
14
+ export declare function unlockCommand(): string;
15
+ /** `isKeyguardShowing=` of `dumpsys window` (API 36), `undefined` when the dump has no such line. */
16
+ export declare function parseKeyguardShowing(dump: string): boolean | undefined;
17
+ export type KeyguardDeps = {
18
+ exec: Exec;
19
+ sleep: (ms: number) => Promise<void>;
20
+ /** the adb binary (`androidTools(env).adb`) */
21
+ adb: string;
22
+ now?: () => number;
23
+ };
24
+ /**
25
+ * Get past the lock screen (idempotent: nothing is typed when it is already gone) and keep the device awake.
26
+ * Up to three unlock attempts; before the last one SystemUI is restarted, which recovers a restored snapshot
27
+ * whose lock screen is black and ignores input.
28
+ */
29
+ export declare function ensureUnlocked(deps: KeyguardDeps, serial: string): AsyncResult<void>;
30
+ /**
31
+ * `adb get-state` = device and the package manager answering (`pm path android`), polled for up to `timeoutMs`:
32
+ * `boot_completed` can precede both on a restored snapshot, and an install in that window fails `device offline`.
33
+ */
34
+ export declare function systemReady(deps: KeyguardDeps, serial: string, timeoutMs: number): AsyncResult<void>;
@@ -40,6 +40,7 @@ export declare const batchPresetSchema: z.ZodObject<{
40
40
  except: z.ZodOptional<z.ZodArray<z.ZodString>>;
41
41
  keep: z.ZodOptional<z.ZodArray<z.ZodString>>;
42
42
  }, z.core.$strict>]>>;
43
+ biometrics: z.ZodOptional<z.ZodBoolean>;
43
44
  retry: z.ZodOptional<z.ZodNumber>;
44
45
  passes: z.ZodOptional<z.ZodNumber>;
45
46
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Biometric profiles. A profile with `biometrics: true` is a different device identity from the same profile
3
+ * without it: pool matching, goldens and snapshots all key on the profile string, so enrolled and plain
4
+ * devices never mix. The identity is the profile plus `+bio` (a character `profileSlug` never produces).
5
+ */
6
+ export declare const BIOMETRIC_PROFILE_SUFFIX = "+bio";
7
+ /** Screen-lock PIN set on every biometrics device (Android needs a secure lock before it enrolls a fingerprint). */
8
+ export declare const BIOMETRIC_PIN = "1111";
9
+ /** Finger id `emu finger touch` presents once enrolled; `99` matches nothing. */
10
+ export declare const BIOMETRIC_FINGER_ID = 1;
11
+ export declare function biometricProfile(profile: string, biometrics: boolean): string;
12
+ export declare function splitBiometricProfile(profile: string): {
13
+ profile: string;
14
+ biometrics: boolean;
15
+ };
@@ -12,6 +12,21 @@ export type BuildConfiguration = "Debug" | "Release";
12
12
  export declare const IOS_NATIVE_PREPARE: string;
13
13
  /** Local build command (run in the project root) when `build.<platform>` is not configured. */
14
14
  export declare function defaultBuildCommand(platform: Platform, configuration: BuildConfiguration, framework?: AppFramework): string;
15
+ /** What an iOS device build is signed with: the team (always) and, when set, the bundle id that replaces the project's. */
16
+ export type IosDeviceBuild = {
17
+ team: string;
18
+ bundleIdentifier?: string | undefined;
19
+ };
20
+ /** The `xcodebuild -derivedDataPath` of a device build, relative to `ios/`: products land in `ios/build/Build/Products/<Config>-iphoneos`. */
21
+ export declare const IOS_DEVICE_DERIVED_DATA = "build";
22
+ /**
23
+ * Local build command of an iOS build for a physical device. A plain `xcodebuild` on the prebuilt workspace (the scheme
24
+ * has the workspace's name, as in Expo and the React Native template): `expo run:ios` would install to a device itself
25
+ * and cannot take the team or `-allowProvisioningUpdates`. `generic/platform=iOS` builds for any device the team's
26
+ * development profile lists; `-allowProvisioningUpdates` lets Xcode create that profile. A Release build runs Xcode's
27
+ * own bundling phase, so the JS is embedded.
28
+ */
29
+ export declare function iosDeviceBuildCommand(configuration: BuildConfiguration, framework: AppFramework, device: IosDeviceBuild): string;
15
30
  /** Android twin of `IOS_NATIVE_PREPARE`: generate `android/` when a CNG checkout has none. */
16
31
  export declare const ANDROID_NATIVE_PREPARE = "{ [ -f android/gradlew ] || bunx expo prebuild --platform android --no-install; }";
17
32
  /**
@@ -3,7 +3,7 @@ import type { z } from "zod";
3
3
  import type { Platform } from "../types";
4
4
  import { type BuildConfiguration } from "./builds.defaults";
5
5
  import type { projectConfigSchema, wardenConfigSchema } from "./config.schema";
6
- import type { BuildKind, ProjectKinds } from "./kinds";
6
+ import type { BuildKind, BuildTarget, ProjectKinds } from "./kinds";
7
7
  import { type AppFramework } from "./native-ids";
8
8
  /** The preferred config file, named in hints. */
9
9
  export declare const CONFIG_FILE = "warden.config.ts";
@@ -45,6 +45,10 @@ export type Project = {
45
45
  kinds?: ProjectKinds;
46
46
  /** set by `projectForKind`: the kind this project is resolved as; undefined = the kind-less flow */
47
47
  kind?: BuildKind;
48
+ /** set by `projectForKind` for a build signed for a physical iPhone; undefined = a simulator / emulator build */
49
+ target?: BuildTarget;
50
+ /** `projects[].ios.device.bundleIdentifier`: replaces the bundle id of builds for a physical iPhone (and the app's id there) */
51
+ iosDeviceBundleId?: string;
48
52
  /** set by `projectForKind`: env of the local build (`kinds.<kind>.env`) */
49
53
  buildEnv?: Record<string, string>;
50
54
  cacheDirs: string[];
@@ -114,6 +114,11 @@ export declare const projectConfigSchema: z.ZodObject<{
114
114
  jsInputs: z.ZodOptional<z.ZodArray<z.ZodString>>;
115
115
  }, z.core.$strict>>;
116
116
  }, z.core.$strict>>;
117
+ ios: z.ZodOptional<z.ZodObject<{
118
+ device: z.ZodOptional<z.ZodObject<{
119
+ bundleIdentifier: z.ZodOptional<z.ZodString>;
120
+ }, z.core.$strict>>;
121
+ }, z.core.$strict>>;
117
122
  cacheDirs: z.ZodOptional<z.ZodArray<z.ZodString>>;
118
123
  }, z.core.$strict>;
119
124
  export declare const wardenConfigSchema: z.ZodObject<{
@@ -202,6 +207,11 @@ export declare const wardenConfigSchema: z.ZodObject<{
202
207
  jsInputs: z.ZodOptional<z.ZodArray<z.ZodString>>;
203
208
  }, z.core.$strict>>;
204
209
  }, z.core.$strict>>;
210
+ ios: z.ZodOptional<z.ZodObject<{
211
+ device: z.ZodOptional<z.ZodObject<{
212
+ bundleIdentifier: z.ZodOptional<z.ZodString>;
213
+ }, z.core.$strict>>;
214
+ }, z.core.$strict>>;
205
215
  cacheDirs: z.ZodOptional<z.ZodArray<z.ZodString>>;
206
216
  }, z.core.$strict>>>;
207
217
  batches: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
@@ -237,6 +247,7 @@ export declare const wardenConfigSchema: z.ZodObject<{
237
247
  except: z.ZodOptional<z.ZodArray<z.ZodString>>;
238
248
  keep: z.ZodOptional<z.ZodArray<z.ZodString>>;
239
249
  }, z.core.$strict>]>>;
250
+ biometrics: z.ZodOptional<z.ZodBoolean>;
240
251
  retry: z.ZodOptional<z.ZodNumber>;
241
252
  passes: z.ZodOptional<z.ZodNumber>;
242
253
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -275,6 +286,9 @@ export declare const wardenConfigSchema: z.ZodObject<{
275
286
  count: z.ZodDefault<z.ZodNumber>;
276
287
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
277
288
  default: z.ZodDefault<z.ZodBoolean>;
289
+ physical: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
290
+ ids: z.ZodArray<z.ZodString>;
291
+ }, z.core.$strict>]>>;
278
292
  }, z.core.$strict>>>;
279
293
  metro: z.ZodOptional<z.ZodObject<{
280
294
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -291,6 +305,9 @@ export declare const wardenConfigSchema: z.ZodObject<{
291
305
  ios: "ios";
292
306
  android: "android";
293
307
  }>>;
308
+ physical: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
309
+ ids: z.ZodArray<z.ZodString>;
310
+ }, z.core.$strict>]>>;
294
311
  base: z.ZodDefault<z.ZodString>;
295
312
  maxDepth: z.ZodOptional<z.ZodNumber>;
296
313
  runAll: z.ZodDefault<z.ZodArray<z.ZodString>>;
@@ -335,6 +352,7 @@ export declare const wardenConfigSchema: z.ZodObject<{
335
352
  except: z.ZodOptional<z.ZodArray<z.ZodString>>;
336
353
  keep: z.ZodOptional<z.ZodArray<z.ZodString>>;
337
354
  }, z.core.$strict>]>>;
355
+ biometrics: z.ZodOptional<z.ZodBoolean>;
338
356
  warmRunners: z.ZodOptional<z.ZodUndefined>;
339
357
  warmDrivers: z.ZodOptional<z.ZodBoolean>;
340
358
  headless: z.ZodOptional<z.ZodBoolean>;
@@ -347,6 +365,84 @@ export declare const wardenConfigSchema: z.ZodObject<{
347
365
  peakMemoryMb: z.ZodOptional<z.ZodNumber>;
348
366
  }, z.core.$strict>>;
349
367
  }, z.core.$strict>>;
368
+ conditions: z.ZodOptional<z.ZodObject<{
369
+ network: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
370
+ edge: "edge";
371
+ "3g": "3g";
372
+ "4g": "4g";
373
+ lte: "lte";
374
+ wifi: "wifi";
375
+ slow: "slow";
376
+ lossy: "lossy";
377
+ online: "online";
378
+ offline: "offline";
379
+ }>, z.ZodObject<{
380
+ latencyMs: z.ZodOptional<z.ZodNumber>;
381
+ jitterMs: z.ZodOptional<z.ZodNumber>;
382
+ downKbps: z.ZodOptional<z.ZodNumber>;
383
+ upKbps: z.ZodOptional<z.ZodNumber>;
384
+ lossPct: z.ZodOptional<z.ZodNumber>;
385
+ }, z.core.$strict>]>>;
386
+ location: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
387
+ "city-run": "city-run";
388
+ "city-bike": "city-bike";
389
+ freeway: "freeway";
390
+ }>, z.ZodObject<{
391
+ lat: z.ZodNumber;
392
+ lon: z.ZodNumber;
393
+ altM: z.ZodOptional<z.ZodNumber>;
394
+ }, z.core.$strict>]>>;
395
+ clock: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
396
+ at: z.ZodString;
397
+ frozen: z.ZodOptional<z.ZodBoolean>;
398
+ }, z.core.$strict>, z.ZodObject<{
399
+ offset: z.ZodString;
400
+ }, z.core.$strict>]>>;
401
+ permissions: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
402
+ location: "location";
403
+ locationAlways: "locationAlways";
404
+ camera: "camera";
405
+ photos: "photos";
406
+ photosAdd: "photosAdd";
407
+ contacts: "contacts";
408
+ contactsLimited: "contactsLimited";
409
+ notifications: "notifications";
410
+ microphone: "microphone";
411
+ calendar: "calendar";
412
+ reminders: "reminders";
413
+ motion: "motion";
414
+ mediaLibrary: "mediaLibrary";
415
+ siri: "siri";
416
+ }> & z.core.$partial, z.ZodEnum<{
417
+ granted: "granted";
418
+ denied: "denied";
419
+ unset: "unset";
420
+ }>>>;
421
+ locale: z.ZodOptional<z.ZodString>;
422
+ timezone: z.ZodOptional<z.ZodString>;
423
+ a11y: z.ZodOptional<z.ZodObject<{
424
+ textSize: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
425
+ "extra-small": "extra-small";
426
+ small: "small";
427
+ medium: "medium";
428
+ large: "large";
429
+ "extra-large": "extra-large";
430
+ "extra-extra-large": "extra-extra-large";
431
+ "extra-extra-extra-large": "extra-extra-extra-large";
432
+ "accessibility-medium": "accessibility-medium";
433
+ "accessibility-large": "accessibility-large";
434
+ "accessibility-extra-large": "accessibility-extra-large";
435
+ "accessibility-extra-extra-large": "accessibility-extra-extra-large";
436
+ "accessibility-extra-extra-extra-large": "accessibility-extra-extra-extra-large";
437
+ }>, z.ZodNumber]>>;
438
+ boldText: z.ZodOptional<z.ZodBoolean>;
439
+ contrast: z.ZodOptional<z.ZodEnum<{
440
+ increased: "increased";
441
+ normal: "normal";
442
+ }>>;
443
+ reduceMotion: z.ZodOptional<z.ZodBoolean>;
444
+ }, z.core.$strict>>;
445
+ }, z.core.$strict>>;
350
446
  required: z.ZodDefault<z.ZodBoolean>;
351
447
  specs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
352
448
  entries: z.ZodDefault<z.ZodArray<z.ZodString>>;
@@ -364,6 +460,7 @@ export declare const wardenConfigSchema: z.ZodObject<{
364
460
  except: z.ZodOptional<z.ZodArray<z.ZodString>>;
365
461
  keep: z.ZodOptional<z.ZodArray<z.ZodString>>;
366
462
  }, z.core.$strict>]>>;
463
+ biometrics: z.ZodOptional<z.ZodBoolean>;
367
464
  perf: z.ZodOptional<z.ZodObject<{
368
465
  budgets: z.ZodOptional<z.ZodObject<{
369
466
  startupColdMs: z.ZodOptional<z.ZodNumber>;
@@ -373,9 +470,94 @@ export declare const wardenConfigSchema: z.ZodObject<{
373
470
  peakMemoryMb: z.ZodOptional<z.ZodNumber>;
374
471
  }, z.core.$strict>>;
375
472
  }, z.core.$strict>>;
473
+ conditions: z.ZodOptional<z.ZodObject<{
474
+ network: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
475
+ edge: "edge";
476
+ "3g": "3g";
477
+ "4g": "4g";
478
+ lte: "lte";
479
+ wifi: "wifi";
480
+ slow: "slow";
481
+ lossy: "lossy";
482
+ online: "online";
483
+ offline: "offline";
484
+ }>, z.ZodObject<{
485
+ latencyMs: z.ZodOptional<z.ZodNumber>;
486
+ jitterMs: z.ZodOptional<z.ZodNumber>;
487
+ downKbps: z.ZodOptional<z.ZodNumber>;
488
+ upKbps: z.ZodOptional<z.ZodNumber>;
489
+ lossPct: z.ZodOptional<z.ZodNumber>;
490
+ }, z.core.$strict>]>>;
491
+ location: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
492
+ "city-run": "city-run";
493
+ "city-bike": "city-bike";
494
+ freeway: "freeway";
495
+ }>, z.ZodObject<{
496
+ lat: z.ZodNumber;
497
+ lon: z.ZodNumber;
498
+ altM: z.ZodOptional<z.ZodNumber>;
499
+ }, z.core.$strict>]>>;
500
+ clock: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
501
+ at: z.ZodString;
502
+ frozen: z.ZodOptional<z.ZodBoolean>;
503
+ }, z.core.$strict>, z.ZodObject<{
504
+ offset: z.ZodString;
505
+ }, z.core.$strict>]>>;
506
+ permissions: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
507
+ location: "location";
508
+ locationAlways: "locationAlways";
509
+ camera: "camera";
510
+ photos: "photos";
511
+ photosAdd: "photosAdd";
512
+ contacts: "contacts";
513
+ contactsLimited: "contactsLimited";
514
+ notifications: "notifications";
515
+ microphone: "microphone";
516
+ calendar: "calendar";
517
+ reminders: "reminders";
518
+ motion: "motion";
519
+ mediaLibrary: "mediaLibrary";
520
+ siri: "siri";
521
+ }> & z.core.$partial, z.ZodEnum<{
522
+ granted: "granted";
523
+ denied: "denied";
524
+ unset: "unset";
525
+ }>>>;
526
+ locale: z.ZodOptional<z.ZodString>;
527
+ timezone: z.ZodOptional<z.ZodString>;
528
+ a11y: z.ZodOptional<z.ZodObject<{
529
+ textSize: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
530
+ "extra-small": "extra-small";
531
+ small: "small";
532
+ medium: "medium";
533
+ large: "large";
534
+ "extra-large": "extra-large";
535
+ "extra-extra-large": "extra-extra-large";
536
+ "extra-extra-extra-large": "extra-extra-extra-large";
537
+ "accessibility-medium": "accessibility-medium";
538
+ "accessibility-large": "accessibility-large";
539
+ "accessibility-extra-large": "accessibility-extra-large";
540
+ "accessibility-extra-extra-large": "accessibility-extra-extra-large";
541
+ "accessibility-extra-extra-extra-large": "accessibility-extra-extra-extra-large";
542
+ }>, z.ZodNumber]>>;
543
+ boldText: z.ZodOptional<z.ZodBoolean>;
544
+ contrast: z.ZodOptional<z.ZodEnum<{
545
+ increased: "increased";
546
+ normal: "normal";
547
+ }>>;
548
+ reduceMotion: z.ZodOptional<z.ZodBoolean>;
549
+ }, z.core.$strict>>;
550
+ }, z.core.$strict>>;
376
551
  android: z.ZodOptional<z.ZodObject<{
377
552
  snapshot: z.ZodOptional<z.ZodBoolean>;
378
553
  }, z.core.$strict>>;
554
+ physical: z.ZodOptional<z.ZodObject<{
555
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
556
+ }, z.core.$strict>>;
557
+ ios: z.ZodOptional<z.ZodObject<{
558
+ teamId: z.ZodOptional<z.ZodString>;
559
+ runnerBundleId: z.ZodOptional<z.ZodString>;
560
+ }, z.core.$strict>>;
379
561
  }, z.core.$strict>;
380
562
  /** The slice of an Expo `app.json` warden reads (name, bundle ids). */
381
563
  export declare const appJsonSchema: z.ZodObject<{
@@ -209,6 +209,8 @@ export interface WardenProject {
209
209
  * `--kind`. Kinds sit on top of {@link WardenProject.variants}: both keep working, but a build is one or the other.
210
210
  */
211
211
  kinds?: WardenKinds | undefined;
212
+ /** iOS-only project settings. */
213
+ ios?: WardenProjectIos | undefined;
212
214
  /** Extra (legacy) cache roots laid out as `<dir>/<hash>/*.app|*.apk`, imported on demand. `~` expands to `$HOME`. */
213
215
  cacheDirs?: string[] | undefined;
214
216
  }
@@ -318,6 +320,12 @@ export interface WardenBatchPreset {
318
320
  except?: string[] | undefined;
319
321
  keep?: string[] | undefined;
320
322
  } | undefined;
323
+ /**
324
+ * Devices of this run have a fingerprint (Android) / Face ID (iOS) enrolled before any app install. Enrolled
325
+ * devices are a separate pool and golden from plain ones (profile `<profile>+bio`). Overrides the top-level
326
+ * `biometrics`. Default false.
327
+ */
328
+ biometrics?: boolean | undefined;
321
329
  /** Per-job log dir. */
322
330
  logs?: string | undefined;
323
331
  /**
@@ -412,6 +420,49 @@ export interface WardenPerfConfig {
412
420
  /** Budgets; a metric the report has no number for (its capture did not run) cannot breach. */
413
421
  budgets?: WardenPerfBudgets | undefined;
414
422
  }
423
+ /** `conditions.network` as a custom shape: the fields of a `custom` network condition. */
424
+ export interface WardenCustomNetwork {
425
+ /** Added round-trip time, ms. */
426
+ latencyMs?: number | undefined;
427
+ /** Plus or minus spread on the latency, ms. */
428
+ jitterMs?: number | undefined;
429
+ /** Download rate, kilobits per second (0 = unlimited). */
430
+ downKbps?: number | undefined;
431
+ /** Upload rate, kilobits per second (0 = unlimited). */
432
+ upKbps?: number | undefined;
433
+ /** Share of packets lost, 0-100. */
434
+ lossPct?: number | undefined;
435
+ }
436
+ /**
437
+ * `conditions` (top level, or `e2e.<suite>.conditions`): the device state every spec of the suite starts from.
438
+ * `network`, `location` and `clock` are applied before the app launches and put back after each spec;
439
+ * `permissions`, `locale`, `timezone` and `a11y` are accepted but not applied yet (`warden e2e` says so once).
440
+ */
441
+ export interface WardenConditionsConfig {
442
+ /** `online`, `offline`, a preset (`edge`, `3g`, `4g`, `lte`, `wifi`, `slow`, `lossy`) or custom shaping. iOS launches the app with the network dylib so specs can change it later. */
443
+ network?: "online" | "offline" | "edge" | "3g" | "4g" | "lte" | "wifi" | "slow" | "lossy" | WardenCustomNetwork | undefined;
444
+ /** A point, or one of the bundled scenarios (`city-run`, `city-bike`, `freeway`). */
445
+ location?: "city-run" | "city-bike" | "freeway" | {
446
+ lat: number;
447
+ lon: number;
448
+ altM?: number | undefined;
449
+ } | undefined;
450
+ /** An ISO instant the clock starts at (and keeps running from), `{ at, frozen }`, or `{ offset }` ("2d") from now. */
451
+ clock?: string | {
452
+ at: string;
453
+ frozen?: boolean | undefined;
454
+ } | {
455
+ offset: string;
456
+ } | undefined;
457
+ /** Not applied yet. */
458
+ permissions?: Record<string, "granted" | "denied" | "unset"> | undefined;
459
+ /** Not applied yet. */
460
+ locale?: string | undefined;
461
+ /** Not applied yet. */
462
+ timezone?: string | undefined;
463
+ /** Not applied yet. */
464
+ a11y?: Record<string, unknown> | undefined;
465
+ }
415
466
  /** `e2e.<suite>.spec`: how `warden e2e` runs the `*.e2e.ts` specs (`bun test` with `@delacour/warden-e2e`). */
416
467
  export interface WardenE2eSpec {
417
468
  /** The app under test. Default: the suite project's `bundleId` for the platform. */
@@ -468,6 +519,8 @@ export interface WardenE2eSuite {
468
519
  project?: string | undefined;
469
520
  /** Perf budgets for this suite; each key replaces the top-level `perf.budgets` one. */
470
521
  perf?: WardenPerfConfig | undefined;
522
+ /** Device conditions every spec of this suite starts from; each area replaces the top-level one. */
523
+ conditions?: WardenConditionsConfig | undefined;
471
524
  /** Directory of specs: `*.e2e.ts(x)` specs whose other `.ts` files are helpers (searched recursively; dot dirs, `node_modules` and `__baselines__` skipped). */
472
525
  specsDir: string;
473
526
  /** How the specs run: the app under test, its launch arguments and the timeouts. */
@@ -626,6 +679,12 @@ export interface WardenE2eSuite {
626
679
  except?: string[] | undefined;
627
680
  keep?: string[] | undefined;
628
681
  } | undefined;
682
+ /**
683
+ * Devices of this run have a fingerprint (Android) / Face ID (iOS) enrolled before any app install. Enrolled
684
+ * devices are a separate pool and golden from plain ones (profile `<profile>+bio`). Overrides the top-level
685
+ * `biometrics`. Default false.
686
+ */
687
+ biometrics?: boolean | undefined;
629
688
  /** Removed: renamed `warmDrivers`. */
630
689
  warmRunners?: undefined;
631
690
  /**
@@ -683,10 +742,55 @@ export interface WardenConfig {
683
742
  except?: string[] | undefined;
684
743
  keep?: string[] | undefined;
685
744
  } | undefined;
745
+ /**
746
+ * Devices of this run have a fingerprint (Android) / Face ID (iOS) enrolled before any app install. Enrolled
747
+ * devices are a separate pool and golden from plain ones (profile `<profile>+bio`). `e2e` suites and `batches` presets
748
+ * override it. Default false.
749
+ */
750
+ biometrics?: boolean | undefined;
686
751
  /** Perf budgets every `e2e` suite starts from (a suite's own `perf.budgets` replace them per key). */
687
752
  perf?: WardenPerfConfig | undefined;
753
+ /** Device conditions every `e2e` suite starts from (a suite's own `conditions` replace them per area). */
754
+ conditions?: WardenConditionsConfig | undefined;
688
755
  /** Android emulator settings. */
689
756
  android?: WardenAndroidSettings | undefined;
757
+ /** Physical iPhone settings. */
758
+ ios?: WardenIosSettings | undefined;
759
+ /** Physical phone and tablet settings. */
760
+ physical?: WardenPhysicalSettings | undefined;
761
+ }
762
+ /** Physical phone and tablet settings (`physical`). */
763
+ export interface WardenPhysicalSettings {
764
+ /**
765
+ * Allowlist for `--physical` claims that name no device: only these adb serials / CoreDevice UDIDs are picked.
766
+ * `WARDEN_PHYSICAL_IDS` (comma-separated) wins over it. Naming a device with `--serial` / `--udid` works for
767
+ * any device, listed or not.
768
+ *
769
+ * @example ["00008140-000A0B0C0D0E0F10", "R5CT123ABC"]
770
+ */
771
+ allow?: string[] | undefined;
772
+ }
773
+ /** iOS settings of one project (`projects[].ios`). */
774
+ export interface WardenProjectIos {
775
+ /** Builds for a physical iPhone (`--physical`, `--udid <iPhone>`). */
776
+ device?: {
777
+ bundleIdentifier?: string | undefined;
778
+ } | undefined;
779
+ }
780
+ /** Physical iPhone settings (`ios`). */
781
+ export interface WardenIosSettings {
782
+ /**
783
+ * Apple developer team id (10 characters, e.g. `LN69P7N673`) that signs warden's on-device runner. Without it
784
+ * (and without `WARDEN_IOS_TEAM_ID`, which wins) warden uses the team of the one `Apple Development` identity
785
+ * in your keychain and fails `ios_team_ambiguous` when there are several teams.
786
+ */
787
+ teamId?: string | undefined;
788
+ /**
789
+ * Bundle id of the runner app (its UI-test bundle is `<id>.uitests`).
790
+ *
791
+ * @default "nz.co.delacour.warden.runner.<team id, lower case>"
792
+ */
793
+ runnerBundleId?: string | undefined;
690
794
  }
691
795
  /** Android emulator settings (`android`). */
692
796
  export interface WardenAndroidSettings {