@delacour/warden-e2e 0.14.0 → 0.15.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 (34) hide show
  1. package/{chunk-zk3wxa70.mjs → chunk-e3cry5br.mjs} +287 -37
  2. package/index.mjs +32 -3
  3. package/package.json +2 -2
  4. package/preload.mjs +304 -30
  5. package/types/core/src/affected/affected.schema.d.ts +5 -0
  6. package/types/core/src/builds/builds.defaults.d.ts +8 -0
  7. package/types/core/src/builds/config.schema.d.ts +9 -0
  8. package/types/core/src/builds/define-config.d.ts +9 -1
  9. package/types/core/src/conditions/conditions.config.d.ts +6 -1
  10. package/types/core/src/conditions/conditions.types.d.ts +21 -0
  11. package/types/core/src/conditions/inject-state.d.ts +3 -2
  12. package/types/e2e/src/a11y/a11y-target.d.ts +2 -0
  13. package/types/e2e/src/conditions/condition-events.d.ts +6 -1
  14. package/types/e2e/src/conditions/device-conditions.d.ts +8 -2
  15. package/types/e2e/src/device.d.ts +10 -2
  16. package/types/e2e/src/driver/android/android-settings.d.ts +9 -2
  17. package/types/e2e/src/driver/ax-wedge.d.ts +38 -0
  18. package/types/e2e/src/driver/bridge-stall.d.ts +4 -0
  19. package/types/e2e/src/driver/driver.types.d.ts +30 -1
  20. package/types/e2e/src/driver/ios/inject.d.ts +17 -2
  21. package/types/e2e/src/driver/ios/ios-driver.d.ts +7 -2
  22. package/types/e2e/src/driver/ios/ios-keyboard.d.ts +39 -0
  23. package/types/e2e/src/driver/ios/simd-protocol.d.ts +99 -0
  24. package/types/e2e/src/driver/keyboard-state.d.ts +9 -0
  25. package/types/e2e/src/driver/physical-conditions.d.ts +1 -1
  26. package/types/e2e/src/driver/read-deadline.d.ts +4 -0
  27. package/types/e2e/src/driver/settle.d.ts +3 -1
  28. package/types/e2e/src/expect/a11y-matchers.d.ts +7 -0
  29. package/types/e2e/src/index.d.ts +2 -1
  30. package/types/e2e/src/screen/actions.d.ts +7 -0
  31. package/types/e2e/src/screen/context.d.ts +3 -1
  32. package/types/e2e/src/screen/keyboard-cover.d.ts +26 -0
  33. package/types/e2e/src/screen/locator.d.ts +16 -7
  34. package/types/e2e/src/session.d.ts +6 -0
