@delacour/warden-e2e 0.7.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.
Files changed (93) hide show
  1. package/{chunk-empqr9n0.mjs → chunk-vs5npy59.mjs} +2010 -169
  2. package/index.mjs +214 -13
  3. package/package.json +2 -2
  4. package/preload.mjs +3002 -798
  5. package/types/core/src/a11y/a11y.config.d.ts +47 -0
  6. package/types/core/src/affected/affected.schema.d.ts +49 -1
  7. package/types/core/src/android-keyguard.d.ts +2 -0
  8. package/types/core/src/batch/preset.schema.d.ts +12 -1
  9. package/types/core/src/builds/app-option.schema.d.ts +1 -1
  10. package/types/core/src/builds/config.schema.d.ts +93 -2
  11. package/types/core/src/builds/define-config.d.ts +55 -0
  12. package/types/core/src/camera-mode.d.ts +17 -0
  13. package/types/core/src/camera-placeholder.d.ts +9 -0
  14. package/types/core/src/camera-profile.d.ts +12 -0
  15. package/types/core/src/claim-errors.d.ts +34 -0
  16. package/types/core/src/conditions/a11y-keys.d.ts +45 -0
  17. package/types/core/src/conditions/camera-media.d.ts +30 -0
  18. package/types/core/src/conditions/conditions.config.d.ts +24 -0
  19. package/types/core/src/conditions/conditions.types.d.ts +30 -0
  20. package/types/core/src/conditions/inject-state.d.ts +1 -1
  21. package/types/core/src/ios-runner/build.d.ts +28 -0
  22. package/types/core/src/ios-runner/cache.d.ts +44 -0
  23. package/types/core/src/ios-runner/pack.d.ts +17 -0
  24. package/types/core/src/ios-runner/signing.d.ts +40 -0
  25. package/types/core/src/ios-runner/sim-build.d.ts +36 -0
  26. package/types/core/src/ios-runner/stage.d.ts +26 -0
  27. package/types/core/src/lease-events.d.ts +126 -0
  28. package/types/core/src/ownership.d.ts +44 -0
  29. package/types/core/src/providers/android.d.ts +10 -1
  30. package/types/core/src/providers/provider.types.d.ts +9 -0
  31. package/types/core/src/queue.d.ts +43 -0
  32. package/types/core/src/store.d.ts +61 -5
  33. package/types/core/src/types.d.ts +10 -0
  34. package/types/core/src/xcode.d.ts +22 -0
  35. package/types/e2e/src/a11y/a11y-target.d.ts +23 -0
  36. package/types/e2e/src/a11y/a11y.types.d.ts +81 -0
  37. package/types/e2e/src/a11y/announcements.d.ts +24 -0
  38. package/types/e2e/src/a11y/audit.d.ts +22 -0
  39. package/types/e2e/src/a11y/native/atf.d.ts +51 -0
  40. package/types/e2e/src/a11y/native/xcuitest.d.ts +60 -0
  41. package/types/e2e/src/a11y/order.d.ts +5 -0
  42. package/types/e2e/src/a11y/rules/duplicate-name.d.ts +6 -0
  43. package/types/e2e/src/a11y/rules/hidden-focusable.d.ts +3 -0
  44. package/types/e2e/src/a11y/rules/image-no-name.d.ts +6 -0
  45. package/types/e2e/src/a11y/rules/label-in-name.d.ts +7 -0
  46. package/types/e2e/src/a11y/rules/missing-name.d.ts +3 -0
  47. package/types/e2e/src/a11y/rules/role-in-name.d.ts +3 -0
  48. package/types/e2e/src/a11y/rules/rule.context.d.ts +22 -0
  49. package/types/e2e/src/a11y/rules/target-size.d.ts +21 -0
  50. package/types/e2e/src/a11y/rules/text-clipped.d.ts +9 -0
  51. package/types/e2e/src/a11y/speech.d.ts +26 -0
  52. package/types/e2e/src/a11y/talkback-log.d.ts +13 -0
  53. package/types/e2e/src/app.d.ts +0 -1
  54. package/types/e2e/src/conditions/condition-events.d.ts +6 -1
  55. package/types/e2e/src/conditions/device-conditions.d.ts +30 -2
  56. package/types/e2e/src/device-a11y.d.ts +97 -0
  57. package/types/e2e/src/device.d.ts +11 -2
  58. package/types/e2e/src/driver/a11y-events.d.ts +30 -0
  59. package/types/e2e/src/driver/a11y-read.d.ts +12 -0
  60. package/types/e2e/src/driver/android/android-animations.d.ts +7 -0
  61. package/types/e2e/src/driver/android/android-argv.d.ts +2 -0
  62. package/types/e2e/src/driver/android/android-camera-host.d.ts +23 -0
  63. package/types/e2e/src/driver/android/android-camera.d.ts +28 -0
  64. package/types/e2e/src/driver/android/android-driver.d.ts +5 -0
  65. package/types/e2e/src/driver/android/android-screen-reader.d.ts +23 -0
  66. package/types/e2e/src/driver/android/android-settings.d.ts +9 -2
  67. package/types/e2e/src/driver/android/android-spoken.d.ts +18 -0
  68. package/types/e2e/src/driver/android/android-talkback.d.ts +57 -0
  69. package/types/e2e/src/driver/android/atf-device.d.ts +23 -0
  70. package/types/e2e/src/driver/android/atf-dex.generated.d.ts +7 -0
  71. package/types/e2e/src/driver/android/uiad-dex.generated.d.ts +5 -5
  72. package/types/e2e/src/driver/android/uiad-ops.d.ts +27 -1
  73. package/types/e2e/src/driver/android/uiad-protocol.d.ts +8 -0
  74. package/types/e2e/src/driver/android/uiad-screen-reader.d.ts +33 -0
  75. package/types/e2e/src/driver/driver.types.d.ts +71 -5
  76. package/types/e2e/src/driver/element-actions.d.ts +16 -0
  77. package/types/e2e/src/driver/ios/inject.d.ts +16 -2
  78. package/types/e2e/src/driver/ios/ios-a11y.d.ts +73 -0
  79. package/types/e2e/src/driver/ios/ios-audit.d.ts +36 -0
  80. package/types/e2e/src/driver/ios/ios-driver.d.ts +21 -1
  81. package/types/e2e/src/driver/ios/ios-network.d.ts +7 -2
  82. package/types/e2e/src/driver/ios/sim-runner.d.ts +41 -0
  83. package/types/e2e/src/driver/ios/simd-transport.d.ts +11 -2
  84. package/types/e2e/src/driver/native-audit.d.ts +26 -0
  85. package/types/e2e/src/driver/physical-conditions.d.ts +1 -1
  86. package/types/e2e/src/driver/screen-reader.d.ts +26 -0
  87. package/types/e2e/src/env.d.ts +16 -1
  88. package/types/e2e/src/expect/a11y-matchers.d.ts +33 -0
  89. package/types/e2e/src/expect/expect.d.ts +7 -2
  90. package/types/e2e/src/expect/matchers.d.ts +14 -0
  91. package/types/e2e/src/index.d.ts +5 -1
  92. package/types/e2e/src/runner/callsite.d.ts +3 -1
  93. package/types/e2e/src/screen/render.d.ts +8 -0
