@delacour/warden-e2e 0.13.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 (42) hide show
  1. package/{chunk-tnr47n9c.mjs → chunk-e3cry5br.mjs} +828 -255
  2. package/index.mjs +144 -14
  3. package/package.json +2 -2
  4. package/preload.mjs +375 -63
  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 +41 -0
  19. package/types/e2e/src/driver/driver.types.d.ts +35 -2
  20. package/types/e2e/src/driver/ios/inject.d.ts +17 -2
  21. package/types/e2e/src/driver/ios/ios-driver.d.ts +17 -2
  22. package/types/e2e/src/driver/ios/ios-keyboard.d.ts +39 -0
  23. package/types/e2e/src/driver/ios/simd-client.d.ts +2 -0
  24. package/types/e2e/src/driver/ios/simd-protocol.d.ts +129 -0
  25. package/types/e2e/src/driver/keyboard-state.d.ts +9 -0
  26. package/types/e2e/src/driver/physical-conditions.d.ts +1 -1
  27. package/types/e2e/src/driver/read-deadline.d.ts +4 -0
  28. package/types/e2e/src/driver/settle.d.ts +11 -1
  29. package/types/e2e/src/errors.d.ts +3 -1
  30. package/types/e2e/src/expect/a11y-matchers.d.ts +7 -0
  31. package/types/e2e/src/expect/matchers.d.ts +5 -0
  32. package/types/e2e/src/index.d.ts +2 -1
  33. package/types/e2e/src/runner/bridge-evidence.d.ts +12 -0
  34. package/types/e2e/src/runner/results.d.ts +29 -0
  35. package/types/e2e/src/screen/actions.d.ts +7 -0
  36. package/types/e2e/src/screen/context.d.ts +11 -12
  37. package/types/e2e/src/screen/degraded-read.d.ts +23 -0
  38. package/types/e2e/src/screen/keyboard-cover.d.ts +26 -0
  39. package/types/e2e/src/screen/locator.d.ts +61 -7
  40. package/types/e2e/src/screen/react-locator.d.ts +17 -2
  41. package/types/e2e/src/screen/react-merge.d.ts +10 -0
  42. package/types/e2e/src/session.d.ts +6 -0
@@ -236,6 +236,10 @@ function settleDetailOf(outcome) {
236
236
  }
237
237
  var DEFAULT_SETTLE_QUIET_MS = 250;
238
238
  var DEFAULT_SETTLE_TIMEOUT_MS = 3000;
239
+ var HASH_FALLBACK_MIN_QUIET_MS = 500;
240
+ function hashFallbackQuietMs(quietMs) {
241
+ return Math.max(quietMs, HASH_FALLBACK_MIN_QUIET_MS);
242
+ }
239
243
  var DEFAULT_POLL_MS = 50;
240
244
  async function settleByHash(poll, deps) {
241
245
  const { quietMs, timeoutMs, now, sleep } = deps;
@@ -260,7 +264,7 @@ async function settleByHash(poll, deps) {
260
264
  return { quiet: false, waitedMs: t - start };
261
265
  }
262
266
  }