@@ -1,4 +1,4 @@
1
- import type { Snapshot } from "./driver.types";
1
+ import type { Element, Snapshot } from "./driver.types";
2
2
  export type SettleDeps = {
3
3
  quietMs: number;
4
4
  timeoutMs: number;
@@ -47,5 +47,7 @@ export declare function hashFallbackQuietMs(quietMs: number): number;
47
47
  * Side effects are injected so tests drive a fake clock.
48
48
  */
49
49
  export declare function settleByHash(poll: () => Promise<string>, deps: SettleDeps): Promise<SettleOutcome>;
50
+ /** One element as `(role, identifier, label, value, frame to 1 pt)`: what `snapshotHash` hashes, per node. */
51
+ export declare function elementKey(element: Element): string;
50
52
  /** Stable fingerprint over `(role, identifier, label, value, frame)` of every node in preorder. */
51
53
  export declare function snapshotHash(snapshot: Pick<Snapshot, "flat">): string;
@@ -28,6 +28,13 @@ export declare class DeviceAssertions {
28
28
  toPassA11yAudit(options?: PassA11yAuditOptions): Promise<void>;
29
29
  /** An announcement or live-region change whose text contains the string or matches the RegExp arrived (`.not`: none did within the timeout). */
30
30
  toHaveAnnounced(expected: TextMatch, options?: AnnouncedOptions): Promise<void>;
31
+ /**
32
+ * The on-screen keyboard is up (`.not`: it is gone), read from the accessibility tree. Polls until it holds or
33
+ * `timeout` (default: the assertion timeout) passes. Under `hardware` mode the keyboard never shows.
34
+ */
35
+ toHaveKeyboard(options?: {
36
+ timeout?: number;
37
+ }): Promise<void>;
31
38
  private failure;
32
39
  private run;
33
40
  }
@@ -1,9 +1,10 @@
1
+ export type { KeyboardMode } from "../../core/src/conditions/conditions.types";
1
2
  export type { A11yAuditOptions, A11yAuditResult, A11yEvent, A11yEventKind, A11yEventSource, A11yIgnore, A11yIssue, A11yRuleId, A11ySeverity, A11ySource, Announcement, ScreenReaderState, SpokenLine, } from "./a11y/a11y.types";
2
3
  export type { OpenOptions, OpenWaitUntil } from "./app";
3
4
  export type { CameraFacingChoice, CameraSetOptions, ClockInput, ConditionRun, DeviceCamera, DeviceClock, DeviceLocation, DeviceNetwork, DevicePermissions, Duration, FlapOptions, LocationPoint, NetworkSetOptions, NetworkStatus, RouteOptions, TimelineStepInput, } from "./conditions/device-conditions";
4
5
  export type { BiometricState, DeviceBiometrics } from "./device";
5
6
  export type { A11yAnnouncement, A11yAnnouncements, A11yAnnouncementsOptions, DeviceA11y, DeviceA11yAuditOptions, DeviceScreenReader, ScreenReaderSpokenOptions, } from "./device-a11y";
6
- export type { A11yOp, A11yState, CameraState } from "./driver/driver.types";
7
+ export type { A11yOp, A11yState, CameraState, KeyboardResult, KeyboardState } from "./driver/driver.types";
7
8
  export { E2eError } from "./errors";
8
9
  export type { AnnouncedOptions, PassA11yAuditOptions } from "./expect/a11y-matchers";
9
10
  export { expect } from "./expect/expect";
@@ -39,6 +39,8 @@ export declare function isOnScreen(point: Point, screen: ScreenInfo): boolean;
39
39
  * field; Android keeps an input's text in `text`.
40
40
  */
41
41
  export declare function fieldValue(entry: NodeEntry): string;
42
+ /** User-perceived characters in `text` (what a secure field shows one bullet for). */
43
+ export declare function graphemes(text: string): number;
42
44
  /** What one read says a field holds: nothing, text, or (secure fields) a number of hidden characters. */
43
45
  export type FieldContent = {
44
46
  kind: "empty";
@@ -55,6 +57,11 @@ export type FieldContent = {
55
57
  * plain field showing its placeholder cannot be told from one holding that text and reads as `text`.
56
58
  */
57
59
  export declare function fieldContent(entry: NodeEntry): FieldContent;
60
+ /**
61
+ * What a fill read-back of a secure field says it holds, given the typed `text`: `text` when it shows one bullet per
62
+ * character of it (the only check a masked field allows), else its bullets (never the typed text, in a message).
63
+ */
64
+ export declare function maskedReading(entry: NodeEntry, text: string): string;
58
65
  /**
59
66
  * Backspaces that empty a field once the caret is at its end: one per character plus a spare. Secure fields are
60
67
  * counted by their dots. The fallback for a driver without select-all, and the retry when select-all did not empty
@@ -128,7 +128,9 @@ export declare class Runtime {
128
128
  excerpt(snapshot: Snapshot): string;
129
129
  /**
130
130
  * `poll` on this runtime's clock and abort signal; an abort throws instead of returning. `intervalMs` is a fixed gap
131
- * between attempts instead of the back-off schedule.
131
+ * between attempts instead of the back-off schedule. The poll's deadline is the read deadline of every driver read
132
+ * made inside it (`withReadDeadline`), so a read that waits for the device (the cold iOS bridge) stops with it; a
133
+ * poll inside another keeps the nearer deadline.
132
134
  */
133
135
  poll<T, S>(step: (attempt: number) => Promise<PollStep<T, S>> | PollStep<T, S>, timeoutMs: number, options?: {
134
136
  intervalMs?: number;
@@ -0,0 +1,26 @@
1
+ import type { Driver, DriverResult, Point, Rect, Snapshot } from "../driver/driver.types";
2
+ import type { NodeEntry } from "./nodes";
3
+ export type Cover = {
4
+ /** the keyboard's top edge */
5
+ top: number;
6
+ /** the free part of the nearest scroll container (its frame down to the keyboard), when the target sits in one */
7
+ scroller?: Rect;
8
+ /** points the content has to move up to clear the keyboard with a margin */
9
+ shift: number;
10
+ };
11
+ /** Whether `point` is under the keyboard of `snapshot`, and how to get clear of it; undefined when it is not. */
12
+ export declare function coverOf(entry: NodeEntry, point: Point, snapshot: Snapshot): Cover | undefined;
13
+ /**
14
+ * The finger path that moves the content of `scroller` up by about `shift` points (a shorter one when the free part
15
+ * is not that tall: the caller looks again and swipes again).
16
+ */
17
+ export declare function scrollPath(scroller: Rect, shift: number): {
18
+ from: Point;
19
+ to: Point;
20
+ };
21
+ export declare const COVER_SCROLL_SWIPE: {
22
+ durationMs: number;
23
+ momentum: boolean;
24
+ };
25
+ /** Dismisses the keyboard the way `device.hideKeyboard()` does: iOS resigns the first responder (no Return), Android presses back. */
26
+ export declare function dismissKeyboard(driver: Driver): DriverResult<void>;
@@ -134,7 +134,8 @@ export declare class Locator {
134
134
  degradedFailure(read: DegradedRead, waitedMs: number, snapshot: Observed["snapshot"] | undefined): E2eError;
135
135
  /**
136
136
  * One look that settles this locator. A whole read answers at once (never waits); a degraded one that cannot say
137
- * whether the locator is there is looked at again until one can, within the action timeout, then `READ_DEGRADED`.
137
+ * whether the locator is there is looked at again until one can, within the action timeout (`quick`: within
138
+ * `QUICK_CHECK_WINDOW_MS`, for checks a spec branches on), then `READ_DEGRADED`.
138
139
  */
139
140
  private conclusive;
140
141
  /** The conclusive answer of `observed`, or undefined while it is `unknown`. */
@@ -219,6 +220,13 @@ export declare class Locator {
219
220
  * the kept snapshot sits outside the app, where the app-scoped hit-test may not see it, and the fresh look answers it.
220
221
  */
221
222
  private aimFromKept;
223
+ /**
224
+ * A target under the on-screen keyboard (the default `software` mode keeps it up) would get the touch on a key. In a
225
+ * scroll container it is scrolled into the free part of the screen (at most `MAX_COVER_SCROLLS` swipes, each looked at
226
+ * fresh); otherwise, or when scrolling does not clear it, the keyboard is dismissed once (`dismissKeyboard`). Either way
227
+ * the match is looked at again, and whatever that look shows is what the action uses: no retry.
228
+ */
229
+ private clearOfKeyboard;
222
230
  /**
223
231
  * Taps the one visible, enabled match. With `until` it is also the retrying tap: the press on a tab bar or a list row
224
232
  * right after a navigation is sometimes dropped with nothing on screen to tell, so it checks that `until` shows
@@ -226,9 +234,10 @@ export declare class Locator {
226
234
  */
227
235
  tap(options?: TapOptions): Promise<void>;
228
236
  /**
229
- * One press; resolves to the snapshot it aimed from (the screen just before the press). A plain tap may aim from the
230
- * kept snapshot (`aimFromKept`); a tap with `until` takes a fresh look, since the screen it aimed from is what the
231
- * checks compare against to tell the press landed, and an older one could differ only because it was older.
237
+ * One press; resolves to the snapshot it aimed from (the screen just before the press) and the element pressed (none
238
+ * for a match only the React tree knows). A plain tap may aim from the kept snapshot (`aimFromKept`); a tap with
239
+ * `until` takes a fresh look, since the screen it aimed from is what the checks compare against to tell the press
240
+ * landed, and an older one could differ only because it was older.
232
241
  */
233
242
  private tapOnce;
234
243
  /**
@@ -236,9 +245,9 @@ export declare class Locator {
236
245
  * (`driver.tap` returns once the HID press is over, ~85 ms, and an AX read queues behind the app's main thread, so
237
246
  * that look usually already shows the screen the press made; measured: holding it back to `pollMs` saved no read
238
247
  * and cost 250 ms a press). A locator is checked on the snapshot of
239
- * the poll itself, which is also compared with `pressedOn` (the hash of the screen the press aimed from): once the
240
- * screen changed the press landed, so it is never sent again (`landed`, even when `until` is late); a screen still
241
- * unchanged on `UNCHANGED_CHECKS` checks in a row from `UNCHANGED_AFTER_MS` on is pressed again at once. A function
248
+ * the poll itself, which is also compared with the screen the press aimed from (`reacted`): once the screen reacted
249
+ * the press landed, so it is never sent again (`landed`, even when `until` is late); a screen that has not reacted
250
+ * on `UNCHANGED_CHECKS` checks in a row from `UNCHANGED_AFTER_MS` on is pressed again at once. A function
242
251
  * is called with the kept snapshot forgotten (after the first check), so its own reads take one new snapshot
243
252
  * between them rather than the previous check's; it gets the whole window.
244
253
  */
@@ -37,6 +37,12 @@ export type Session = {
37
37
  * reopens the driver and devtools, once per session. Resolves `true` when the test is worth running again.
38
38
  */
39
39
  recoverHid: (() => Promise<boolean>) | undefined;
40
+ /**
41
+ * Present for iOS simulator runs: after a test failed, asks the open driver whether `warden-simd` restarted the
42
+ * sim's wedged accessibility service (backboardd, which quits the app) within the last `attemptMs` (waiting for a
43
+ * restart still in flight). Resolves `true` once per restart: the test is worth running again.
44
+ */
45
+ recoverAxWedge: ((attemptMs: number) => Promise<boolean>) | undefined;
40
46
  /** closes the open driver and devtools so the next call opens them afresh (the device was rebooted under them) */
41
47
  resetDevice(): Promise<void>;
42
48
  /** where the console reporter prints one line; default fd 1 */