@@ -0,0 +1,47 @@
1
+ import { type Result } from "../../../types/src/result";
2
+ import { z } from "zod";
3
+ /** Every rule id an audit can report (`native` = XCUITest / ATF findings). Keep in step with `A11yRuleId` in `@delacour/warden-e2e`. */
4
+ export declare const A11Y_RULE_IDS: readonly ["missing-name", "image-no-name", "target-size", "target-size-platform", "duplicate-name", "role-in-name", "label-in-name", "hidden-focusable", "text-clipped", "native"];
5
+ /**
6
+ * `a11y` (top level, or per `e2e.<suite>`): how `device.a11yAudit()` / `toPassA11yAudit()` judge a screen.
7
+ * `ignore` drops a rule (everywhere, or only on the element with that `identifier`); `minSeverity` is the lowest
8
+ * severity that fails (default `error`); `rules` limits the audit to those rules.
9
+ */
10
+ export declare const a11yAuditConfigSchema: z.ZodObject<{
11
+ ignore: z.ZodOptional<z.ZodArray<z.ZodObject<{
12
+ rule: z.ZodEnum<{
13
+ "missing-name": "missing-name";
14
+ "image-no-name": "image-no-name";
15
+ "target-size": "target-size";
16
+ "target-size-platform": "target-size-platform";
17
+ "duplicate-name": "duplicate-name";
18
+ "role-in-name": "role-in-name";
19
+ "label-in-name": "label-in-name";
20
+ "hidden-focusable": "hidden-focusable";
21
+ "text-clipped": "text-clipped";
22
+ native: "native";
23
+ }>;
24
+ identifier: z.ZodOptional<z.ZodString>;
25
+ }, z.core.$strict>>>;
26
+ minSeverity: z.ZodOptional<z.ZodEnum<{
27
+ error: "error";
28
+ warning: "warning";
29
+ }>>;
30
+ rules: z.ZodOptional<z.ZodArray<z.ZodEnum<{
31
+ "missing-name": "missing-name";
32
+ "image-no-name": "image-no-name";
33
+ "target-size": "target-size";
34
+ "target-size-platform": "target-size-platform";
35
+ "duplicate-name": "duplicate-name";
36
+ "role-in-name": "role-in-name";
37
+ "label-in-name": "label-in-name";
38
+ "hidden-focusable": "hidden-focusable";
39
+ "text-clipped": "text-clipped";
40
+ native: "native";
41
+ }>>>;
42
+ }, z.core.$strict>;
43
+ export type A11yAuditConfig = z.infer<typeof a11yAuditConfigSchema>;
44
+ /** The suite's keys over the top-level ones (a suite's `ignore` / `rules` replace, not extend); undefined when neither is set. */
45
+ export declare function mergeA11yAuditConfig(top: A11yAuditConfig | undefined, suite: A11yAuditConfig | undefined): A11yAuditConfig | undefined;
46
+ /** `WARDEN_A11Y_AUDIT`: the JSON `warden e2e` writes. */
47
+ export declare function parseA11yAuditEnv(raw: string): Result<A11yAuditConfig>;
@@ -151,8 +151,8 @@ export declare const e2eSuiteSchema: z.ZodObject<{
151
151
  variant: z.ZodOptional<z.ZodString>;
152
152
  kind: z.ZodOptional<z.ZodEnum<{
153
153
  release: "release";
154
- dev: "dev";
155
154
  simulator: "simulator";
155
+ dev: "dev";
156
156
  }>>;
157
157
  }, z.core.$strict>]>>;