263
- function tuple(element) {
267
+ function elementKey(element) {
264
268
  const { x, y, width, height } = element.frame;
265
269
  return JSON.stringify([
266
270
  element.role,
@@ -276,7 +280,7 @@ function tuple(element) {
276
280
  function snapshotHash(snapshot) {
277
281
  let text = "";
278
282
  for (const element of snapshot.flat)
279
- text += `${tuple(element)}
283
+ text += `${elementKey(element)}
280
284
  `;
281
285
  return Bun.hash(text).toString(36);
282
286
  }
@@ -430,6 +434,11 @@ function fieldContent(entry) {
430
434
  const text = fieldValue(entry);
431
435
  return text === "" ? { kind: "empty" } : { kind: "text", text };
432
436
  }
437
+ function maskedReading(entry, text) {
438
+ const content = fieldContent(entry);
439
+ const count = content.kind === "dots" ? content.count : 0;
440
+ return count === graphemes(text) ? text : "\u2022".repeat(count);
441
+ }
433
442
  function clearKeyPresses(entry) {
434
443
  const content = fieldContent(entry);
435
444
  switch (content.kind) {
@@ -479,6 +488,34 @@ function assertDegrees(degrees) {
479
488
  }
480
489
  }
481
490
 
491
+ // ../../packages/e2e/src/screen/degraded-read.ts
492
+ function degradedRead(snapshot) {
493
+ if (snapshot.fellBackFrom !== undefined) {
494
+ return { kind: "fallback", from: snapshot.fellBackFrom, backend: snapshot.backend };
495
+ }
496
+ const [root, ...others] = snapshot.elements;
497
+ if (root !== undefined && others.length === 0 && root.children.length === 0) {
498
+ const { width, height } = root.frame;
499
+ if (width * height === 0)
500
+ return { kind: "emptyRoot", backend: snapshot.backend };
501
+ }
502
+ return;
503
+ }
504
+ function describeDegraded(read) {
505
+ if (read.kind === "emptyRoot")
506
+ return `the ${read.backend} read returned an empty root (backend: ${read.backend})`;
507
+ return `the read fell back from ${read.from} to ${read.backend} (fellBackFrom: ${read.from}, backend: ${read.backend}), which can drop React Native testIDs`;
508
+ }
509
+ var REACT_NOTES = {
510
+ unanswered: "the React tree did not answer",
511
+ "no-devtools": "there is no React tree to ask (no devtools: not a dev client with Metro)",
512
+ "not-testid": "only a plain getByTestId can be asked of the React tree"
513
+ };
514
+ function degradedFailure(locator, read, waitedMs, react, screen) {
515
+ const message = `${locator} could not be confirmed within ${waitedMs} ms: bridge degraded, ${describeDegraded(read)}, ` + `and ${REACT_NOTES[react]}. A missing node on such a read is not proof of absence.`;
516
+ return new E2eError2("READ_DEGRADED", message, screen);
517
+ }
518
+
482
519
  // ../../packages/e2e/src/screen/roles.ts
483
520
  var QUERY_ROLES = [
484
521
  "button",
@@ -725,7 +762,7 @@ function nonEmpty(value) {
725
762
  }
726
763
  var MASKED_VALUE = /^[\u2022\u25CF]+$/;
727
764
  function isSecure(element, traits) {
728
- return element.role === "textfield" && element.value !== undefined && MASKED_VALUE.test(element.value) || element.role === "securefield" || traits.has("password") || traits.has("secure") || element.rawType.toLowerCase().includes("secure");
765
+ return element.role === "textfield" && element.value !== undefined && MASKED_VALUE.test(element.value) || element.role === "securefield" || traits.has("password") || traits.has("secure") || traits.has("secure-text-field") || element.rawType.toLowerCase().includes("secure");
729
766
  }
730
767
  function deriveChecked(element, role, spelled, traits, value) {
731
768
  if (spelled?.checked !== undefined)
@@ -984,6 +1021,60 @@ async function typeOver(driver, sleep, prepared, text, via) {
984
1021
  return typeText(driver, sleep, text);
985
1022
  }
986
1023
 
1024
+ // ../../packages/e2e/src/driver/keyboard-state.ts
1025
+ function keyboardElement(snapshot) {
1026
+ const { height } = snapshot.screen;
1027
+ const onScreen = snapshot.flat.filter((e) => e.role === "keyboard" && e.hidden !== true && e.frame.width > 0 && e.frame.height > 0 && (height <= 0 || e.frame.y < height && e.frame.y + e.frame.height > 0));
1028
+ return onScreen.sort((a, b) => b.frame.width * b.frame.height - a.frame.width * a.frame.height)[0];
1029
+ }
1030
+ function keyboardVisible(snapshot) {
1031
+ return keyboardElement(snapshot) !== undefined;
1032
+ }
1033
+ function keyboardFrame(snapshot) {
1034
+ return keyboardElement(snapshot)?.frame;
1035
+ }
1036
+
1037
+ // ../../packages/e2e/src/screen/keyboard-cover.ts
1038
+ var COVER_MARGIN = 40;
1039
+ var SWIPE_INSET = 12;
1040
+ var SCROLL_SWIPE = { durationMs: 350, momentum: false };
1041
+ var SCROLL_ROLES = new Set(["scrollview", "list"]);
1042
+ function scrollContainer(entry) {
1043
+ for (let node = entry.parent;node !== undefined; node = node.parent) {
1044
+ if (SCROLL_ROLES.has(node.element.role))
1045
+ return node;
1046
+ }
1047
+ return;
1048
+ }
1049
+ function coverOf(entry, point, snapshot) {
1050
+ const keyboard = keyboardFrame(snapshot);
1051
+ if (keyboard === undefined || entry.element.role === "keyboard")
1052
+ return;
1053
+ const inside = point.x >= keyboard.x && point.x <= keyboard.x + keyboard.width && point.y >= keyboard.y && point.y <= keyboard.y + keyboard.height;
1054
+ if (!inside)
1055
+ return;
1056
+ const container = scrollContainer(entry);
1057
+ const shift = point.y - (keyboard.y - COVER_MARGIN);
1058
+ if (container === undefined)
1059
+ return { top: keyboard.y, shift };
1060
+ const { frame } = container.element;
1061
+ const bottom = Math.min(frame.y + frame.height, keyboard.y);
1062
+ const free = { x: frame.x, y: frame.y, width: frame.width, height: Math.max(0, bottom - frame.y) };
1063
+ return free.height > 2 * SWIPE_INSET ? { top: keyboard.y, scroller: free, shift } : { top: keyboard.y, shift };
1064
+ }
1065
+ function scrollPath(scroller, shift) {
1066
+ const x = scroller.x + scroller.width / 2;
1067
+ const room = scroller.height - 2 * SWIPE_INSET;
1068
+ const travel = Math.max(1, Math.min(shift, room));
1069
+ const from = scroller.y + scroller.height - SWIPE_INSET;
1070
+ return { from: { x, y: from }, to: { x, y: from - travel } };
1071
+ }
1072
+ var COVER_SCROLL_SWIPE = SCROLL_SWIPE;
1073
+ async function dismissKeyboard(driver) {
1074
+ const done = await driver.dismissKeyboard();
1075
+ return done.success ? { success: true, data: undefined } : done;
1076
+ }
1077
+
987
1078
  // ../../packages/e2e/src/screen/selector.ts
988
1079
  var VALUE_KEYS = ["id", "label", "text", "role", "value"];
989
1080
  var KEY_ORDER = [...VALUE_KEYS, "editable", "nth"];
@@ -1534,7 +1625,7 @@ function describeExpression(expr) {
1534
1625
  }
1535
1626
 
1536
1627
  // ../../packages/e2e/src/screen/react-locator.ts
1537
- async function locateByTestIdViaReact(facet, testId, view, options = {}) {
1628
+ async function lookUpTestIdViaReact(facet, testId, view, options = {}) {
1538
1629
  const treeOptions = {
1539
1630
  ...view.platform === "android" ? { pixelRatio: view.screen.scale } : {},
1540
1631
  ...options.screenName === undefined ? {} : { screen: options.screenName },
@@ -1544,12 +1635,13 @@ async function locateByTestIdViaReact(facet, testId, view, options = {}) {
1544
1635
  try {
1545
1636
  result = await facet.tree(treeOptions);
1546
1637
  } catch {
1547
- return [];
1638
+ return { answered: false };
1548
1639
  }
1549
1640
  if (!result.success)
1550
- return [];
1641
+ return { answered: false };
1551
1642
  const matches = [];
1552
- for (const component of result.data.components) {
1643
+ const { components } = result.data;
1644
+ for (const component of components) {
1553
1645
  const { testID, rect } = component;
1554
1646
  if (testID === undefined || rect === undefined || !matchesText(testID, testId))
1555
1647
  continue;
@@ -1558,10 +1650,25 @@ async function locateByTestIdViaReact(facet, testId, view, options = {}) {
1558
1650
  tapPoint: { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 },
1559
1651
  source: "react",
1560
1652
  testId: testID,
1561
- name: component.name
1653
+ name: component.name,
1654
+ ...textOf2(component, components)
1562
1655
  });
1563
1656
  }
1564
- return matches;
1657
+ return { answered: true, matches };
1658
+ }
1659
+ function textOf2(component, components) {
1660
+ if (component.text !== undefined)
1661
+ return { text: component.text };
1662
+ const inside = new Set([component.id]);
1663
+ const texts = [];
1664
+ for (const other of components) {
1665
+ if (other.parent === null || !inside.has(other.parent))
1666
+ continue;
1667
+ inside.add(other.id);
1668
+ if (other.text !== undefined)
1669
+ texts.push(other.text);
1670
+ }
1671
+ return texts.length === 0 ? {} : { text: texts.join(" ") };
1565
1672
  }
1566
1673
  function reactTapPoint(match, position) {
1567
1674
  if (position === undefined)
@@ -1569,18 +1676,58 @@ function reactTapPoint(match, position) {
1569
1676
  return { x: match.frame.x + position.x, y: match.frame.y + position.y };
1570
1677
  }
1571
1678
 
1679
+ // ../../packages/e2e/src/screen/react-merge.ts
1680
+ var EDGE_SLACK = 1.5;
1681
+ function sameRect(a, b) {
1682
+ if (a.width <= 0 || a.height <= 0 || b.width <= 0 || b.height <= 0)
1683
+ return false;
1684
+ return Math.abs(a.x - b.x) <= EDGE_SLACK && Math.abs(a.y - b.y) <= EDGE_SLACK && Math.abs(a.x + a.width - (b.x + b.width)) <= EDGE_SLACK && Math.abs(a.y + a.height - (b.y + b.height)) <= EDGE_SLACK;
1685
+ }
1686
+ function ownText(entry) {
1687
+ return normalizeText(entry.name ?? entry.value ?? "");
1688
+ }
1689
+ function nodeOfReactMatch(match, index) {
1690
+ const candidates = index.entries.filter((entry) => {
1691
+ const id = entry.element.identifier;
1692
+ return (id === undefined || id === match.testId) && sameRect(entry.element.frame, match.frame);
1693
+ });
1694
+ const text = match.text === undefined ? "" : normalizeText(match.text);
1695
+ const worded = text === "" ? [] : candidates.filter((entry) => ownText(entry) === text);
1696
+ const pool = worded.length > 0 ? worded : candidates;
1697
+ let best;
1698
+ for (const entry of pool)
1699
+ if (best === undefined || entry.depth > best.depth)
1700
+ best = entry;
1701
+ return best;
1702
+ }
1703
+ function mergeReactMatches(matches, index) {
1704
+ const entries = [];
1705
+ for (const match of matches) {
1706
+ const entry = nodeOfReactMatch(match, index);
1707
+ if (entry === undefined || entries.includes(entry))
1708
+ return;
1709
+ entries.push(entry);
1710
+ }
1711
+ return entries;
1712
+ }
1713
+
1572
1714
  // ../../packages/e2e/src/screen/locator.ts
1573
1715
  var WAIT_STATES = ["attached", "detached", "visible", "hidden"];
1574
1716
  var DEFAULT_MAX_SWIPES = 10;
1575
1717
  var VERIFY_MS = 1000;
1576
1718
  var CONFIRM_FLOOR_MS = 500;
1577
1719
  var SCROLL_SETTLE = { quietMs: 150, timeoutMs: 1000 };
1720
+ var MAX_COVER_SCROLLS = 3;
1721
+ var QUICK_CHECK_WINDOW_MS = 2000;
1578
1722
  function assertOptions(verb, options, allowed) {
1579
1723
  const unknown = Object.keys(options).filter((key) => !allowed.includes(key));
1580
1724
  if (unknown.length > 0) {
1581
1725
  throw new E2eError2("INVALID_ARGUMENT", `${verb} does not take ${unknown.map((key) => `"${key}"`).join(", ")}; it takes ${allowed.join(", ")}`);
1582
1726
  }
1583
1727
  }
1728
+ function reactVisible(match, observed) {
1729
+ return match.frame.width > 0 && match.frame.height > 0 && isOnScreen(match.tapPoint, observed.snapshot.screen);
1730
+ }
1584
1731
  var REACT_ONLY = "exists only in the React tree, not in the accessibility tree, so only tap() and boundingBox() work on it; " + "expose it to accessibility (accessible, accessibilityLabel) to use anything else";
1585
1732
  function plainTestId(expr) {
1586
1733
  if (expr.kind !== "query" || expr.scope !== undefined || expr.query.kind !== "testId")
@@ -1665,8 +1812,79 @@ class Locator {
1665
1812
  const observed = await this.rt.observe(options);
1666
1813
  return { entries: resolve(this.expr, observed.index), observed };
1667
1814
  }
1668
- matches() {
1669
- return this.look();
1815
+ async resolveIn(observed) {
1816
+ const entries = resolve(this.expr, observed.index);
1817
+ if (entries.length > 0)
1818
+ return { kind: "nodes", entries };
1819
+ const read = degradedRead(observed.snapshot);
1820
+ if (read === undefined)
1821
+ return { kind: "nodes", entries };
1822
+ const testId = plainTestId(this.expr);
1823
+ const lookup = testId === undefined ? undefined : await this.rt.reactLookup(testId, observed);
1824
+ if (lookup === undefined || !lookup.answered)
1825
+ return { kind: "unknown", read };
1826
+ if (lookup.matches.length === 0)
1827
+ return { kind: "nodes", entries };
1828
+ const merged = mergeReactMatches(lookup.matches, observed.index);
1829
+ return merged === undefined ? { kind: "react", matches: lookup.matches } : { kind: "nodes", entries: merged };
1830
+ }
1831
+ reactNote() {
1832
+ if (plainTestId(this.expr) === undefined)
1833
+ return "not-testid";
1834
+ return this.rt.hasReactTree() ? "unanswered" : "no-devtools";
1835
+ }
1836
+ degradedFailure(read, waitedMs, snapshot) {
1837
+ const screen = snapshot === undefined ? undefined : this.rt.excerpt(snapshot);
1838
+ return degradedFailure(this.toString(), read, waitedMs, this.reactNote(), screen);
1839
+ }
1840
+ async conclusive(options = {}) {
1841
+ const first = await this.look(options.reuse === undefined ? {} : { reuse: options.reuse });
1842
+ const settled = await this.settled(first.observed);
1843
+ if (settled !== undefined)
1844
+ return settled;
1845
+ const actionMs = this.rt.actionTimeout();
1846
+ const timeoutMs = options.quick === true ? Math.min(actionMs, QUICK_CHECK_WINDOW_MS) : actionMs;
1847
+ let last;
1848
+ const result = await this.rt.poll(async () => {
1849
+ const observation = await this.rt.tryObserve({ reuse: false });
1850
+ if (!observation.ok) {
1851
+ if (!observation.error.retryable)
1852
+ throw new E2eError2("DRIVER", `snapshot failed: ${observation.error.message}`);
1853
+ return { done: false, state: undefined };
1854
+ }
1855
+ const answer = await this.settled(observation.observed);
1856
+ if (answer !== undefined)
1857
+ return { done: true, value: answer };
1858
+ const read = degradedRead(observation.observed.snapshot);
1859
+ if (read !== undefined)
1860
+ last = { read, snapshot: observation.observed.snapshot };
1861
+ return { done: false, state: undefined };
1862
+ }, timeoutMs);
1863
+ if (result.status === "done")
1864
+ return result.value;
1865
+ const fallback = degradedRead(first.observed.snapshot);
1866
+ const read = last?.read ?? fallback;
1867
+ if (read === undefined)
1868
+ throw new E2eError2("TIMEOUT", `${this} could not be read within ${timeoutMs} ms`);
1869
+ throw this.degradedFailure(read, timeoutMs, last?.snapshot ?? first.observed.snapshot);
1870
+ }
1871
+ async settled(observed) {
1872
+ const resolved = await this.resolveIn(observed);
1873
+ if (resolved.kind === "unknown")
1874
+ return;
1875
+ if (resolved.kind === "react")
1876
+ return { entries: [], react: resolved.matches, observed };
1877
+ return { entries: resolved.entries, react: undefined, observed };
1878
+ }
1879
+ async matches() {
1880
+ const { entries, observed } = await this.conclusive();
1881
+ return { entries, observed };
1882
+ }
1883
+ reactOnly(matches, observed) {
1884
+ const [only, ...others] = matches;
1885
+ if (only !== undefined && others.length === 0)
1886
+ return only;
1887
+ throw new E2eError2("LOCATOR_AMBIGUOUS", `${this} matched ${matches.length} components in the React tree`, this.rt.excerpt(observed.snapshot), matches.length);
1670
1888
  }
1671
1889
  async single() {
1672
1890
  const { entries, observed } = await this.matches();
@@ -1686,27 +1904,58 @@ class Locator {
1686
1904
  return this.rt.span(`read.${name}`, run, { detail: () => ({ locator: this.toString() }) });
1687
1905
  }
1688
1906
  count() {
1689
- return this.traced("count", async () => (await this.matches()).entries.length);
1907
+ return this.traced("count", async () => {
1908
+ const { entries, react } = await this.conclusive({ quick: true });
1909
+ return react?.length ?? entries.length;
1910
+ });
1690
1911
  }
1691
1912
  async all() {
1692
1913
  const count = await this.count();
1693
1914
  return Array.from({ length: count }, (_, index) => this.nth(index));
1694
1915
  }
1695
1916
  text() {
1696
- return this.traced("text", async () => textOf((await this.single()).entry));
1917
+ return this.traced("text", async () => {
1918
+ const { entries, react, observed } = await this.conclusive();
1919
+ if (react !== undefined)
1920
+ return this.reactText(this.reactOnly(react, observed), observed);
1921
+ if (entries.length === 0 && (await this.reactCandidates(observed)).length > 0) {
1922
+ throw new E2eError2("NOT_ACTIONABLE", `${this} ${REACT_ONLY}`, this.rt.excerpt(observed.snapshot));
1923
+ }
1924
+ return textOf(this.exactlyOne(entries, observed));
1925
+ });
1697
1926
  }
1698
1927
  allTexts() {
1699
- return this.traced("allTexts", async () => (await this.matches()).entries.map(textOf));
1928
+ return this.traced("allTexts", async () => {
1929
+ const { entries, react, observed } = await this.conclusive();
1930
+ if (react !== undefined)
1931
+ return react.map((match) => this.reactText(match, observed));
1932
+ return entries.map(textOf);
1933
+ });
1934
+ }
1935
+ reactText(match, observed) {
1936
+ if (match.text !== undefined)
1937
+ return normalizeText(match.text);
1938
+ throw new E2eError2("NOT_ACTIONABLE", `${this} ${REACT_ONLY}`, this.rt.excerpt(observed.snapshot));
1700
1939
  }
1701
1940
  value() {
1702
1941
  return this.traced("value", async () => fieldValue((await this.single()).entry));
1703
1942
  }
1704
1943
  isVisible() {
1705
- return this.traced("isVisible", async () => this.visibleIn((await this.matches()).observed));
1944
+ return this.traced("isVisible", async () => {
1945
+ const { entries, react, observed } = await this.conclusive({ quick: true });
1946
+ if (react !== undefined)
1947
+ return reactVisible(this.reactOnly(react, observed), observed);
1948
+ return entries.length > 0 && this.exactlyOne(entries, observed).visible;
1949
+ });
1706
1950
  }
1707
1951
  read() {
1708
1952
  return this.traced("read", async () => {
1709
- const { entries, observed } = await this.matches();
1953
+ const { entries, react, observed } = await this.conclusive();
1954
+ if (react !== undefined) {
1955
+ const match = this.reactOnly(react, observed);
1956
+ const visible = reactVisible(match, observed);
1957
+ return match.text === undefined ? { visible } : { visible, text: normalizeText(match.text) };
1958
+ }
1710
1959
  if (entries.length === 0)
1711
1960
  return { visible: false };
1712
1961
  const entry = this.exactlyOne(entries, observed);
@@ -1718,11 +1967,13 @@ class Locator {
1718
1967
  };
1719
1968
  });
1720
1969
  }
1721
- visibleIn(observed) {
1722
- const entries = resolve(this.expr, observed.index);
1723
- if (entries.length === 0)
1970
+ async shownIn(observed) {
1971
+ const resolved = await this.resolveIn(observed);
1972
+ if (resolved.kind === "unknown")
1724
1973
  return false;
1725
- return this.exactlyOne(entries, observed).visible;
1974
+ if (resolved.kind === "react")
1975
+ return reactVisible(this.reactOnly(resolved.matches, observed), observed);
1976
+ return resolved.entries.length > 0 && this.exactlyOne(resolved.entries, observed).visible;
1726
1977
  }
1727
1978
  async isHidden() {
1728
1979
  return !await this.isVisible();
@@ -1735,7 +1986,7 @@ class Locator {
1735
1986
  }
1736
1987
  boundingBox() {
1737
1988
  return this.traced("boundingBox", async () => {
1738
- const { entries, observed } = await this.look({ reuse: false });
1989
+ const { entries, observed } = await this.conclusive({ reuse: false });
1739
1990
  if (entries.length === 0) {
1740
1991
  const [only, ...others] = await this.reactCandidates(observed);
1741
1992
  if (only !== undefined && others.length === 0)
@@ -1762,14 +2013,19 @@ class Locator {
1762
2013
  return { done: false, state: undefined };
1763
2014
  }
1764
2015
  const { observed } = observation;
1765
- const entries = resolve(this.expr, observed.index);
1766
- const entry = entries.length === 0 ? undefined : this.exactlyOne(entries, observed);
1767
- return reached(state, entry) ? { done: true, value: true } : { done: false, state: observed.snapshot };
2016
+ const resolved = await this.resolveIn(observed);
2017
+ if (resolved.kind === "unknown")
2018
+ return { done: false, state: { snapshot: observed.snapshot, degraded: resolved.read } };
2019
+ const done = resolved.kind === "react" ? reachedByReact(state, reactVisible(this.reactOnly(resolved.matches, observed), observed)) : reached(state, resolved.entries.length === 0 ? undefined : this.exactlyOne(resolved.entries, observed));
2020
+ return done ? { done: true, value: true } : { done: false, state: { snapshot: observed.snapshot } };
1768
2021
  }, timeoutMs);
1769
2022
  if (result.status === "done")
1770
2023
  return;
2024
+ const last = result.last;
2025
+ if (last?.degraded !== undefined)
2026
+ throw this.degradedFailure(last.degraded, timeoutMs, last.snapshot);
1771
2027
  const message = `${this} did not become ${state} within ${timeoutMs} ms`;
1772
- throw new E2eError2("TIMEOUT", message, result.last === undefined ? undefined : this.rt.excerpt(result.last));
2028
+ throw new E2eError2("TIMEOUT", message, last === undefined ? undefined : this.rt.excerpt(last.snapshot));
1773
2029
  }
1774
2030
  act(verb, run, suffix = "") {
1775
2031
  return this.rt.step(`${verb} ${this}${suffix}`, run);
@@ -1795,6 +2051,8 @@ class Locator {
1795
2051
  }
1796
2052
  if (seen?.kind === "driver")
1797
2053
  throw new E2eError2("DRIVER", `snapshot kept failing: ${seen.message}`);
2054
+ if (seen?.kind === "degraded")
2055
+ throw this.degradedFailure(seen.read, timeoutMs, seen.snapshot);
1798
2056
  throw new E2eError2("LOCATOR_NOT_FOUND", `${this} matched no elements within ${timeoutMs} ms`, seen === undefined ? undefined : this.rt.excerpt(seen.snapshot));
1799
2057
  }
1800
2058
  async actionableLook(spec, allowReact, anyFrame) {
@@ -1857,6 +2115,26 @@ class Locator {
1857
2115
  return;
1858
2116
  return { entry, observed };
1859
2117
  }
2118
+ async clearOfKeyboard(found, spec, position, timeoutMs) {
2119
+ const coverAt = (at) => coverOf(at.entry, tapPointOf(at.entry, position), at.observed.snapshot);
2120
+ let current = found;
2121
+ let cover = coverAt(current);
2122
+ if (cover === undefined)
2123
+ return found;
2124
+ const { driver } = found.observed;
2125
+ for (let scrolls = 0;cover?.scroller !== undefined && scrolls < MAX_COVER_SCROLLS; scrolls += 1) {
2126
+ const path = scrollPath(cover.scroller, cover.shift);
2127
+ this.rt.drive("scrollIntoView", await driver.swipe(path.from, path.to, COVER_SCROLL_SWIPE));
2128
+ await driver.settle(SCROLL_SETTLE);
2129
+ current = await this.actionable(spec, timeoutMs);
2130
+ cover = coverAt(current);
2131
+ }
2132
+ if (cover === undefined)
2133
+ return current;
2134
+ this.rt.drive("dismissKeyboard", await dismissKeyboard(driver));
2135
+ await driver.settle(SCROLL_SETTLE);
2136
+ return this.actionable(spec, timeoutMs);
2137
+ }
1860
2138
  async tap(options = {}) {
1861
2139
  assertOptions("tap", options, ["position", "timeout", "until", "retries", "windowMs", "pollMs"]);
1862
2140
  const retry = retryPlan(options);
@@ -1866,7 +2144,7 @@ class Locator {
1866
2144
  if (retry === undefined)
1867
2145
  return;
1868
2146
  for (let resent = 0;resent < retry.retries; resent += 1) {
1869
- const outcome = await this.arrivedWithin(retry, snapshotHash(before));
2147
+ const outcome = await this.arrivedWithin(retry, before);
1870
2148
  if (outcome !== "press-again")
1871
2149
  return;
1872
2150
  before = await this.tapOnce(options);
@@ -1876,19 +2154,31 @@ class Locator {
1876
2154
  async tapOnce(options) {
1877
2155
  const withPosition = options.position !== undefined;
1878
2156
  const spec = { enabled: !withPosition, tapPointOnScreen: !withPosition };
1879
- const found = (options.until === undefined ? await this.aimFromKept(spec, options.position) : undefined) ?? await this.actionable(spec, options.timeout ?? this.rt.actionTimeout(), true);
2157
+ const timeoutMs = options.timeout ?? this.rt.actionTimeout();
2158
+ const look = (options.until === undefined ? await this.aimFromKept(spec, options.position) : undefined) ?? await this.actionable(spec, timeoutMs, true);
2159
+ const found = "entry" in look ? await this.clearOfKeyboard(look, spec, options.position, timeoutMs) : look;
1880
2160
  const point = "react" in found ? reactTapPoint(found.react, options.position) : tapPointOf(found.entry, options.position);
1881
2161
  const { driver } = found.observed;
2162
+ const aimed = {
2163
+ snapshot: found.observed.snapshot,
2164
+ target: "entry" in found ? found.entry.element : undefined
2165
+ };
1882
2166
  if (!withPosition && "entry" in found && canActOnElements(driver)) {
1883
2167
  if (this.rt.drive("tap", await driver.pressElement(found.entry.element)))
1884
- return found.observed.snapshot;
2168
+ return aimed;
1885
2169
  }
1886
2170
  this.rt.drive("tap", await driver.tap(point));
1887
- return found.observed.snapshot;
2171
+ return aimed;
1888
2172
  }
1889
- async arrivedWithin(plan, pressedOn) {
2173
+ async arrivedWithin(plan, aimed) {
1890
2174
  const { until } = plan;
1891
- const watch = { pressedOn, started: this.rt.clock.now(), changed: false, unchanged: 0 };
2175
+ const watch = {
2176
+ before: new Set(aimed.snapshot.flat.map(elementKey)),
2177
+ target: aimed.target === undefined ? undefined : elementKey(aimed.target),
2178
+ started: this.rt.clock.now(),
2179
+ changed: false,
2180
+ unchanged: 0
2181
+ };
1892
2182
  const result = await this.rt.poll(async (attempt) => {
1893
2183
  if (typeof until !== "function")
1894
2184
  return this.checkLocatorUntil(until, watch, attempt);
@@ -1909,9 +2199,9 @@ class Locator {
1909
2199
  watch.unchanged = 0;
1910
2200
  return { done: false, state: undefined };
1911
2201
  }
1912
- if (until.visibleIn(observation.observed))
2202
+ if (await until.shownIn(observation.observed))
1913
2203
  return { done: true, value: "arrived" };
1914
- if (snapshotHash(observation.observed.snapshot) === watch.pressedOn)
2204
+ if (!reacted(observation.observed.snapshot, watch))
1915
2205
  watch.unchanged += 1;
1916
2206
  else {
1917
2207
  watch.changed = true;
@@ -1923,7 +2213,9 @@ class Locator {
1923
2213
  async longPress(options = {}) {
1924
2214
  assertOptions("longPress", options, ["durationMs", "timeout"]);
1925
2215
  return this.act("longPress", async () => {
1926
- const { entry, observed } = await this.actionable({ enabled: true, tapPointOnScreen: true }, options.timeout ?? this.rt.actionTimeout());
2216
+ const spec = { enabled: true, tapPointOnScreen: true };
2217
+ const timeoutMs = options.timeout ?? this.rt.actionTimeout();
2218
+ const { entry, observed } = await this.clearOfKeyboard(await this.actionable(spec, timeoutMs), spec, undefined, timeoutMs);
1927
2219
  const opts = options.durationMs === undefined ? undefined : { durationMs: options.durationMs };
1928
2220
  this.rt.drive("longPress", await observed.driver.longPress(tapPointOf(entry), opts));
1929
2221
  });
@@ -1934,18 +2226,18 @@ class Locator {
1934
2226
  return this.act("fill", async () => {
1935
2227
  const budget = this.rt.budget(options.timeout);
1936
2228
  let target = await this.actionable({ enabled: true, tapPointOnScreen: false }, budget.remaining());
2229
+ const verify = !target.entry.secure;
1937
2230
  let firstHeld;
1938
2231
  for (let attempt = 1;; attempt += 1) {
1939
2232
  const point = focusPoint(target.entry.element.frame);
1940
2233
  this.rt.drive("fill", await focusClearType(target.observed.driver, this.pause, point, target.entry, text, clearMethodFor(attempt), process.env, viaFor(attempt, via)));
1941
- if (target.entry.secure)
2234
+ if (!verify)
1942
2235
  return;
1943
2236
  const outcome = await this.confirm(target, text, budget);
1944
2237
  if (outcome.ok)
1945
2238
  return;
1946
2239
  if (attempt === 2) {
1947
- const earlier = firstHeld === undefined ? "" : ` (first attempt held ${JSON.stringify(firstHeld)})`;
1948
- throw new E2eError2("ACTION_FAILED", `${this}: fill did not take: expected ${JSON.stringify(text)} but the field holds ${JSON.stringify(outcome.held)}${earlier}`, outcome.screen);
2240
+ throw new E2eError2("ACTION_FAILED", `${this}: ${fillMismatch(text, target.entry.secure, outcome.held, firstHeld)}`, outcome.screen);
1949
2241
  }
1950
2242
  firstHeld = outcome.held;
1951
2243
  target = await this.actionable({ enabled: true, tapPointOnScreen: false }, budget.remaining());
@@ -2034,10 +2326,17 @@ class Locator {
2034
2326
  return scrollUntilVisible(this.rt, this, options);
2035
2327
  }
2036
2328
  async reactStep(spec, observed, allowReact) {
2037
- const found = await this.reactCandidates(observed);
2329
+ const read = degradedRead(observed.snapshot);
2330
+ const testId = plainTestId(this.expr);
2331
+ const lookup = testId === undefined ? undefined : await this.rt.reactLookup(testId, observed);
2332
+ const found = lookup?.answered === true ? lookup.matches : [];
2038
2333
  const [match, ...others] = found;
2039
- if (match === undefined)
2334
+ if (match === undefined) {
2335
+ if (read !== undefined && lookup?.answered !== true) {
2336
+ return { done: false, state: { kind: "degraded", read, snapshot: observed.snapshot } };
2337
+ }
2040
2338
  return { done: false, state: { kind: "none", snapshot: observed.snapshot } };
2339
+ }
2041
2340
  if (!allowReact)
2042
2341
  return { done: false, state: { kind: "react", snapshot: observed.snapshot, matches: found.length } };
2043
2342
  if (others.length > 0) {
@@ -2061,7 +2360,11 @@ class Locator {
2061
2360
  async confirm({ entry, observed }, text, budget) {
2062
2361
  const span = Math.max(budget.remaining(), CONFIRM_FLOOR_MS);
2063
2362
  let lastSeen;
2064
- const readValue = (found) => text === "" ? fieldValue(found) : rawValue(found);
2363
+ const readValue = (found) => {
2364
+ if (text === "")
2365
+ return fieldValue(found);
2366
+ return found.secure ? maskedReading(found, text) : rawValue(found);
2367
+ };
2065
2368
  const outcome = await confirmFieldValue({
2066
2369
  text,
2067
2370
  now: this.rt.clock.now,
@@ -2119,6 +2422,16 @@ var TAP_WINDOW_MS = 4000;
2119
2422
  var TAP_CHECK_MS = 250;
2120
2423
  var UNCHANGED_CHECKS = 2;
2121
2424
  var UNCHANGED_AFTER_MS = 750;
2425
+ function reacted(snapshot, watch) {
2426
+ const now = new Set;
2427
+ for (const element of snapshot.flat) {
2428
+ const key = elementKey(element);
2429
+ if (!watch.before.has(key))
2430
+ return true;
2431
+ now.add(key);
2432
+ }
2433
+ return watch.target !== undefined && !now.has(watch.target);
2434
+ }
2122
2435
  function wholeNumber(name, value, atLeast) {
2123
2436
  if (!Number.isInteger(value) || value < atLeast) {
2124
2437
  throw new E2eError2("INVALID_ARGUMENT", `tap ${name} must be an integer of at least ${atLeast}, got ${String(value)}`);
@@ -2161,6 +2474,11 @@ function viaFor(attempt, via) {
2161
2474
  function clearMethodFor(attempt) {
2162
2475
  return attempt === 1 ? "auto" : "counted";
2163
2476
  }
2477
+ function fillMismatch(text, secure, held, firstHeld) {
2478
+ const expected = secure ? `${graphemes(text)} characters (secure)` : JSON.stringify(text);
2479
+ const earlier = firstHeld === undefined ? "" : ` (first attempt held ${JSON.stringify(firstHeld)})`;
2480
+ return `fill did not take: expected ${expected} but the field holds ${JSON.stringify(held)}${earlier}`;
2481
+ }
2164
2482
  function rawValue(entry) {
2165
2483
  return entry.value ?? (entry.role === "textbox" || entry.role === "searchbox" ? entry.element.text ?? "" : "");
2166
2484
  }
@@ -2176,6 +2494,18 @@ function reached(state, entry) {
2176
2494
  return entry === undefined || !entry.visible;
2177
2495
  }
2178
2496
  }
2497
+ function reachedByReact(state, visible) {
2498
+ switch (state) {
2499
+ case "attached":
2500
+ return true;
2501
+ case "detached":
2502
+ return false;
2503
+ case "visible":
2504
+ return visible;
2505
+ case "hidden":
2506
+ return !visible;
2507
+ }
2508
+ }
2179
2509
  function blockedReason(entry, spec, observed) {
2180
2510
  if (!entry.visible)
2181
2511
  return "is not visible";
@@ -2189,7 +2519,11 @@ function blockedReason(entry, spec, observed) {
2189
2519
  function isOnScreenEntry(entry, observed) {
2190
2520
  return entry?.visible === true && isOnScreen(tapPointOf(entry), observed.snapshot.screen);
2191
2521
  }
2192
- function scrollGaveUp(target, absent, effort, screen) {
2522
+ function scrollGaveUp(target, absent, effort, observed, waitedMs) {
2523
+ const read = absent ? degradedRead(observed.snapshot) : undefined;
2524
+ if (read !== undefined)
2525
+ return target.degradedFailure(read, waitedMs, observed.snapshot);
2526
+ const screen = target.runtime.excerpt(observed.snapshot);
2193
2527
  if (absent)
2194
2528
  return new E2eError2("LOCATOR_NOT_FOUND", `${target} was not found after ${effort}`, screen);
2195
2529
  return new E2eError2("NOT_ACTIONABLE", `${target} is still not on screen after ${effort}`, screen);
@@ -2218,7 +2552,8 @@ async function scrollUntilVisible(rt, target, options = {}) {
2218
2552
  if (isOnScreenEntry(entry, observed))
2219
2553
  return;
2220
2554
  if (swipes >= maxSwipes || budget.remaining() <= 0) {
2221
- throw scrollGaveUp(target, entry === undefined, `${swipes} swipes ${direction}`, rt.excerpt(observed.snapshot));
2555
+ const effort = `${swipes} swipes ${direction}`;
2556
+ throw scrollGaveUp(target, entry === undefined, effort, observed, budget.total);
2222
2557
  }
2223
2558
  await scrollOnce(rt, observed, direction, options.momentum);
2224
2559
  await observed.driver.settle(SCROLL_SETTLE);
@@ -2288,7 +2623,7 @@ function describeException(details) {
2288
2623
  return String(thrown.value);
2289
2624
  return details.text ?? "JS exception";
2290
2625
  }
2291
- function textOf2(data) {
2626
+ function textOf3(data) {
2292
2627
  if (typeof data === "string")
2293
2628
  return data;
2294
2629
  if (data instanceof ArrayBuffer)
@@ -2311,7 +2646,7 @@ function taggedBindingPayload(params) {
2311
2646
  return tagged.success ? { requestId: tagged.data.requestId, payload } : undefined;
2312
2647
  }
2313
2648
  function parseEnvelope(data) {
2314
- const text = textOf2(data);
2649
+ const text = textOf3(data);
2315
2650
  if (text === undefined)
2316
2651
  return;
2317
2652
  let json;
@@ -4346,6 +4681,14 @@ async function captureNativeLog(target, deps, win) {
4346
4681
  }
4347
4682
  }
4348
4683
 
4684
+ // ../../packages/e2e/src/driver/ax-wedge.ts
4685
+ function canRecoverAxWedge(driver) {
4686
+ return typeof driver.axWedge === "function";
4687
+ }
4688
+ function restartedWithin(state, windowMs) {
4689
+ return state.last?.outcome === "restarted" && state.last.agoMs <= windowMs;
4690
+ }
4691
+
4349
4692
  // ../../packages/e2e/src/driver/ios/hid-recovery.ts
4350
4693
  import { existsSync as existsSync2 } from "fs";
4351
4694
 
@@ -4421,19 +4764,133 @@ function driverErr(code, message, extra) {
4421
4764
  }
4422
4765
 
4423
4766
  // ../../packages/e2e/src/driver/ios/simd-protocol.ts
4767
+ import { z as z7 } from "zod";
4768
+
4769
+ // ../../packages/e2e/src/driver/bridge-stall.ts
4424
4770
  import { z as z6 } from "zod";
4771
+ var bridgeStallSchema = z6.looseObject({
4772
+ stage: z6.string(),
4773
+ readMs: z6.number().optional(),
4774
+ deadlineMs: z6.number().optional(),
4775
+ guestAgeMs: z6.number().optional(),
4776
+ cold: z6.boolean(),
4777
+ cooldownRemainingMs: z6.number().optional(),
4778
+ probes: z6.number(),
4779
+ recycles: z6.number().optional(),
4780
+ recyclesExhausted: z6.boolean().optional(),
4781
+ axWedge: z6.string().optional(),
4782
+ axWedgeRestarts: z6.number().optional()
4783
+ });
4784
+ var SPAN_FIELDS = [
4785
+ ["stallStage", "stage"],
4786
+ ["stallReadMs", "readMs"],
4787
+ ["stallDeadlineMs", "deadlineMs"],
4788
+ ["stallGuestAgeMs", "guestAgeMs"],
4789
+ ["stallCold", "cold"],
4790
+ ["stallCooldownMs", "cooldownRemainingMs"],
4791
+ ["stallProbes", "probes"],
4792
+ ["stallRecycles", "recycles"],
4793
+ ["stallRecyclesExhausted", "recyclesExhausted"],
4794
+ ["stallAxWedge", "axWedge"],
4795
+ ["stallAxWedgeRestarts", "axWedgeRestarts"]
4796
+ ];
4797
+ function toBridgeStall(wire) {
4798
+ const stall = { stage: wire.stage, cold: wire.cold, probes: wire.probes };
4799
+ if (wire.readMs !== undefined)
4800
+ stall.readMs = wire.readMs;
4801
+ if (wire.deadlineMs !== undefined)
4802
+ stall.deadlineMs = wire.deadlineMs;
4803
+ if (wire.guestAgeMs !== undefined)
4804
+ stall.guestAgeMs = wire.guestAgeMs;
4805
+ if (wire.cooldownRemainingMs !== undefined)
4806
+ stall.cooldownRemainingMs = wire.cooldownRemainingMs;
4807
+ if (wire.recycles !== undefined)
4808
+ stall.recycles = wire.recycles;
4809
+ if (wire.recyclesExhausted !== undefined)
4810
+ stall.recyclesExhausted = wire.recyclesExhausted;
4811
+ if (wire.axWedge !== undefined)
4812
+ stall.axWedge = wire.axWedge;
4813
+ if (wire.axWedgeRestarts !== undefined)
4814
+ stall.axWedgeRestarts = wire.axWedgeRestarts;
4815
+ return stall;
4816
+ }
4817
+ function noteBridgeStall(stall) {
4818
+ for (const [key, field] of SPAN_FIELDS) {
4819
+ const value = stall[field];
4820
+ if (value !== undefined)
4821
+ noteSpanDetail(key, value);
4822
+ }
4823
+ }
4824
+ function bridgeStallFromSpan(detail) {
4825
+ const stage = detail?.stallStage;
4826
+ if (detail === undefined || typeof stage !== "string")
4827
+ return;
4828
+ const stall = {
4829
+ stage,
4830
+ cold: detail.stallCold === true,
4831
+ probes: typeof detail.stallProbes === "number" ? detail.stallProbes : 0
4832
+ };
4833
+ const numbers = [
4834
+ ["stallReadMs", "readMs"],
4835
+ ["stallDeadlineMs", "deadlineMs"],
4836
+ ["stallGuestAgeMs", "guestAgeMs"],
4837
+ ["stallCooldownMs", "cooldownRemainingMs"],
4838
+ ["stallRecycles", "recycles"],
4839
+ ["stallAxWedgeRestarts", "axWedgeRestarts"]
4840
+ ];
4841
+ for (const [key, field] of numbers) {
4842
+ const value = detail[key];
4843
+ if (typeof value === "number")
4844
+ stall[field] = value;
4845
+ }
4846
+ if (typeof detail.stallRecyclesExhausted === "boolean")
4847
+ stall.recyclesExhausted = detail.stallRecyclesExhausted;
4848
+ if (typeof detail.stallAxWedge === "string")
4849
+ stall.axWedge = detail.stallAxWedge;
4850
+ return stall;
4851
+ }
4852
+ var seconds = (ms) => `${(ms / 1000).toFixed(1)} s`;
4853
+ function axWedgeParts(stall) {
4854
+ const parts = [];
4855
+ if (stall.axWedge === "checking")
4856
+ parts.push("both readers silent: checking for a wedged accessibility service");
4857
+ if (stall.axWedgeRestarts !== undefined) {
4858
+ parts.push(`backboardd restarted ${stall.axWedgeRestarts} time${stall.axWedgeRestarts === 1 ? "" : "s"}`);
4859
+ }
4860
+ return parts;
4861
+ }
4862
+ function formatBridgeStall(stall) {
4863
+ const parts = [`stage ${stall.stage}`];
4864
+ if (stall.readMs !== undefined) {
4865
+ parts.push(stall.deadlineMs === undefined ? `read ${stall.readMs} ms` : `read ${stall.readMs} ms of a ${stall.deadlineMs} ms deadline`);
4866
+ } else if (stall.deadlineMs !== undefined)
4867
+ parts.push(`${stall.deadlineMs} ms deadline`);
4868
+ parts.push(stall.cold ? "cold (first read)" : "warm");
4869
+ if (stall.guestAgeMs !== undefined)
4870
+ parts.push(`guest ${seconds(stall.guestAgeMs)} old`);
4871
+ if (stall.cooldownRemainingMs !== undefined)
4872
+ parts.push(`cooldown ${seconds(stall.cooldownRemainingMs)} left`);
4873
+ parts.push(`${stall.probes} failed bridge reads in a row`);
4874
+ if (stall.recycles !== undefined) {
4875
+ const guests = stall.recycles === 1 ? "guest" : "guests";
4876
+ parts.push(`${stall.recycles} stalled ${guests} recycled${stall.recyclesExhausted === true ? ", none left" : ""}`);
4877
+ }
4878
+ return [...parts, ...axWedgeParts(stall)].join(" \xB7 ");
4879
+ }
4880
+
4881
+ // ../../packages/e2e/src/driver/ios/simd-protocol.ts
4425
4882
  var protocolVersion = 1;
4426
- var rectSchema2 = z6.object({
4427
- x: z6.number(),
4428
- y: z6.number(),
4429
- width: z6.number(),
4430
- height: z6.number()
4883
+ var rectSchema2 = z7.object({
4884
+ x: z7.number(),
4885
+ y: z7.number(),
4886
+ width: z7.number(),
4887
+ height: z7.number()
4431
4888
  });
4432
- var screenInfoSchema = z6.object({
4433
- width: z6.number(),
4434
- height: z6.number(),
4435
- scale: z6.number(),
4436
- rotation: z6.number().optional()
4889
+ var screenInfoSchema = z7.object({
4890
+ width: z7.number(),
4891
+ height: z7.number(),
4892
+ scale: z7.number(),
4893
+ rotation: z7.number().optional()
4437
4894
  });
4438
4895
  var ROLES = [
4439
4896
  "button",
@@ -4460,29 +4917,29 @@ var ROLES = [
4460
4917
  "application",
4461
4918
  "other"
4462
4919
  ];
4463
- var pointSchema = z6.object({ x: z6.number(), y: z6.number() });
4464
- var wireElementSchema = z6.lazy(() => z6.object({
4465
- id: z6.string().nullish(),
4466
- role: z6.enum(ROLES),
4467
- rawType: z6.string(),
4468
- label: z6.string().nullish(),
4469
- identifier: z6.string().nullish(),
4470
- value: z6.string().nullish(),
4471
- text: z6.string().nullish(),
4472
- placeholder: z6.string().nullish(),
4920
+ var pointSchema = z7.object({ x: z7.number(), y: z7.number() });
4921
+ var wireElementSchema = z7.lazy(() => z7.object({
4922
+ id: z7.string().nullish(),
4923
+ role: z7.enum(ROLES),
4924
+ rawType: z7.string(),
4925
+ label: z7.string().nullish(),
4926
+ identifier: z7.string().nullish(),
4927
+ value: z7.string().nullish(),
4928
+ text: z7.string().nullish(),
4929
+ placeholder: z7.string().nullish(),
4473
4930
  frame: rectSchema2,
4474
4931
  normFrame: rectSchema2.nullish(),
4475
- traits: z6.array(z6.string()).nullish(),
4476
- enabled: z6.boolean().nullish(),
4477
- focused: z6.boolean().nullish(),
4478
- hidden: z6.boolean().nullish(),
4479
- selected: z6.boolean().nullish(),
4480
- checked: z6.boolean().nullish(),
4481
- hittable: z6.boolean().nullish(),
4932
+ traits: z7.array(z7.string()).nullish(),
4933
+ enabled: z7.boolean().nullish(),
4934
+ focused: z7.boolean().nullish(),
4935
+ hidden: z7.boolean().nullish(),
4936
+ selected: z7.boolean().nullish(),
4937
+ checked: z7.boolean().nullish(),
4938
+ hittable: z7.boolean().nullish(),
4482
4939
  tapPoint: pointSchema.nullish(),
4483
- pid: z6.number().nullish(),
4484
- depth: z6.number().nullish(),
4485
- children: z6.array(wireElementSchema).nullish()
4940
+ pid: z7.number().nullish(),
4941
+ depth: z7.number().nullish(),
4942
+ children: z7.array(wireElementSchema).nullish()
4486
4943
  }));
4487
4944
  var ROLE_SET = new Set(ROLES);
4488
4945
  var isBag = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -4520,33 +4977,33 @@ function wireElementProblem(value) {
4520
4977
  const issue = parsed.error.issues[0];
4521
4978
  return issue ? `${issue.path.join(".") || "(element)"}: ${issue.message}` : "invalid element";
4522
4979
  }
4523
- var wireErrorSchema = z6.object({
4524
- code: z6.string(),
4525
- message: z6.string(),
4526
- retryable: z6.boolean().optional(),
4527
- detail: z6.unknown().optional()
4980
+ var wireErrorSchema = z7.object({
4981
+ code: z7.string(),
4982
+ message: z7.string(),
4983
+ retryable: z7.boolean().optional(),
4984
+ detail: z7.unknown().optional()
4528
4985
  });
4529
- var readyEventSchema = z6.object({
4530
- event: z6.literal("ready"),
4531
- protocol: z6.number(),
4532
- version: z6.string(),
4533
- udid: z6.string(),
4534
- hid: z6.object({ transport: z6.string() }),
4535
- ax: z6.object({ default: z6.string(), bridge: z6.string() }),
4986
+ var readyEventSchema = z7.object({
4987
+ event: z7.literal("ready"),
4988
+ protocol: z7.number(),
4989
+ version: z7.string(),
4990
+ udid: z7.string(),
4991
+ hid: z7.object({ transport: z7.string() }),
4992
+ ax: z7.object({ default: z7.string(), bridge: z7.string() }),
4536
4993
  screen: screenInfoSchema
4537
4994
  });
4538
- var logEventSchema = z6.object({
4539
- event: z6.literal("log"),
4540
- level: z6.enum(["debug", "info", "warn", "error"]),
4541
- message: z6.string(),
4542
- op: z6.string().optional(),
4543
- id: z6.string().optional()
4995
+ var logEventSchema = z7.object({
4996
+ event: z7.literal("log"),
4997
+ level: z7.enum(["debug", "info", "warn", "error"]),
4998
+ message: z7.string(),
4999
+ op: z7.string().optional(),
5000
+ id: z7.string().optional()
4544
5001
  });
4545
- var fatalEventSchema = z6.object({ event: z6.literal("fatal"), error: wireErrorSchema });
4546
- var eventSchema = z6.discriminatedUnion("event", [readyEventSchema, logEventSchema, fatalEventSchema]);
4547
- var responseSchema = z6.discriminatedUnion("ok", [
4548
- z6.object({ id: z6.string(), ok: z6.literal(true), data: z6.unknown().optional() }),
4549
- z6.object({ id: z6.string(), ok: z6.literal(false), error: wireErrorSchema })
5002
+ var fatalEventSchema = z7.object({ event: z7.literal("fatal"), error: wireErrorSchema });
5003
+ var eventSchema = z7.discriminatedUnion("event", [readyEventSchema, logEventSchema, fatalEventSchema]);
5004
+ var responseSchema = z7.discriminatedUnion("ok", [
5005
+ z7.object({ id: z7.string(), ok: z7.literal(true), data: z7.unknown().optional() }),
5006
+ z7.object({ id: z7.string(), ok: z7.literal(false), error: wireErrorSchema })
4550
5007
  ]);
4551
5008
  function parseLine(line) {
4552
5009
  let json;
@@ -4562,74 +5019,81 @@ function parseLine(line) {
4562
5019
  const response = responseSchema.safeParse(json);
4563
5020
  return response.success ? { success: true, message: { kind: "response", response: response.data } } : { success: false, reason: `bad response: ${response.error.message}` };
4564
5021
  }
4565
- var healthDataSchema = z6.looseObject({
4566
- version: z6.string(),
4567
- udid: z6.string(),
4568
- hid: z6.object({ transport: z6.string() }),
4569
- ax: z6.object({
4570
- default: z6.string(),
4571
- bridge: z6.enum(["available", "degraded", "missing", "failed"]),
4572
- error: z6.string().optional(),
4573
- lastError: z6.object({ message: z6.string(), agoMs: z6.number() }).optional()
5022
+ var healthDataSchema = z7.looseObject({
5023
+ version: z7.string(),
5024
+ udid: z7.string(),
5025
+ hid: z7.object({ transport: z7.string() }),
5026
+ ax: z7.object({
5027
+ default: z7.string(),
5028
+ bridge: z7.enum(["available", "degraded", "missing", "failed"]),
5029
+ error: z7.string().optional(),
5030
+ lastError: z7.object({ message: z7.string(), agoMs: z7.number() }).optional()
4574
5031
  }),
4575
5032
  screen: screenInfoSchema,
4576
- socket: z6.object({ path: z6.string(), clients: z6.number() }).optional(),
4577
- idb: z6.string().optional(),
4578
- xcode: z6.string().optional(),
4579
- builtWith: z6.object({ xcode: z6.string().optional(), idb: z6.string().optional() }).optional(),
4580
- coreSimulatorVersion: z6.string().nullish(),
4581
- frontmost: z6.object({ unresolvedAgoMs: z6.number(), method: z6.string() }).optional(),
4582
- state: z6.string().optional(),
4583
- uptimeMs: z6.number().optional()
5033
+ socket: z7.object({ path: z7.string(), clients: z7.number() }).optional(),
5034
+ idb: z7.string().optional(),
5035
+ xcode: z7.string().optional(),
5036
+ builtWith: z7.object({ xcode: z7.string().optional(), idb: z7.string().optional() }).optional(),
5037
+ coreSimulatorVersion: z7.string().nullish(),
5038
+ frontmost: z7.object({ unresolvedAgoMs: z7.number(), method: z7.string() }).optional(),
5039
+ bridgeRecycles: z7.object({ count: z7.number(), exhausted: z7.boolean() }).optional(),
5040
+ axWedge: z7.lazy(() => axWedgeDataSchema).optional(),
5041
+ state: z7.string().optional(),
5042
+ uptimeMs: z7.number().optional()
4584
5043
  });
4585
- var snapshotDataSchema = z6.looseObject({
4586
- backend: z6.enum(["axbridge", "ax", "uiautomator"]),
5044
+ var snapshotDataSchema = z7.looseObject({
5045
+ backend: z7.enum(["axbridge", "ax", "uiautomator"]),
4587
5046
  screen: screenInfoSchema,
4588
- modal: z6.object({ pid: z6.number().optional(), description: z6.string().optional() }).nullish(),
4589
- truncated: z6.boolean(),
4590
- elements: z6.array(z6.custom(isWireElement, { error: (issue) => wireElementProblem(issue.input) })),
4591
- ms: z6.number(),
4592
- fallback: z6.object({ from: z6.string(), to: z6.string(), reason: z6.string() }).optional(),
4593
- target: z6.object({ pid: z6.number(), source: z6.string() }).optional(),
4594
- readMs: z6.number().optional(),
4595
- nodes: z6.number().optional()
5047
+ modal: z7.object({ pid: z7.number().optional(), description: z7.string().optional() }).nullish(),
5048
+ truncated: z7.boolean(),
5049
+ elements: z7.array(z7.custom(isWireElement, { error: (issue) => wireElementProblem(issue.input) })),
5050
+ ms: z7.number(),
5051
+ fallback: z7.object({
5052
+ from: z7.string(),
5053
+ to: z7.string(),
5054
+ reason: z7.string(),
5055
+ stall: bridgeStallSchema.optional()
5056
+ }).optional(),
5057
+ target: z7.object({ pid: z7.number(), source: z7.string() }).optional(),
5058
+ readMs: z7.number().optional(),
5059
+ nodes: z7.number().optional()
4596
5060
  });
4597
5061
  var elementAtPointDataSchema = wireElementSchema.nullable();
4598
- var screenshotDataSchema = z6.looseObject({
4599
- path: z6.string().optional(),
4600
- png: z6.string().optional(),
4601
- width: z6.number().optional(),
4602
- height: z6.number().optional()
5062
+ var screenshotDataSchema = z7.looseObject({
5063
+ path: z7.string().optional(),
5064
+ png: z7.string().optional(),
5065
+ width: z7.number().optional(),
5066
+ height: z7.number().optional()
4603
5067
  });
4604
- var settleDataSchema = z6.looseObject({
4605
- quiet: z6.boolean(),
4606
- waitedMs: z6.number(),
4607
- via: z6.enum(["stream", "snapshot"]).optional().catch(undefined),
4608
- reason: z6.string().optional(),
4609
- frontmostPid: z6.number().optional()
5068
+ var settleDataSchema = z7.looseObject({
5069
+ quiet: z7.boolean(),
5070
+ waitedMs: z7.number(),
5071
+ via: z7.enum(["stream", "snapshot"]).optional().catch(undefined),
5072
+ reason: z7.string().optional(),
5073
+ frontmostPid: z7.number().optional()
4610
5074
  });
4611
- var rebindDataSchema = z6.looseObject({
4612
- bound: z6.boolean(),
4613
- waitedMs: z6.number(),
4614
- pid: z6.number().optional(),
4615
- restarts: z6.number().optional(),
4616
- recycled: z6.boolean().optional(),
4617
- reason: z6.string().optional()
5075
+ var rebindDataSchema = z7.looseObject({
5076
+ bound: z7.boolean(),
5077
+ waitedMs: z7.number(),
5078
+ pid: z7.number().optional(),
5079
+ restarts: z7.number().optional(),
5080
+ recycled: z7.boolean().optional(),
5081
+ reason: z7.string().optional()
4618
5082
  });
4619
- var alertButtonsDataSchema = z6.object({
4620
- title: z6.string().optional(),
4621
- message: z6.string().optional(),
4622
- buttons: z6.array(wireElementSchema)
5083
+ var alertButtonsDataSchema = z7.object({
5084
+ title: z7.string().optional(),
5085
+ message: z7.string().optional(),
5086
+ buttons: z7.array(wireElementSchema)
4623
5087
  }).nullable();
4624
- var frontmostDataSchema = z6.looseObject({
4625
- frontmost: z6.boolean(),
4626
- pid: z6.number().optional(),
4627
- frontmostPid: z6.number().optional()
5088
+ var frontmostDataSchema = z7.looseObject({
5089
+ frontmost: z7.boolean(),
5090
+ pid: z7.number().optional(),
5091
+ frontmostPid: z7.number().optional()
4628
5092
  });
4629
- var launchDataSchema = z6.looseObject({ pid: z6.number() });
4630
- var terminateDataSchema = z6.looseObject({ terminated: z6.boolean() });
4631
- var orientationDataSchema = z6.object({
4632
- orientation: z6.enum([
5093
+ var launchDataSchema = z7.looseObject({ pid: z7.number() });
5094
+ var terminateDataSchema = z7.looseObject({ terminated: z7.boolean() });
5095
+ var orientationDataSchema = z7.object({
5096
+ orientation: z7.enum([
4633
5097
  "portrait",
4634
5098
  "portraitUpsideDown",
4635
5099
  "landscapeLeft",
@@ -4638,7 +5102,18 @@ var orientationDataSchema = z6.object({
4638
5102
  "faceDown",
4639
5103
  "unknown"
4640
5104
  ]),
4641
- source: z6.enum(["device", "written", "assumed"]).optional()
5105
+ source: z7.enum(["device", "written", "assumed"]).optional()
5106
+ });
5107
+ var axWedgeDataSchema = z7.looseObject({
5108
+ restarts: z7.number(),
5109
+ maxRestarts: z7.number(),
5110
+ recovering: z7.boolean(),
5111
+ checked: z7.enum(["restarted", "not-wedged", "failed"]).optional(),
5112
+ last: z7.discriminatedUnion("outcome", [
5113
+ z7.looseObject({ outcome: z7.literal("restarted"), agoMs: z7.number(), ms: z7.number().optional() }),
5114
+ z7.looseObject({ outcome: z7.literal("not-wedged"), agoMs: z7.number() }),
5115
+ z7.looseObject({ outcome: z7.literal("failed"), agoMs: z7.number(), error: z7.string() })
5116
+ ]).optional()
4642
5117
  });
4643
5118
  var opSchemas = {
4644
5119
  health: healthDataSchema,
@@ -4651,7 +5126,8 @@ var opSchemas = {
4651
5126
  frontmost: frontmostDataSchema,
4652
5127
  orientation: orientationDataSchema,
4653
5128
  launch: launchDataSchema,
4654
- terminate: terminateDataSchema
5129
+ terminate: terminateDataSchema,
5130
+ axWedge: axWedgeDataSchema
4655
5131
  };
4656
5132
  function hasOpSchema(op) {
4657
5133
  return Object.hasOwn(opSchemas, op);
@@ -5079,7 +5555,7 @@ async function createSimdClient(factory, options = {}) {
5079
5555
  const transport = session.data.transport;
5080
5556
  if (!transport)
5081
5557
  return { success: false, error: driverError("E_INTERNAL", "warden-simd transport missing") };
5082
- const timeoutMs = opts.timeoutMs ?? defaultTimeoutMs;
5558
+ const timeoutMs = Math.max(opts.timeoutMs ?? defaultTimeoutMs, opts.minTimeoutMs ?? 0);
5083
5559
  const id = String(++seq);
5084
5560
  const result = await new Promise((resolve) => {
5085
5561
  const timer = setTimeout(() => {
@@ -5342,7 +5818,7 @@ function traceDriver(driver, options) {
5342
5818
  }
5343
5819
 
5344
5820
  // ../../packages/core/src/a11y/a11y.config.ts
5345
- import { z as z7 } from "zod";
5821
+ import { z as z8 } from "zod";
5346
5822
  var A11Y_RULE_IDS = [
5347
5823
  "missing-name",
5348
5824
  "image-no-name",
@@ -5355,11 +5831,11 @@ var A11Y_RULE_IDS = [
5355
5831
  "text-clipped",
5356
5832
  "native"
5357
5833
  ];
5358
- var ruleId = z7.enum(A11Y_RULE_IDS);
5359
- var a11yAuditConfigSchema = z7.object({
5360
- ignore: z7.array(z7.object({ rule: ruleId, identifier: z7.string().min(1).optional() }).strict()).optional(),
5361
- minSeverity: z7.enum(["error", "warning"]).optional(),
5362
- rules: z7.array(ruleId).min(1).optional()
5834
+ var ruleId = z8.enum(A11Y_RULE_IDS);
5835
+ var a11yAuditConfigSchema = z8.object({
5836
+ ignore: z8.array(z8.object({ rule: ruleId, identifier: z8.string().min(1).optional() }).strict()).optional(),
5837
+ minSeverity: z8.enum(["error", "warning"]).optional(),
5838
+ rules: z8.array(ruleId).min(1).optional()
5363
5839
  }).strict();
5364
5840
  function parseA11yAuditEnv(raw) {
5365
5841
  let json;
@@ -5375,7 +5851,7 @@ function parseA11yAuditEnv(raw) {
5375
5851
  }
5376
5852
 
5377
5853
  // ../../packages/core/src/conditions/conditions.config.ts
5378
- import { z as z8 } from "zod";
5854
+ import { z as z9 } from "zod";
5379
5855
 
5380
5856
  // ../../packages/core/src/duration.ts
5381
5857
  var UNIT_MS = { ms: 1, s: 1000, m: 60000, h: 3600000, d: 86400000 };
@@ -5417,6 +5893,10 @@ var TEXT_SIZE_NAMES = [
5417
5893
  "accessibility-extra-extra-large",
5418
5894
  "accessibility-extra-extra-extra-large"
5419
5895
  ];
5896
+ var KEYBOARD_MODES = ["software", "hardware"];
5897
+ var DEFAULT_KEYBOARD_MODE = "software";
5898
+ var IME_STASH_ENABLED = "warden_ime_enabled";
5899
+ var IME_STASH_DEFAULT = "warden_ime_default";
5420
5900
  var CAMERA_FACINGS = ["back", "front"];
5421
5901
  var CONDITION_AREAS = [
5422
5902
  "network",
@@ -5426,7 +5906,8 @@ var CONDITION_AREAS = [
5426
5906
  "locale",
5427
5907
  "a11y",
5428
5908
  "battery",
5429
- "camera"
5909
+ "camera",
5910
+ "keyboard"
5430
5911
  ];
5431
5912
 
5432
5913
  // ../../packages/core/src/conditions/network.presets.ts
@@ -5536,51 +6017,52 @@ function appliedA11y(op, applied) {
5536
6017
 
5537
6018
  // ../../packages/core/src/conditions/conditions.config.ts
5538
6019
  var NETWORK_WORDS = ["online", "offline", ...NETWORK_PRESET_NAMES];
5539
- var nonNegative2 = z8.number().nonnegative().finite();
5540
- var customNetworkSchema = z8.object({
6020
+ var nonNegative2 = z9.number().nonnegative().finite();
6021
+ var customNetworkSchema = z9.object({
5541
6022
  latencyMs: nonNegative2.optional(),
5542
6023
  jitterMs: nonNegative2.optional(),
5543
6024
  downKbps: nonNegative2.optional(),
5544
6025
  upKbps: nonNegative2.optional(),
5545
- lossPct: z8.number().min(0).max(100).optional()
6026
+ lossPct: z9.number().min(0).max(100).optional()
5546
6027
  }).strict();
5547
- var isoDate = z8.string().refine((v) => !Number.isNaN(Date.parse(v)), { message: "invalid date (use ISO 8601)" });
5548
- var offsetDuration = z8.string().refine((v) => parseDuration(v).success, { message: "invalid duration (use e.g. 2d)" });
5549
- var textSize = z8.union([z8.enum(TEXT_SIZE_NAMES), z8.number().positive().finite()]);
5550
- var a11yConfigSchema = z8.object({
6028
+ var isoDate = z9.string().refine((v) => !Number.isNaN(Date.parse(v)), { message: "invalid date (use ISO 8601)" });
6029
+ var offsetDuration = z9.string().refine((v) => parseDuration(v).success, { message: "invalid duration (use e.g. 2d)" });
6030
+ var textSize = z9.union([z9.enum(TEXT_SIZE_NAMES), z9.number().positive().finite()]);
6031
+ var a11yConfigSchema = z9.object({
5551
6032
  textSize: textSize.optional(),
5552
- boldText: z8.boolean().optional(),
5553
- contrast: z8.enum(["increased", "normal"]).optional(),
5554
- reduceMotion: z8.boolean().optional()
6033
+ boldText: z9.boolean().optional(),
6034
+ contrast: z9.enum(["increased", "normal"]).optional(),
6035
+ reduceMotion: z9.boolean().optional()
5555
6036
  }).strict();
5556
- var conditionsConfigSchema = z8.object({
5557
- network: z8.union([z8.enum(NETWORK_WORDS), customNetworkSchema]).optional(),
5558
- location: z8.union([
5559
- z8.enum(["city-run", "city-bike", "freeway"]),
5560
- z8.object({
5561
- lat: z8.number().min(-90).max(90),
5562
- lon: z8.number().min(-180).max(180),
5563
- altM: z8.number().finite().optional()
6037
+ var conditionsConfigSchema = z9.object({
6038
+ network: z9.union([z9.enum(NETWORK_WORDS), customNetworkSchema]).optional(),
6039
+ location: z9.union([
6040
+ z9.enum(["city-run", "city-bike", "freeway"]),
6041
+ z9.object({
6042
+ lat: z9.number().min(-90).max(90),
6043
+ lon: z9.number().min(-180).max(180),
6044
+ altM: z9.number().finite().optional()
5564
6045
  }).strict()
5565
6046
  ]).optional(),
5566
- clock: z8.union([
6047
+ clock: z9.union([
5567
6048
  isoDate,
5568
- z8.object({ at: isoDate, frozen: z8.boolean().optional() }).strict(),
5569
- z8.object({ offset: offsetDuration }).strict()
6049
+ z9.object({ at: isoDate, frozen: z9.boolean().optional() }).strict(),
6050
+ z9.object({ offset: offsetDuration }).strict()
5570
6051
  ]).optional(),
5571
- permissions: z8.partialRecord(z8.enum(PERMISSION_NAMES), z8.enum(["granted", "denied", "unset"])).optional(),
5572
- locale: z8.string().min(1).optional(),
5573
- timezone: z8.string().min(1).optional(),
5574
- a11y: a11yConfigSchema.optional()
6052
+ permissions: z9.partialRecord(z9.enum(PERMISSION_NAMES), z9.enum(["granted", "denied", "unset"])).optional(),
6053
+ locale: z9.string().min(1).optional(),
6054
+ timezone: z9.string().min(1).optional(),
6055
+ a11y: a11yConfigSchema.optional(),
6056
+ keyboard: z9.enum(KEYBOARD_MODES).optional()
5575
6057
  }).strict();
5576
- var cameraFeedInput = z8.union([
5577
- z8.string().min(1),
5578
- z8.object({ path: z8.string().min(1), loop: z8.boolean().optional() }).strict()
6058
+ var cameraFeedInput = z9.union([
6059
+ z9.string().min(1),
6060
+ z9.object({ path: z9.string().min(1), loop: z9.boolean().optional() }).strict()
5579
6061
  ]);
5580
- var cameraConfigSchema = z8.object({ back: cameraFeedInput.optional(), front: cameraFeedInput.optional() }).strict().refine((v) => v.back !== undefined || v.front !== undefined, { message: "camera needs a back or a front asset" });
5581
- var cameraFeedsSchema = z8.object({
5582
- back: z8.object({ path: z8.string().min(1), loop: z8.boolean() }).strict().optional(),
5583
- front: z8.object({ path: z8.string().min(1), loop: z8.boolean() }).strict().optional()
6062
+ var cameraConfigSchema = z9.object({ back: cameraFeedInput.optional(), front: cameraFeedInput.optional() }).strict().refine((v) => v.back !== undefined || v.front !== undefined, { message: "camera needs a back or a front asset" });
6063
+ var cameraFeedsSchema = z9.object({
6064
+ back: z9.object({ path: z9.string().min(1), loop: z9.boolean() }).strict().optional(),
6065
+ front: z9.object({ path: z9.string().min(1), loop: z9.boolean() }).strict().optional()
5584
6066
  }).strict();
5585
6067
  function parseCameraFeedsEnv(raw) {
5586
6068
  let json;
@@ -5638,6 +6120,8 @@ function normalizeConditions(config) {
5638
6120
  conditions.locale = config.locale;
5639
6121
  if (config.timezone !== undefined)
5640
6122
  conditions.timezone = config.timezone;
6123
+ if (config.keyboard !== undefined)
6124
+ conditions.keyboard = { mode: config.keyboard };
5641
6125
  if (config.a11y !== undefined) {
5642
6126
  const a11y = { ...config.a11y };
5643
6127
  if (config.a11y.textSize !== undefined) {
@@ -5662,7 +6146,7 @@ function parseConditionsEnv(raw) {
5662
6146
  }
5663
6147
 
5664
6148
  // ../../packages/e2e/src/env.ts
5665
- import { z as z9 } from "zod";
6149
+ import { z as z10 } from "zod";
5666
6150
  var ENV_NAMES = {
5667
6151
  udid: "WARDEN_UDID",
5668
6152
  deviceName: "WARDEN_DEVICE_NAME",
@@ -5700,68 +6184,68 @@ var ENV_NAMES = {
5700
6184
  var DEFAULT_TIMEOUT_MS5 = 120000;
5701
6185
  var DEFAULT_ACTION_TIMEOUT_MS = 30000;
5702
6186
  var DEFAULT_ASSERTION_TIMEOUT_MS = 5000;
5703
- var toggle = z9.enum(["1", "true", "0", "false"]).transform((v) => v === "1" || v === "true");
5704
- var millis = z9.string().regex(/^\d+$/, "must be a whole number of milliseconds").transform(Number).pipe(z9.number().int().positive());
5705
- var launchArgs = z9.string().transform((raw, ctx) => {
6187
+ var toggle = z10.enum(["1", "true", "0", "false"]).transform((v) => v === "1" || v === "true");
6188
+ var millis = z10.string().regex(/^\d+$/, "must be a whole number of milliseconds").transform(Number).pipe(z10.number().int().positive());
6189
+ var launchArgs = z10.string().transform((raw, ctx) => {
5706
6190
  try {
5707
- const parsed = z9.array(z9.string()).safeParse(JSON.parse(raw));
6191
+ const parsed = z10.array(z10.string()).safeParse(JSON.parse(raw));
5708
6192
  if (parsed.success)
5709
6193
  return parsed.data;
5710
6194
  } catch {}
5711
6195
  ctx.addIssue({ code: "custom", message: "must be a JSON array of strings" });
5712
- return z9.NEVER;
6196
+ return z10.NEVER;
5713
6197
  });
5714
- var conditions = z9.string().transform((raw, ctx) => {
6198
+ var conditions = z10.string().transform((raw, ctx) => {
5715
6199
  const parsed = parseConditionsEnv(raw);
5716
6200
  if (parsed.success)
5717
6201
  return parsed.data;
5718
6202
  ctx.addIssue({ code: "custom", message: parsed.error });
5719
- return z9.NEVER;
6203
+ return z10.NEVER;
5720
6204
  });
5721
- var a11yAudit = z9.string().transform((raw, ctx) => {
6205
+ var a11yAudit = z10.string().transform((raw, ctx) => {
5722
6206
  const parsed = parseA11yAuditEnv(raw);
5723
6207
  if (parsed.success)
5724
6208
  return parsed.data;
5725
6209
  ctx.addIssue({ code: "custom", message: parsed.error });
5726
- return z9.NEVER;
6210
+ return z10.NEVER;
5727
6211
  });
5728
- var cameraFeeds = z9.string().transform((raw, ctx) => {
6212
+ var cameraFeeds = z10.string().transform((raw, ctx) => {
5729
6213
  const parsed = parseCameraFeedsEnv(raw);
5730
6214
  if (parsed.success)
5731
6215
  return parsed.data;
5732
6216
  ctx.addIssue({ code: "custom", message: parsed.error });
5733
- return z9.NEVER;
6217
+ return z10.NEVER;
5734
6218
  });
5735
6219
  var REQUIRED = "required when WARDEN_UDID is set";
5736
- var schema = z9.object({
5737
- udid: z9.string().min(1),
5738
- deviceName: z9.string().optional(),
5739
- platform: z9.enum(["ios", "android"]).default("ios"),
5740
- bundleId: z9.string({ error: REQUIRED }).min(1, REQUIRED),
5741
- appPath: z9.string().optional(),
5742
- metroUrl: z9.string().optional(),
5743
- devClientScheme: z9.string().min(1).optional(),
6220
+ var schema = z10.object({
6221
+ udid: z10.string().min(1),
6222
+ deviceName: z10.string().optional(),
6223
+ platform: z10.enum(["ios", "android"]).default("ios"),
6224
+ bundleId: z10.string({ error: REQUIRED }).min(1, REQUIRED),
6225
+ appPath: z10.string().optional(),
6226
+ metroUrl: z10.string().optional(),
6227
+ devClientScheme: z10.string().min(1).optional(),
5744
6228
  launchArgs: launchArgs.default([]),
5745
- out: z9.string().optional(),
6229
+ out: z10.string().optional(),
5746
6230
  timeout: millis.default(DEFAULT_TIMEOUT_MS5),
5747
6231
  actionTimeout: millis.default(DEFAULT_ACTION_TIMEOUT_MS),
5748
6232
  assertionTimeout: millis.default(DEFAULT_ASSERTION_TIMEOUT_MS),
5749
- specsDir: z9.string().optional(),
5750
- helperDir: z9.string().optional(),
5751
- simd: z9.string().optional(),
5752
- simdSocket: z9.string().optional(),
5753
- iosRunnerSocket: z9.string().optional(),
6233
+ specsDir: z10.string().optional(),
6234
+ helperDir: z10.string().optional(),
6235
+ simd: z10.string().optional(),
6236
+ simdSocket: z10.string().optional(),
6237
+ iosRunnerSocket: z10.string().optional(),
5754
6238
  logTimestamps: toggle.default(false),
5755
- deviceKind: z9.enum(["physical"]).optional(),
6239
+ deviceKind: z10.enum(["physical"]).optional(),
5756
6240
  iosRunnerRestart: launchArgs.optional(),
5757
6241
  afterReboot: launchArgs.optional(),
5758
- version: z9.string().optional(),
5759
- bin: z9.string().optional(),
5760
- perf: z9.string().optional(),
5761
- perfBudgets: z9.string().optional(),
6242
+ version: z10.string().optional(),
6243
+ bin: z10.string().optional(),
6244
+ perf: z10.string().optional(),
6245
+ perfBudgets: z10.string().optional(),
5762
6246
  conditions: conditions.optional(),
5763
- leaseId: z9.string().min(1).optional(),
5764
- netproxyCommand: launchArgs.pipe(z9.array(z9.string()).min(1)).optional(),
6247
+ leaseId: z10.string().min(1).optional(),
6248
+ netproxyCommand: launchArgs.pipe(z10.array(z10.string()).min(1)).optional(),
5765
6249
  biometrics: toggle.optional(),
5766
6250
  a11yAudit: a11yAudit.optional(),
5767
6251
  cameraFeeds: cameraFeeds.optional()
@@ -5771,7 +6255,7 @@ function defined2(values) {
5771
6255
  }
5772
6256
  function parseArgv(raw) {
5773
6257
  try {
5774
- const parsed = z9.array(z9.string()).min(1).safeParse(JSON.parse(raw));
6258
+ const parsed = z10.array(z10.string()).min(1).safeParse(JSON.parse(raw));
5775
6259
  if (parsed.success)
5776
6260
  return parsed.data;
5777
6261
  } catch {}
@@ -5841,25 +6325,43 @@ function readEnv(env, opts = {}) {
5841
6325
  // ../../packages/e2e/src/runner/results.ts
5842
6326
  import { appendFileSync, mkdirSync as mkdirSync2 } from "fs";
5843
6327
  import { dirname as dirname3 } from "path";
5844
- import { z as z10 } from "zod";
5845
- var testStatusSchema = z10.enum(["passed", "failed", "skipped", "timed-out"]);
5846
- var testResultSchema = z10.object({
5847
- file: z10.string(),
5848
- title: z10.array(z10.string()),
6328
+ import { z as z11 } from "zod";
6329
+ var bridgeReadSchema = z11.object({
6330
+ reason: z11.string().optional(),
6331
+ code: z11.string().optional(),
6332
+ stage: z11.string().optional(),
6333
+ readMs: z11.number().optional(),
6334
+ deadlineMs: z11.number().optional(),
6335
+ guestAgeMs: z11.number().optional(),
6336
+ cold: z11.boolean().optional(),
6337
+ cooldownRemainingMs: z11.number().optional(),
6338
+ probes: z11.number().optional(),
6339
+ recycles: z11.number().optional(),
6340
+ recyclesExhausted: z11.boolean().optional()
6341
+ });
6342
+ var testStatusSchema = z11.enum(["passed", "failed", "skipped", "timed-out"]);
6343
+ var testResultSchema = z11.object({
6344
+ file: z11.string(),
6345
+ title: z11.array(z11.string()),
5849
6346
  status: testStatusSchema,
5850
- durationMs: z10.number(),
5851
- startedAt: z10.number(),
5852
- only: z10.boolean().optional(),
5853
- error: z10.object({
5854
- message: z10.string(),
5855
- code: z10.string().optional(),
5856
- stack: z10.string().optional()
6347
+ durationMs: z11.number(),
6348
+ startedAt: z11.number(),
6349
+ only: z11.boolean().optional(),
6350
+ error: z11.object({
6351
+ message: z11.string(),
6352
+ code: z11.string().optional(),
6353
+ stack: z11.string().optional()
5857
6354
  }).optional(),
5858
- artifacts: z10.object({ dir: z10.string(), files: z10.array(z10.string()) }).optional(),
5859
- device: z10.object({
5860
- udid: z10.string(),
5861
- platform: z10.enum(["ios", "android"]),
5862
- name: z10.string().optional()
6355
+ artifacts: z11.object({ dir: z11.string(), files: z11.array(z11.string()) }).optional(),
6356
+ bridge: z11.object({
6357
+ fallbacks: z11.number(),
6358
+ first: bridgeReadSchema,
6359
+ last: bridgeReadSchema
6360
+ }).optional(),
6361
+ device: z11.object({
6362
+ udid: z11.string(),
6363
+ platform: z11.enum(["ios", "android"]),
6364
+ name: z11.string().optional()
5863
6365
  })
5864
6366
  });
5865
6367
  function openResults(path) {
@@ -5995,6 +6497,8 @@ ${read.error}`);
5995
6497
  throw new E2eError2("SESSION", "not running under warden: WARDEN_UDID is not set");
5996
6498
  return read.data;
5997
6499
  }
6500
+ var AX_WEDGE_WAIT_MS = 60000;
6501
+ var AX_WEDGE_POLL_MS = 1000;
5998
6502
  var WARM_TRIES = 15;
5999
6503
  var WARM_INTERVAL_MS = 2000;
6000
6504
  function createSession(opts = {}) {
@@ -6039,6 +6543,27 @@ function createSession(opts = {}) {
6039
6543
  await sleep(WARM_INTERVAL_MS);
6040
6544
  }
6041
6545
  }
6546
+ let axWedgeRerunFor = 0;
6547
+ async function recoverAxWedge(attemptMs) {
6548
+ const driver = current;
6549
+ if (closing !== undefined || driver === undefined || !canRecoverAxWedge(driver))
6550
+ return false;
6551
+ const sleep = hid?.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
6552
+ let state = await driver.axWedge();
6553
+ let waited = 0;
6554
+ while (state.success && state.data.recovering && waited < AX_WEDGE_WAIT_MS) {
6555
+ await sleep(AX_WEDGE_POLL_MS);
6556
+ waited += AX_WEDGE_POLL_MS;
6557
+ state = await driver.axWedge();
6558
+ }
6559
+ if (!state.success || state.data.restarts <= axWedgeRerunFor)
6560
+ return false;
6561
+ if (!restartedWithin(state.data, attemptMs + waited))
6562
+ return false;
6563
+ axWedgeRerunFor = state.data.restarts;
6564
+ note(`sim ${resolved.deviceName ?? resolved.udid}: accessibility service wedged, warden-simd restarted backboardd (the app was quit); running the test again`);
6565
+ return true;
6566
+ }
6042
6567
  async function recoverRunner(deps, name) {
6043
6568
  if (hidRecovered) {
6044
6569
  note(`iPhone ${name}: the runner connection was lost again after a restart; check the phone and retry`);
@@ -6116,6 +6641,7 @@ function createSession(opts = {}) {
6116
6641
  fixtures: opts.fixtures ?? defaultFixtures,
6117
6642
  nativeLog: opts.nativeLog ?? defaultNativeLog,
6118
6643
  recoverHid: hid === undefined || resolved.platform !== "ios" ? undefined : recoverHid,
6644
+ recoverAxWedge: resolved.platform !== "ios" || resolved.deviceKind === "physical" ? undefined : recoverAxWedge,
6119
6645
  resetDevice,
6120
6646
  log: opts.log ?? writeLine,
6121
6647
  get attempt() {
@@ -6254,6 +6780,9 @@ function attemptSession(session, binding) {
6254
6780
  get recoverHid() {
6255
6781
  return session.recoverHid;
6256
6782
  },
6783
+ get recoverAxWedge() {
6784
+ return session.recoverAxWedge;
6785
+ },
6257
6786
  resetDevice: () => session.resetDevice(),
6258
6787
  get fixtures() {
6259
6788
  return session.fixtures;
@@ -6884,15 +7413,15 @@ function runAudit(snapshot, platform, opts = {}) {
6884
7413
  function failing(result, minSeverity = "error") {
6885
7414
  return result.issues.filter((i) => SEVERITY_RANK[i.severity] >= SEVERITY_RANK[minSeverity]);
6886
7415
  }
6887
- function elementKey(i) {
7416
+ function elementKey2(i) {
6888
7417
  return i.identifier ?? i.elementId;
6889
7418
  }
6890
7419
  function mergeIssues(base, extra, skipped = []) {
6891
7420
  const issues = [...base.issues];
6892
7421
  const added = [];
6893
7422
  for (const e of extra) {
6894
- const key = elementKey(e);
6895
- const idx = issues.findIndex((i) => key !== undefined && elementKey(i) === key && (e.wcag !== undefined ? i.wcag === e.wcag : i.rule === e.rule && i.message === e.message));
7423
+ const key = elementKey2(e);
7424
+ const idx = issues.findIndex((i) => key !== undefined && elementKey2(i) === key && (e.wcag !== undefined ? i.wcag === e.wcag : i.rule === e.rule && i.message === e.message));
6896
7425
  const hit = idx === -1 ? undefined : issues[idx];
6897
7426
  if (hit === undefined) {
6898
7427
  added.push(e);
@@ -7235,6 +7764,12 @@ function createDeviceA11y(deps) {
7235
7764
  const merged = await withA11yRead(driver, taken.data);
7236
7765
  return renderA11yScreen(merged.success ? merged.data : taken.data);
7237
7766
  },
7767
+ async keyboardVisible() {
7768
+ const state = await settled(() => driver.keyboardState(), "keyboardState", signal());
7769
+ if (!state.success)
7770
+ throw toE2eError(state.error, "read the keyboard");
7771
+ return state.data.visible;
7772
+ },
7238
7773
  assertionTimeout: () => env.assertionTimeoutMs,
7239
7774
  step: (label, fn) => deps.step === undefined ? fn() : deps.step(label, fn)
7240
7775
  };
@@ -8030,6 +8565,7 @@ var KNOWN_AREAS = new Set([
8030
8565
  "locale",
8031
8566
  "a11y",
8032
8567
  "battery",
8568
+ "keyboard",
8033
8569
  "camera"
8034
8570
  ]);
8035
8571
 
@@ -8403,6 +8939,8 @@ function createDeviceConditions(deps) {
8403
8939
  let localeDirty = false;
8404
8940
  let a11yDirty = false;
8405
8941
  let batteryDirty = false;
8942
+ let keyboardDirty = false;
8943
+ let currentKeyboard = DEFAULT_KEYBOARD_MODE;
8406
8944
  let cameraDirty = false;
8407
8945
  let currentCamera = {};
8408
8946
  const permissionStates = new Map;
@@ -8779,6 +9317,28 @@ the app runs without the warden network dylib: declare \`conditions.network\` fo
8779
9317
  emit({ area: "battery", value });
8780
9318
  return state;
8781
9319
  }
9320
+ const ownsDevice = recorder !== undefined && env.deviceKind !== "physical";
9321
+ const keyboardGoal = baseline.keyboard?.mode ?? DEFAULT_KEYBOARD_MODE;
9322
+ async function applyKeyboard(input) {
9323
+ const mode = input === "toggle" ? currentKeyboard === "software" ? "hardware" : "software" : input;
9324
+ if (!KEYBOARD_MODES.includes(mode)) {
9325
+ throw invalid2(`unknown keyboard mode "${String(input)}" (use software, hardware or toggle)`);
9326
+ }
9327
+ keyboardDirty = true;
9328
+ const run = settingOp("keyboard");
9329
+ const state = await call("keyboard", () => run(mode));
9330
+ currentKeyboard = mode;
9331
+ const value = {
9332
+ mode,
9333
+ ...state.previousIme === undefined ? {} : { previousIme: state.previousIme }
9334
+ };
9335
+ if (mode === DEFAULT_KEYBOARD_MODE)
9336
+ recorder?.settle("keyboard", value, true);
9337
+ else
9338
+ recorder?.record("keyboard", value);
9339
+ emit({ area: "keyboard", value });
9340
+ return state;
9341
+ }
8782
9342
  const home = deps.wardenHome ?? wardenHome(process.env);
8783
9343
  async function applyCamera(next) {
8784
9344
  cameraDirty = true;
@@ -8881,7 +9441,7 @@ the app runs without the warden network dylib: declare \`conditions.network\` fo
8881
9441
  throw new E2eError2("ACTION_FAILED", `a network flap or timeline stopped on its own after failing: ${failures[0]}`);
8882
9442
  }
8883
9443
  }
8884
- const declared = baseline.network !== undefined || baseline.location !== undefined || baseline.clock !== undefined || baseline.permissions !== undefined || baseline.locale !== undefined || baseline.timezone !== undefined || baseline.a11y !== undefined || env.cameraFeeds !== undefined;
9444
+ const declared = baseline.network !== undefined || baseline.location !== undefined || baseline.clock !== undefined || baseline.permissions !== undefined || baseline.locale !== undefined || baseline.timezone !== undefined || baseline.a11y !== undefined || baseline.keyboard !== undefined || ownsDevice || env.cameraFeeds !== undefined;
8885
9445
  async function applyBaselinePermissions() {
8886
9446
  if (baseline.permissions === undefined)
8887
9447
  return;
@@ -8918,6 +9478,10 @@ the app runs without the warden network dylib: declare \`conditions.network\` fo
8918
9478
  async () => {
8919
9479
  if (env.cameraFeeds !== undefined)
8920
9480
  await applyCamera(baselineCamera());
9481
+ },
9482
+ async () => {
9483
+ if (baseline.keyboard !== undefined || ownsDevice)
9484
+ await applyKeyboard(keyboardGoal);
8921
9485
  }
8922
9486
  ];
8923
9487
  const teardownSteps = [
@@ -8957,6 +9521,13 @@ the app runs without the warden network dylib: declare \`conditions.network\` fo
8957
9521
  batteryDirty = false;
8958
9522
  }
8959
9523
  },
9524
+ {
9525
+ dirty: () => keyboardDirty,
9526
+ run: async () => {
9527
+ await applyKeyboard(keyboardGoal);
9528
+ keyboardDirty = false;
9529
+ }
9530
+ },
8960
9531
  {
8961
9532
  dirty: () => cameraDirty,
8962
9533
  run: async () => {
@@ -8967,7 +9538,7 @@ the app runs without the warden network dylib: declare \`conditions.network\` fo
8967
9538
  ];
8968
9539
  const internals = {
8969
9540
  declared,
8970
- dirty: () => networkDirty || locationDirty || clockDirty || permissionsDirty || localeDirty || a11yDirty || batteryDirty || cameraDirty || runs.size > 0,
9541
+ dirty: () => networkDirty || locationDirty || clockDirty || permissionsDirty || localeDirty || a11yDirty || batteryDirty || keyboardDirty || cameraDirty || runs.size > 0,
8971
9542
  wantsInject: () => baseline.network !== undefined || baseline.clock !== undefined || currentNetwork.kind !== "online" || currentClock.kind !== "real",
8972
9543
  async applyBaseline() {
8973
9544
  for (const step of baselineSteps)
@@ -8980,6 +9551,7 @@ the app runs without the warden network dylib: declare \`conditions.network\` fo
8980
9551
  localeDirty = false;
8981
9552
  a11yDirty = false;
8982
9553
  batteryDirty = false;
9554
+ keyboardDirty = false;
8983
9555
  },
8984
9556
  async teardown() {
8985
9557
  const errors = [];
@@ -9008,6 +9580,7 @@ the app runs without the warden network dylib: declare \`conditions.network\` fo
9008
9580
  locale: applyLocale,
9009
9581
  a11y: applyA11y,
9010
9582
  battery: applyBattery,
9583
+ keyboard: applyKeyboard,
9011
9584
  camera: cameraApi,
9012
9585
  memoryWarning: async (options) => {
9013
9586
  const op = settingOp("memoryWarning");
@@ -9327,6 +9900,6 @@ function onlyWasSeen() {
9327
9900
 
9328
9901
  // ../../packages/e2e/src/version.ts
9329
9902
  var WORKSPACE_VERSION = "0.0.0-workspace";
9330
- var WARDEN_E2E_VERSION2 = "0.13.0";
9903
+ var WARDEN_E2E_VERSION2 = "0.15.0";
9331
9904
 
9332
- export { E2eError2, registerA11yTarget, a11yTargetOf, canActOnElements, noteSpanDetail, addSpanDetail, canObserve, canDetectAlerts, settleDetailOf, DEFAULT_SETTLE_QUIET_MS, DEFAULT_SETTLE_TIMEOUT_MS, settleByHash, snapshotHash, ok, err, swipeVector, screenRect, fieldValue, PINCH_MS, ROTATE_MS, PATH_MS, centreOf, pinchRadius, rotateRadius, requireGesture, assertScale, assertDegrees, isInteractiveRole, resolveRole, normalizeText, matchesText, indexSnapshot, testIdQuery, textQuery, roleQuery, selectorExpression, renderSnapshot, renderHeader, resolve, locateByTestIdViaReact, isLocator, Locator, pickOne, textOf, scrollUntilVisible, formatNativeTail, realNativeLogDeps, captureNativeLog, bunExec, execError, driverError, driverErr, logEventSchema, fatalEventSchema, responseSchema, mapWireError, createLineSplitter, encodeRequest, bunSpawn, stdioTransport, socketTransport, createSimdClient, spawnSimd, connectSimd, isRecoverableLoss, parseDuration, CAMERA_FACINGS, CONDITION_AREAS, resolveNetwork, resolveTextSize, androidFontScale, ENV_NAMES, DEFAULT_ASSERTION_TIMEOUT_MS, readEnv, runStep, setDefaultHidRecovery, setDefaultNativeLog, setDefaultDriverFactory, hasDefaultDriverFactory, setDefaultFixtureFactory, hasDefaultFixtureFactory, attemptSession, getSession, peekSession, accessibleName, announce, failing, formatIssues, toE2eError, settled, unwrap, parseUiadA11yEvents, parseInjectEvents, withA11yRead, renderA11yScreen, createDeviceA11y, IOS_DEVICE_CAPABILITIES, sniffCameraMedia, cameraFeedDir, clearCameraFeeds, isLeaseAlive, processAlive, describeOwner, isPhysicalIosId, wardenHome, defaultDbPath, ownerKey, openStore, callerFile, formatCoord, DEFAULT_SPEED_MPS, DEFAULT_INTERVAL_S, realTickerClock, startRouteTicker, startFlap, registerConditions, conditionsOf, conditionSinkFor, createDeviceConditions, parseBudgets, createDevicePerf, perfStartFor, spawnWarden, hash6, attemptDir, screenshotPath, specIdOf, BUN_TIMEOUT_MARGIN_MS2, ownHook, currentScope, createScope, runInScope, hooksFor, resolveUse, registrationDefaults, markOnly, onlyWasSeen, WORKSPACE_VERSION, WARDEN_E2E_VERSION2 };
9905
+ export { E2eError2, registerA11yTarget, a11yTargetOf, canActOnElements, noteSpanDetail, addSpanDetail, canObserve, canDetectAlerts, settleDetailOf, DEFAULT_SETTLE_QUIET_MS, DEFAULT_SETTLE_TIMEOUT_MS, hashFallbackQuietMs, settleByHash, snapshotHash, ok, err, swipeVector, screenRect, isOnScreen, fieldValue, PINCH_MS, ROTATE_MS, PATH_MS, centreOf, pinchRadius, rotateRadius, requireGesture, assertScale, assertDegrees, isInteractiveRole, resolveRole, normalizeText, matchesText, indexSnapshot, keyboardVisible, testIdQuery, textQuery, roleQuery, selectorExpression, renderSnapshot, renderHeader, lookUpTestIdViaReact, isLocator, Locator, pickOne, textOf, scrollUntilVisible, formatNativeTail, realNativeLogDeps, captureNativeLog, bunExec, execError, driverError, driverErr, bridgeStallSchema, toBridgeStall, noteBridgeStall, bridgeStallFromSpan, formatBridgeStall, logEventSchema, fatalEventSchema, responseSchema, mapWireError, createLineSplitter, encodeRequest, bunSpawn, stdioTransport, socketTransport, createSimdClient, spawnSimd, connectSimd, isRecoverableLoss, parseDuration, KEYBOARD_MODES, DEFAULT_KEYBOARD_MODE, IME_STASH_ENABLED, IME_STASH_DEFAULT, CAMERA_FACINGS, CONDITION_AREAS, resolveNetwork, resolveTextSize, androidFontScale, ENV_NAMES, DEFAULT_ASSERTION_TIMEOUT_MS, readEnv, runStep, setDefaultHidRecovery, setDefaultNativeLog, setDefaultDriverFactory, hasDefaultDriverFactory, setDefaultFixtureFactory, hasDefaultFixtureFactory, attemptSession, getSession, peekSession, accessibleName, announce, failing, formatIssues, toE2eError, settled, unwrap, parseUiadA11yEvents, parseInjectEvents, withA11yRead, renderA11yScreen, createDeviceA11y, IOS_DEVICE_CAPABILITIES, sniffCameraMedia, cameraFeedDir, clearCameraFeeds, isLeaseAlive, processAlive, describeOwner, isPhysicalIosId, wardenHome, defaultDbPath, ownerKey, openStore, callerFile, formatCoord, DEFAULT_SPEED_MPS, DEFAULT_INTERVAL_S, realTickerClock, startRouteTicker, startFlap, registerConditions, conditionsOf, conditionSinkFor, createDeviceConditions, parseBudgets, createDevicePerf, perfStartFor, spawnWarden, hash6, attemptDir, screenshotPath, specIdOf, BUN_TIMEOUT_MARGIN_MS2, ownHook, currentScope, createScope, runInScope, hooksFor, resolveUse, registrationDefaults, markOnly, onlyWasSeen, WORKSPACE_VERSION, WARDEN_E2E_VERSION2 };