158
158
  ports: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -166,6 +166,11 @@ export declare const e2eSuiteSchema: z.ZodObject<{
166
166
  keep: z.ZodOptional<z.ZodArray<z.ZodString>>;
167
167
  }, z.core.$strict>]>>;
168
168
  biometrics: z.ZodOptional<z.ZodBoolean>;
169
+ reclaim: z.ZodOptional<z.ZodEnum<{
170
+ none: "none";
171
+ uninstall: "uninstall";
172
+ erase: "erase";
173
+ }>>;
169
174
  warmRunners: z.ZodOptional<z.ZodUndefined>;
170
175
  warmDrivers: z.ZodOptional<z.ZodBoolean>;
171
176
  headless: z.ZodOptional<z.ZodBoolean>;
@@ -256,6 +261,49 @@ export declare const e2eSuiteSchema: z.ZodObject<{
256
261
  reduceMotion: z.ZodOptional<z.ZodBoolean>;
257
262
  }, z.core.$strict>>;
258
263
  }, z.core.$strict>>;
264
+ a11y: z.ZodOptional<z.ZodObject<{
265
+ ignore: z.ZodOptional<z.ZodArray<z.ZodObject<{
266
+ rule: z.ZodEnum<{
267
+ "missing-name": "missing-name";
268
+ "image-no-name": "image-no-name";
269
+ "target-size": "target-size";
270
+ "target-size-platform": "target-size-platform";
271
+ "duplicate-name": "duplicate-name";
272
+ "role-in-name": "role-in-name";
273
+ "label-in-name": "label-in-name";
274
+ "hidden-focusable": "hidden-focusable";
275
+ "text-clipped": "text-clipped";
276
+ native: "native";
277
+ }>;
278
+ identifier: z.ZodOptional<z.ZodString>;
279
+ }, z.core.$strict>>>;
280
+ minSeverity: z.ZodOptional<z.ZodEnum<{
281
+ error: "error";
282
+ warning: "warning";
283
+ }>>;
284
+ rules: z.ZodOptional<z.ZodArray<z.ZodEnum<{
285
+ "missing-name": "missing-name";
286
+ "image-no-name": "image-no-name";
287
+ "target-size": "target-size";
288
+ "target-size-platform": "target-size-platform";
289
+ "duplicate-name": "duplicate-name";
290
+ "role-in-name": "role-in-name";
291
+ "label-in-name": "label-in-name";
292
+ "hidden-focusable": "hidden-focusable";
293
+ "text-clipped": "text-clipped";
294
+ native: "native";
295
+ }>>>;
296
+ }, z.core.$strict>>;
297
+ camera: z.ZodOptional<z.ZodObject<{
298
+ back: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
299
+ path: z.ZodString;
300
+ loop: z.ZodOptional<z.ZodBoolean>;
301
+ }, z.core.$strict>]>>;
302
+ front: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
303
+ path: z.ZodString;
304
+ loop: z.ZodOptional<z.ZodBoolean>;
305
+ }, z.core.$strict>]>>;
306
+ }, z.core.$strict>>;
259
307
  required: z.ZodDefault<z.ZodBoolean>;
260
308
  specs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
261
309
  entries: z.ZodDefault<z.ZodArray<z.ZodString>>;
@@ -21,6 +21,8 @@ export type KeyguardDeps = {
21
21
  adb: string;
22
22
  now?: () => number;
23
23
  };
24
+ /** Whether `dumpsys window` positively reports the keyguard up; an unreadable dump is not a lock screen. */
25
+ export declare function keyguardIsShowing(deps: KeyguardDeps, serial: string): Promise<boolean>;
24
26
  /**
25
27
  * Get past the lock screen (idempotent: nothing is typed when it is already gone) and keep the device awake.
26
28
  * Up to three unlock attempts; before the last one SystemUI is restarted, which recovers a restored snapshot
@@ -4,6 +4,12 @@ export declare const slimConfigSchema: z.ZodUnion<readonly [z.ZodBoolean, z.ZodO
4
4
  except: z.ZodOptional<z.ZodArray<z.ZodString>>;
5
5
  keep: z.ZodOptional<z.ZodArray<z.ZodString>>;
6
6
  }, z.core.$strict>]>;
7
+ /** `reclaim`: what happens to a device's state when its lease ends (`ReclaimMode`). */
8
+ export declare const reclaimSchema: z.ZodEnum<{
9
+ none: "none";
10
+ uninstall: "uninstall";
11
+ erase: "erase";
12
+ }>;
7
13
  export declare const duration: z.ZodString;
8
14
  export declare const portSpec: z.ZodString;
9
15
  /** `batches.<name>` in `warden.config.ts`: a saved `warden batch` invocation. */
@@ -31,8 +37,8 @@ export declare const batchPresetSchema: z.ZodObject<{
31
37
  variant: z.ZodOptional<z.ZodString>;
32
38
  kind: z.ZodOptional<z.ZodEnum<{
33
39
  release: "release";
34
- dev: "dev";
35
40
  simulator: "simulator";
41
+ dev: "dev";
36
42
  }>>;
37
43
  }, z.core.$strict>]>>;
38
44
  headless: z.ZodOptional<z.ZodBoolean>;
@@ -41,6 +47,11 @@ export declare const batchPresetSchema: z.ZodObject<{
41
47
  keep: z.ZodOptional<z.ZodArray<z.ZodString>>;
42
48
  }, z.core.$strict>]>>;
43
49
  biometrics: z.ZodOptional<z.ZodBoolean>;
50
+ reclaim: z.ZodOptional<z.ZodEnum<{
51
+ none: "none";
52
+ uninstall: "uninstall";
53
+ erase: "erase";
54
+ }>>;
44
55
  retry: z.ZodOptional<z.ZodNumber>;
45
56
  passes: z.ZodOptional<z.ZodNumber>;
46
57
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -29,8 +29,8 @@ export declare const appOptionSchema: z.ZodUnion<readonly [z.ZodBoolean, z.ZodOb
29
29
  variant: z.ZodOptional<z.ZodString>;
30
30
  kind: z.ZodOptional<z.ZodEnum<{
31
31
  release: "release";
32
- dev: "dev";
33
32
  simulator: "simulator";
33
+ dev: "dev";
34
34
  }>>;
35
35
  }, z.core.$strict>]>;
36
36
  export type AppOption = z.infer<typeof appOptionSchema>;
@@ -238,8 +238,8 @@ export declare const wardenConfigSchema: z.ZodObject<{
238
238
  variant: z.ZodOptional<z.ZodString>;
239
239
  kind: z.ZodOptional<z.ZodEnum<{
240
240
  release: "release";
241
- dev: "dev";
242
241
  simulator: "simulator";
242
+ dev: "dev";
243
243
  }>>;
244
244
  }, z.core.$strict>]>>;
245
245
  headless: z.ZodOptional<z.ZodBoolean>;
@@ -248,6 +248,11 @@ export declare const wardenConfigSchema: z.ZodObject<{
248
248
  keep: z.ZodOptional<z.ZodArray<z.ZodString>>;
249
249
  }, z.core.$strict>]>>;
250
250
  biometrics: z.ZodOptional<z.ZodBoolean>;
251
+ reclaim: z.ZodOptional<z.ZodEnum<{
252
+ none: "none";
253
+ uninstall: "uninstall";
254
+ erase: "erase";
255
+ }>>;
251
256
  retry: z.ZodOptional<z.ZodNumber>;
252
257
  passes: z.ZodOptional<z.ZodNumber>;
253
258
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -338,8 +343,8 @@ export declare const wardenConfigSchema: z.ZodObject<{
338
343
  variant: z.ZodOptional<z.ZodString>;
339
344
  kind: z.ZodOptional<z.ZodEnum<{
340
345
  release: "release";
341
- dev: "dev";
342
346
  simulator: "simulator";
347
+ dev: "dev";
343
348
  }>>;
344
349
  }, z.core.$strict>]>>;
345
350
  ports: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -353,6 +358,11 @@ export declare const wardenConfigSchema: z.ZodObject<{
353
358
  keep: z.ZodOptional<z.ZodArray<z.ZodString>>;
354
359
  }, z.core.$strict>]>>;
355
360
  biometrics: z.ZodOptional<z.ZodBoolean>;
361
+ reclaim: z.ZodOptional<z.ZodEnum<{
362
+ none: "none";
363
+ uninstall: "uninstall";
364
+ erase: "erase";
365
+ }>>;
356
366
  warmRunners: z.ZodOptional<z.ZodUndefined>;
357
367
  warmDrivers: z.ZodOptional<z.ZodBoolean>;
358
368
  headless: z.ZodOptional<z.ZodBoolean>;
@@ -443,6 +453,49 @@ export declare const wardenConfigSchema: z.ZodObject<{
443
453
  reduceMotion: z.ZodOptional<z.ZodBoolean>;
444
454
  }, z.core.$strict>>;
445
455
  }, z.core.$strict>>;
456
+ a11y: z.ZodOptional<z.ZodObject<{
457
+ ignore: z.ZodOptional<z.ZodArray<z.ZodObject<{
458
+ rule: z.ZodEnum<{
459
+ "missing-name": "missing-name";
460
+ "image-no-name": "image-no-name";
461
+ "target-size": "target-size";
462
+ "target-size-platform": "target-size-platform";
463
+ "duplicate-name": "duplicate-name";
464
+ "role-in-name": "role-in-name";
465
+ "label-in-name": "label-in-name";
466
+ "hidden-focusable": "hidden-focusable";
467
+ "text-clipped": "text-clipped";
468
+ native: "native";
469
+ }>;
470
+ identifier: z.ZodOptional<z.ZodString>;
471
+ }, z.core.$strict>>>;
472
+ minSeverity: z.ZodOptional<z.ZodEnum<{
473
+ error: "error";
474
+ warning: "warning";
475
+ }>>;
476
+ rules: z.ZodOptional<z.ZodArray<z.ZodEnum<{
477
+ "missing-name": "missing-name";
478
+ "image-no-name": "image-no-name";
479
+ "target-size": "target-size";
480
+ "target-size-platform": "target-size-platform";
481
+ "duplicate-name": "duplicate-name";
482
+ "role-in-name": "role-in-name";
483
+ "label-in-name": "label-in-name";
484
+ "hidden-focusable": "hidden-focusable";
485
+ "text-clipped": "text-clipped";
486
+ native: "native";
487
+ }>>>;
488
+ }, z.core.$strict>>;
489
+ camera: z.ZodOptional<z.ZodObject<{
490
+ back: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
491
+ path: z.ZodString;
492
+ loop: z.ZodOptional<z.ZodBoolean>;
493
+ }, z.core.$strict>]>>;
494
+ front: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
495
+ path: z.ZodString;
496
+ loop: z.ZodOptional<z.ZodBoolean>;
497
+ }, z.core.$strict>]>>;
498
+ }, z.core.$strict>>;
446
499
  required: z.ZodDefault<z.ZodBoolean>;
447
500
  specs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
448
501
  entries: z.ZodDefault<z.ZodArray<z.ZodString>>;
@@ -461,6 +514,11 @@ export declare const wardenConfigSchema: z.ZodObject<{
461
514
  keep: z.ZodOptional<z.ZodArray<z.ZodString>>;
462
515
  }, z.core.$strict>]>>;
463
516
  biometrics: z.ZodOptional<z.ZodBoolean>;
517
+ reclaim: z.ZodOptional<z.ZodEnum<{
518
+ none: "none";
519
+ uninstall: "uninstall";
520
+ erase: "erase";
521
+ }>>;
464
522
  perf: z.ZodOptional<z.ZodObject<{
465
523
  budgets: z.ZodOptional<z.ZodObject<{
466
524
  startupColdMs: z.ZodOptional<z.ZodNumber>;
@@ -548,6 +606,39 @@ export declare const wardenConfigSchema: z.ZodObject<{
548
606
  reduceMotion: z.ZodOptional<z.ZodBoolean>;
549
607
  }, z.core.$strict>>;
550
608
  }, z.core.$strict>>;
609
+ a11y: z.ZodOptional<z.ZodObject<{
610
+ ignore: z.ZodOptional<z.ZodArray<z.ZodObject<{
611
+ rule: z.ZodEnum<{
612
+ "missing-name": "missing-name";
613
+ "image-no-name": "image-no-name";
614
+ "target-size": "target-size";
615
+ "target-size-platform": "target-size-platform";
616
+ "duplicate-name": "duplicate-name";
617
+ "role-in-name": "role-in-name";
618
+ "label-in-name": "label-in-name";
619
+ "hidden-focusable": "hidden-focusable";
620
+ "text-clipped": "text-clipped";
621
+ native: "native";
622
+ }>;
623
+ identifier: z.ZodOptional<z.ZodString>;
624
+ }, z.core.$strict>>>;
625
+ minSeverity: z.ZodOptional<z.ZodEnum<{
626
+ error: "error";
627
+ warning: "warning";
628
+ }>>;
629
+ rules: z.ZodOptional<z.ZodArray<z.ZodEnum<{
630
+ "missing-name": "missing-name";
631
+ "image-no-name": "image-no-name";
632
+ "target-size": "target-size";
633
+ "target-size-platform": "target-size-platform";
634
+ "duplicate-name": "duplicate-name";
635
+ "role-in-name": "role-in-name";
636
+ "label-in-name": "label-in-name";
637
+ "hidden-focusable": "hidden-focusable";
638
+ "text-clipped": "text-clipped";
639
+ native: "native";
640
+ }>>>;
641
+ }, z.core.$strict>>;
551
642
  android: z.ZodOptional<z.ZodObject<{
552
643
  snapshot: z.ZodOptional<z.ZodBoolean>;
553
644
  }, z.core.$strict>>;
@@ -326,6 +326,13 @@ export interface WardenBatchPreset {
326
326
  * `biometrics`. Default false.
327
327
  */
328
328
  biometrics?: boolean | undefined;
329
+ /**
330
+ * What happens to the state of the devices of this run when they are released: `"erase"` (iOS: shutdown +
331
+ * `simctl erase`; Android: uninstalls the third-party apps), `"uninstall"` (removes the user-installed apps) or
332
+ * `"none"`. Only warden-created simulators and emulators are reclaimed, never foreign, golden or physical
333
+ * devices. Overrides the top-level `reclaim`; `WARDEN_RECLAIM` is the fallback below it. Default `"none"`.
334
+ */
335
+ reclaim?: "erase" | "uninstall" | "none" | undefined;
329
336
  /** Per-job log dir. */
330
337
  logs?: string | undefined;
331
338
  /**
@@ -420,6 +427,20 @@ export interface WardenPerfConfig {
420
427
  /** Budgets; a metric the report has no number for (its capture did not run) cannot breach. */
421
428
  budgets?: WardenPerfBudgets | undefined;
422
429
  }
430
+ /** `a11y` (top level, or `e2e.<suite>.a11y`): how accessibility audits judge a screen. */
431
+ export interface WardenA11yConfig {
432
+ /** Findings to drop: a rule everywhere, or only on the element with that `identifier` (testID). */
433
+ ignore?: Array<{
434
+ rule: WardenA11yRule;
435
+ identifier?: string | undefined;
436
+ }> | undefined;
437
+ /** Lowest severity that fails an audit. @default "error" */
438
+ minSeverity?: "error" | "warning" | undefined;
439
+ /** Run only these rules (default: all). */
440
+ rules?: WardenA11yRule[] | undefined;
441
+ }
442
+ /** A rule id an audit reports; `native` = XCUITest / ATF findings. */
443
+ export type WardenA11yRule = "missing-name" | "image-no-name" | "target-size" | "target-size-platform" | "duplicate-name" | "role-in-name" | "label-in-name" | "hidden-focusable" | "text-clipped" | "native";
423
444
  /** `conditions.network` as a custom shape: the fields of a `custom` network condition. */
424
445
  export interface WardenCustomNetwork {
425
446
  /** Added round-trip time, ms. */
@@ -507,6 +528,16 @@ export interface WardenE2eDeviceLeg {
507
528
  */
508
529
  default?: boolean | undefined;
509
530
  }
531
+ /** One camera asset: a path (relative to the config file), or `{ path, loop }`. */
532
+ export type WardenCameraFeed = string | {
533
+ path: string;
534
+ loop?: boolean | undefined;
535
+ };
536
+ /** `e2e.<suite>.camera`: the asset each facing plays. At least one of `back` / `front`. */
537
+ export type WardenCameraConfig = {
538
+ back?: WardenCameraFeed | undefined;
539
+ front?: WardenCameraFeed | undefined;
540
+ };
510
541
  /**
511
542
  * `e2e.<suite>`: the specs `warden affected` selects and `warden e2e` runs. Every path and glob is
512
543
  * relative to the config file.
@@ -521,6 +552,14 @@ export interface WardenE2eSuite {
521
552
  perf?: WardenPerfConfig | undefined;
522
553
  /** Device conditions every spec of this suite starts from; each area replaces the top-level one. */
523
554
  conditions?: WardenConditionsConfig | undefined;
555
+ /** Accessibility audit settings for this suite; each key replaces the top-level `a11y` one. */
556
+ a11y?: WardenA11yConfig | undefined;
557
+ /**
558
+ * The simulated camera every spec of this suite starts from, applied before the first `app.open()`: a path, or
559
+ * `{ path, loop }` (video loop, default true), per facing. Paths are relative to the config file. Android devices of
560
+ * the suite are claimed with `--camera` (profile `<profile>+cam`, cold boot). png, jpg, heic, mp4 and mov are accepted.
561
+ */
562
+ camera?: WardenCameraConfig | undefined;
524
563
  /** Directory of specs: `*.e2e.ts(x)` specs whose other `.ts` files are helpers (searched recursively; dot dirs, `node_modules` and `__baselines__` skipped). */
525
564
  specsDir: string;
526
565
  /** How the specs run: the app under test, its launch arguments and the timeouts. */
@@ -685,6 +724,13 @@ export interface WardenE2eSuite {
685
724
  * `biometrics`. Default false.
686
725
  */
687
726
  biometrics?: boolean | undefined;
727
+ /**
728
+ * What happens to the state of the devices of this run when they are released: `"erase"` (iOS: shutdown +
729
+ * `simctl erase`; Android: uninstalls the third-party apps), `"uninstall"` (removes the user-installed apps) or
730
+ * `"none"`. Only warden-created simulators and emulators are reclaimed, never foreign, golden or physical
731
+ * devices. Overrides the top-level `reclaim`; `WARDEN_RECLAIM` is the fallback below it. Default `"none"`.
732
+ */
733
+ reclaim?: "erase" | "uninstall" | "none" | undefined;
688
734
  /** Removed: renamed `warmDrivers`. */
689
735
  warmRunners?: undefined;
690
736
  /**
@@ -748,10 +794,19 @@ export interface WardenConfig {
748
794
  * override it. Default false.
749
795
  */
750
796
  biometrics?: boolean | undefined;
797
+ /**
798
+ * What happens to the state of the devices of this run when they are released: `"erase"` (iOS: shutdown +
799
+ * `simctl erase`; Android: uninstalls the third-party apps), `"uninstall"` (removes the user-installed apps) or
800
+ * `"none"`. Only warden-created simulators and emulators are reclaimed, never foreign, golden or physical
801
+ * devices. Overrides the top-level `reclaim`; `WARDEN_RECLAIM` is the fallback below it. Default `"none"`.
802
+ */
803
+ reclaim?: "erase" | "uninstall" | "none" | undefined;
751
804
  /** Perf budgets every `e2e` suite starts from (a suite's own `perf.budgets` replace them per key). */
752
805
  perf?: WardenPerfConfig | undefined;
753
806
  /** Device conditions every `e2e` suite starts from (a suite's own `conditions` replace them per area). */
754
807
  conditions?: WardenConditionsConfig | undefined;
808
+ /** Accessibility audit settings every `e2e` suite starts from (a suite's own `a11y` keys replace them). */
809
+ a11y?: WardenA11yConfig | undefined;
755
810
  /** Android emulator settings. */
756
811
  android?: WardenAndroidSettings | undefined;
757
812
  /** Physical iPhone settings. */
@@ -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;
@@ -93,6 +93,30 @@ export declare const conditionsConfigSchema: z.ZodObject<{
93
93
  }, z.core.$strict>>;
94
94
  }, z.core.$strict>;
95
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>;
96
120
  /** What a spec's `device.network.set` takes: a condition, or its word. */
97
121
  export type NetworkInput = NetworkCondition | "online" | "offline" | NetworkPreset;
98
122
  /** A word, a custom shape (config) or a ready condition, as a `NetworkCondition`. */