@delacour/warden-e2e 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{chunk-tnr47n9c.mjs → chunk-zk3wxa70.mjs} +552 -229
- package/index.mjs +113 -12
- package/package.json +2 -2
- package/preload.mjs +72 -34
- package/types/e2e/src/driver/bridge-stall.d.ts +37 -0
- package/types/e2e/src/driver/driver.types.d.ts +5 -1
- package/types/e2e/src/driver/ios/ios-driver.d.ts +10 -0
- package/types/e2e/src/driver/ios/simd-client.d.ts +2 -0
- package/types/e2e/src/driver/ios/simd-protocol.d.ts +30 -0
- package/types/e2e/src/driver/settle.d.ts +8 -0
- package/types/e2e/src/errors.d.ts +3 -1
- package/types/e2e/src/expect/matchers.d.ts +5 -0
- package/types/e2e/src/runner/bridge-evidence.d.ts +12 -0
- package/types/e2e/src/runner/results.d.ts +29 -0
- package/types/e2e/src/screen/context.d.ts +8 -11
- package/types/e2e/src/screen/degraded-read.d.ts +23 -0
- package/types/e2e/src/screen/locator.d.ts +46 -1
- package/types/e2e/src/screen/react-locator.d.ts +17 -2
- package/types/e2e/src/screen/react-merge.d.ts +10 -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;
|
|
@@ -479,6 +483,34 @@ function assertDegrees(degrees) {
|
|
|
479
483
|
}
|
|
480
484
|
}
|
|
481
485
|
|
|
486
|
+
// ../../packages/e2e/src/screen/degraded-read.ts
|
|
487
|
+
function degradedRead(snapshot) {
|
|
488
|
+
if (snapshot.fellBackFrom !== undefined) {
|
|
489
|
+
return { kind: "fallback", from: snapshot.fellBackFrom, backend: snapshot.backend };
|
|
490
|
+
}
|
|
491
|
+
const [root, ...others] = snapshot.elements;
|
|
492
|
+
if (root !== undefined && others.length === 0 && root.children.length === 0) {
|
|
493
|
+
const { width, height } = root.frame;
|
|
494
|
+
if (width * height === 0)
|
|
495
|
+
return { kind: "emptyRoot", backend: snapshot.backend };
|
|
496
|
+
}
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
function describeDegraded(read) {
|
|
500
|
+
if (read.kind === "emptyRoot")
|
|
501
|
+
return `the ${read.backend} read returned an empty root (backend: ${read.backend})`;
|
|
502
|
+
return `the read fell back from ${read.from} to ${read.backend} (fellBackFrom: ${read.from}, backend: ${read.backend}), which can drop React Native testIDs`;
|
|
503
|
+
}
|
|
504
|
+
var REACT_NOTES = {
|
|
505
|
+
unanswered: "the React tree did not answer",
|
|
506
|
+
"no-devtools": "there is no React tree to ask (no devtools: not a dev client with Metro)",
|
|
507
|
+
"not-testid": "only a plain getByTestId can be asked of the React tree"
|
|
508
|
+
};
|
|
509
|
+
function degradedFailure(locator, read, waitedMs, react, screen) {
|
|
510
|
+
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.`;
|
|
511
|
+
return new E2eError2("READ_DEGRADED", message, screen);
|
|
512
|
+
}
|
|
513
|
+
|
|
482
514
|
// ../../packages/e2e/src/screen/roles.ts
|
|
483
515
|
var QUERY_ROLES = [
|
|
484
516
|
"button",
|
|
@@ -1534,7 +1566,7 @@ function describeExpression(expr) {
|
|
|
1534
1566
|
}
|
|
1535
1567
|
|
|
1536
1568
|
// ../../packages/e2e/src/screen/react-locator.ts
|
|
1537
|
-
async function
|
|
1569
|
+
async function lookUpTestIdViaReact(facet, testId, view, options = {}) {
|
|
1538
1570
|
const treeOptions = {
|
|
1539
1571
|
...view.platform === "android" ? { pixelRatio: view.screen.scale } : {},
|
|
1540
1572
|
...options.screenName === undefined ? {} : { screen: options.screenName },
|
|
@@ -1544,10 +1576,10 @@ async function locateByTestIdViaReact(facet, testId, view, options = {}) {
|
|
|
1544
1576
|
try {
|
|
1545
1577
|
result = await facet.tree(treeOptions);
|
|
1546
1578
|
} catch {
|
|
1547
|
-
return
|
|
1579
|
+
return { answered: false };
|
|
1548
1580
|
}
|
|
1549
1581
|
if (!result.success)
|
|
1550
|
-
return
|
|
1582
|
+
return { answered: false };
|
|
1551
1583
|
const matches = [];
|
|
1552
1584
|
for (const component of result.data.components) {
|
|
1553
1585
|
const { testID, rect } = component;
|
|
@@ -1558,10 +1590,11 @@ async function locateByTestIdViaReact(facet, testId, view, options = {}) {
|
|
|
1558
1590
|
tapPoint: { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 },
|
|
1559
1591
|
source: "react",
|
|
1560
1592
|
testId: testID,
|
|
1561
|
-
name: component.name
|
|
1593
|
+
name: component.name,
|
|
1594
|
+
...component.text === undefined ? {} : { text: component.text }
|
|
1562
1595
|
});
|
|
1563
1596
|
}
|
|
1564
|
-
return matches;
|
|
1597
|
+
return { answered: true, matches };
|
|
1565
1598
|
}
|
|
1566
1599
|
function reactTapPoint(match, position) {
|
|
1567
1600
|
if (position === undefined)
|
|
@@ -1569,6 +1602,41 @@ function reactTapPoint(match, position) {
|
|
|
1569
1602
|
return { x: match.frame.x + position.x, y: match.frame.y + position.y };
|
|
1570
1603
|
}
|
|
1571
1604
|
|
|
1605
|
+
// ../../packages/e2e/src/screen/react-merge.ts
|
|
1606
|
+
var EDGE_SLACK = 1.5;
|
|
1607
|
+
function sameRect(a, b) {
|
|
1608
|
+
if (a.width <= 0 || a.height <= 0 || b.width <= 0 || b.height <= 0)
|
|
1609
|
+
return false;
|
|
1610
|
+
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;
|
|
1611
|
+
}
|
|
1612
|
+
function ownText(entry) {
|
|
1613
|
+
return normalizeText(entry.name ?? entry.value ?? "");
|
|
1614
|
+
}
|
|
1615
|
+
function nodeOfReactMatch(match, index) {
|
|
1616
|
+
const candidates = index.entries.filter((entry) => {
|
|
1617
|
+
const id = entry.element.identifier;
|
|
1618
|
+
return (id === undefined || id === match.testId) && sameRect(entry.element.frame, match.frame);
|
|
1619
|
+
});
|
|
1620
|
+
const text = match.text === undefined ? "" : normalizeText(match.text);
|
|
1621
|
+
const worded = text === "" ? [] : candidates.filter((entry) => ownText(entry) === text);
|
|
1622
|
+
const pool = worded.length > 0 ? worded : candidates;
|
|
1623
|
+
let best;
|
|
1624
|
+
for (const entry of pool)
|
|
1625
|
+
if (best === undefined || entry.depth > best.depth)
|
|
1626
|
+
best = entry;
|
|
1627
|
+
return best;
|
|
1628
|
+
}
|
|
1629
|
+
function mergeReactMatches(matches, index) {
|
|
1630
|
+
const entries = [];
|
|
1631
|
+
for (const match of matches) {
|
|
1632
|
+
const entry = nodeOfReactMatch(match, index);
|
|
1633
|
+
if (entry === undefined || entries.includes(entry))
|
|
1634
|
+
return;
|
|
1635
|
+
entries.push(entry);
|
|
1636
|
+
}
|
|
1637
|
+
return entries;
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1572
1640
|
// ../../packages/e2e/src/screen/locator.ts
|
|
1573
1641
|
var WAIT_STATES = ["attached", "detached", "visible", "hidden"];
|
|
1574
1642
|
var DEFAULT_MAX_SWIPES = 10;
|
|
@@ -1581,6 +1649,9 @@ function assertOptions(verb, options, allowed) {
|
|
|
1581
1649
|
throw new E2eError2("INVALID_ARGUMENT", `${verb} does not take ${unknown.map((key) => `"${key}"`).join(", ")}; it takes ${allowed.join(", ")}`);
|
|
1582
1650
|
}
|
|
1583
1651
|
}
|
|
1652
|
+
function reactVisible(match, observed) {
|
|
1653
|
+
return match.frame.width > 0 && match.frame.height > 0 && isOnScreen(match.tapPoint, observed.snapshot.screen);
|
|
1654
|
+
}
|
|
1584
1655
|
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
1656
|
function plainTestId(expr) {
|
|
1586
1657
|
if (expr.kind !== "query" || expr.scope !== undefined || expr.query.kind !== "testId")
|
|
@@ -1665,8 +1736,78 @@ class Locator {
|
|
|
1665
1736
|
const observed = await this.rt.observe(options);
|
|
1666
1737
|
return { entries: resolve(this.expr, observed.index), observed };
|
|
1667
1738
|
}
|
|
1668
|
-
|
|
1669
|
-
|
|
1739
|
+
async resolveIn(observed) {
|
|
1740
|
+
const entries = resolve(this.expr, observed.index);
|
|
1741
|
+
if (entries.length > 0)
|
|
1742
|
+
return { kind: "nodes", entries };
|
|
1743
|
+
const read = degradedRead(observed.snapshot);
|
|
1744
|
+
if (read === undefined)
|
|
1745
|
+
return { kind: "nodes", entries };
|
|
1746
|
+
const testId = plainTestId(this.expr);
|
|
1747
|
+
const lookup = testId === undefined ? undefined : await this.rt.reactLookup(testId, observed);
|
|
1748
|
+
if (lookup === undefined || !lookup.answered)
|
|
1749
|
+
return { kind: "unknown", read };
|
|
1750
|
+
if (lookup.matches.length === 0)
|
|
1751
|
+
return { kind: "nodes", entries };
|
|
1752
|
+
const merged = mergeReactMatches(lookup.matches, observed.index);
|
|
1753
|
+
return merged === undefined ? { kind: "react", matches: lookup.matches } : { kind: "nodes", entries: merged };
|
|
1754
|
+
}
|
|
1755
|
+
reactNote() {
|
|
1756
|
+
if (plainTestId(this.expr) === undefined)
|
|
1757
|
+
return "not-testid";
|
|
1758
|
+
return this.rt.hasReactTree() ? "unanswered" : "no-devtools";
|
|
1759
|
+
}
|
|
1760
|
+
degradedFailure(read, waitedMs, snapshot) {
|
|
1761
|
+
const screen = snapshot === undefined ? undefined : this.rt.excerpt(snapshot);
|
|
1762
|
+
return degradedFailure(this.toString(), read, waitedMs, this.reactNote(), screen);
|
|
1763
|
+
}
|
|
1764
|
+
async conclusive(options = {}) {
|
|
1765
|
+
const first = await this.look(options);
|
|
1766
|
+
const settled = await this.settled(first.observed);
|
|
1767
|
+
if (settled !== undefined)
|
|
1768
|
+
return settled;
|
|
1769
|
+
const timeoutMs = this.rt.actionTimeout();
|
|
1770
|
+
let last;
|
|
1771
|
+
const result = await this.rt.poll(async () => {
|
|
1772
|
+
const observation = await this.rt.tryObserve({ reuse: false });
|
|
1773
|
+
if (!observation.ok) {
|
|
1774
|
+
if (!observation.error.retryable)
|
|
1775
|
+
throw new E2eError2("DRIVER", `snapshot failed: ${observation.error.message}`);
|
|
1776
|
+
return { done: false, state: undefined };
|
|
1777
|
+
}
|
|
1778
|
+
const answer = await this.settled(observation.observed);
|
|
1779
|
+
if (answer !== undefined)
|
|
1780
|
+
return { done: true, value: answer };
|
|
1781
|
+
const read = degradedRead(observation.observed.snapshot);
|
|
1782
|
+
if (read !== undefined)
|
|
1783
|
+
last = { read, snapshot: observation.observed.snapshot };
|
|
1784
|
+
return { done: false, state: undefined };
|
|
1785
|
+
}, timeoutMs);
|
|
1786
|
+
if (result.status === "done")
|
|
1787
|
+
return result.value;
|
|
1788
|
+
const fallback = degradedRead(first.observed.snapshot);
|
|
1789
|
+
const read = last?.read ?? fallback;
|
|
1790
|
+
if (read === undefined)
|
|
1791
|
+
throw new E2eError2("TIMEOUT", `${this} could not be read within ${timeoutMs} ms`);
|
|
1792
|
+
throw this.degradedFailure(read, timeoutMs, last?.snapshot ?? first.observed.snapshot);
|
|
1793
|
+
}
|
|
1794
|
+
async settled(observed) {
|
|
1795
|
+
const resolved = await this.resolveIn(observed);
|
|
1796
|
+
if (resolved.kind === "unknown")
|
|
1797
|
+
return;
|
|
1798
|
+
if (resolved.kind === "react")
|
|
1799
|
+
return { entries: [], react: resolved.matches, observed };
|
|
1800
|
+
return { entries: resolved.entries, react: undefined, observed };
|
|
1801
|
+
}
|
|
1802
|
+
async matches() {
|
|
1803
|
+
const { entries, observed } = await this.conclusive();
|
|
1804
|
+
return { entries, observed };
|
|
1805
|
+
}
|
|
1806
|
+
reactOnly(matches, observed) {
|
|
1807
|
+
const [only, ...others] = matches;
|
|
1808
|
+
if (only !== undefined && others.length === 0)
|
|
1809
|
+
return only;
|
|
1810
|
+
throw new E2eError2("LOCATOR_AMBIGUOUS", `${this} matched ${matches.length} components in the React tree`, this.rt.excerpt(observed.snapshot), matches.length);
|
|
1670
1811
|
}
|
|
1671
1812
|
async single() {
|
|
1672
1813
|
const { entries, observed } = await this.matches();
|
|
@@ -1686,27 +1827,58 @@ class Locator {
|
|
|
1686
1827
|
return this.rt.span(`read.${name}`, run, { detail: () => ({ locator: this.toString() }) });
|
|
1687
1828
|
}
|
|
1688
1829
|
count() {
|
|
1689
|
-
return this.traced("count", async () =>
|
|
1830
|
+
return this.traced("count", async () => {
|
|
1831
|
+
const { entries, react } = await this.conclusive();
|
|
1832
|
+
return react?.length ?? entries.length;
|
|
1833
|
+
});
|
|
1690
1834
|
}
|
|
1691
1835
|
async all() {
|
|
1692
1836
|
const count = await this.count();
|
|
1693
1837
|
return Array.from({ length: count }, (_, index) => this.nth(index));
|
|
1694
1838
|
}
|
|
1695
1839
|
text() {
|
|
1696
|
-
return this.traced("text", async () =>
|
|
1840
|
+
return this.traced("text", async () => {
|
|
1841
|
+
const { entries, react, observed } = await this.conclusive();
|
|
1842
|
+
if (react !== undefined)
|
|
1843
|
+
return this.reactText(this.reactOnly(react, observed), observed);
|
|
1844
|
+
if (entries.length === 0 && (await this.reactCandidates(observed)).length > 0) {
|
|
1845
|
+
throw new E2eError2("NOT_ACTIONABLE", `${this} ${REACT_ONLY}`, this.rt.excerpt(observed.snapshot));
|
|
1846
|
+
}
|
|
1847
|
+
return textOf(this.exactlyOne(entries, observed));
|
|
1848
|
+
});
|
|
1697
1849
|
}
|
|
1698
1850
|
allTexts() {
|
|
1699
|
-
return this.traced("allTexts", async () =>
|
|
1851
|
+
return this.traced("allTexts", async () => {
|
|
1852
|
+
const { entries, react, observed } = await this.conclusive();
|
|
1853
|
+
if (react !== undefined)
|
|
1854
|
+
return react.map((match) => this.reactText(match, observed));
|
|
1855
|
+
return entries.map(textOf);
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
reactText(match, observed) {
|
|
1859
|
+
if (match.text !== undefined)
|
|
1860
|
+
return normalizeText(match.text);
|
|
1861
|
+
throw new E2eError2("NOT_ACTIONABLE", `${this} ${REACT_ONLY}`, this.rt.excerpt(observed.snapshot));
|
|
1700
1862
|
}
|
|
1701
1863
|
value() {
|
|
1702
1864
|
return this.traced("value", async () => fieldValue((await this.single()).entry));
|
|
1703
1865
|
}
|
|
1704
1866
|
isVisible() {
|
|
1705
|
-
return this.traced("isVisible", async () =>
|
|
1867
|
+
return this.traced("isVisible", async () => {
|
|
1868
|
+
const { entries, react, observed } = await this.conclusive();
|
|
1869
|
+
if (react !== undefined)
|
|
1870
|
+
return reactVisible(this.reactOnly(react, observed), observed);
|
|
1871
|
+
return entries.length > 0 && this.exactlyOne(entries, observed).visible;
|
|
1872
|
+
});
|
|
1706
1873
|
}
|
|
1707
1874
|
read() {
|
|
1708
1875
|
return this.traced("read", async () => {
|
|
1709
|
-
const { entries, observed } = await this.
|
|
1876
|
+
const { entries, react, observed } = await this.conclusive();
|
|
1877
|
+
if (react !== undefined) {
|
|
1878
|
+
const match = this.reactOnly(react, observed);
|
|
1879
|
+
const visible = reactVisible(match, observed);
|
|
1880
|
+
return match.text === undefined ? { visible } : { visible, text: normalizeText(match.text) };
|
|
1881
|
+
}
|
|
1710
1882
|
if (entries.length === 0)
|
|
1711
1883
|
return { visible: false };
|
|
1712
1884
|
const entry = this.exactlyOne(entries, observed);
|
|
@@ -1718,11 +1890,13 @@ class Locator {
|
|
|
1718
1890
|
};
|
|
1719
1891
|
});
|
|
1720
1892
|
}
|
|
1721
|
-
|
|
1722
|
-
const
|
|
1723
|
-
if (
|
|
1893
|
+
async shownIn(observed) {
|
|
1894
|
+
const resolved = await this.resolveIn(observed);
|
|
1895
|
+
if (resolved.kind === "unknown")
|
|
1724
1896
|
return false;
|
|
1725
|
-
|
|
1897
|
+
if (resolved.kind === "react")
|
|
1898
|
+
return reactVisible(this.reactOnly(resolved.matches, observed), observed);
|
|
1899
|
+
return resolved.entries.length > 0 && this.exactlyOne(resolved.entries, observed).visible;
|
|
1726
1900
|
}
|
|
1727
1901
|
async isHidden() {
|
|
1728
1902
|
return !await this.isVisible();
|
|
@@ -1735,7 +1909,7 @@ class Locator {
|
|
|
1735
1909
|
}
|
|
1736
1910
|
boundingBox() {
|
|
1737
1911
|
return this.traced("boundingBox", async () => {
|
|
1738
|
-
const { entries, observed } = await this.
|
|
1912
|
+
const { entries, observed } = await this.conclusive({ reuse: false });
|
|
1739
1913
|
if (entries.length === 0) {
|
|
1740
1914
|
const [only, ...others] = await this.reactCandidates(observed);
|
|
1741
1915
|
if (only !== undefined && others.length === 0)
|
|
@@ -1762,14 +1936,19 @@ class Locator {
|
|
|
1762
1936
|
return { done: false, state: undefined };
|
|
1763
1937
|
}
|
|
1764
1938
|
const { observed } = observation;
|
|
1765
|
-
const
|
|
1766
|
-
|
|
1767
|
-
|
|
1939
|
+
const resolved = await this.resolveIn(observed);
|
|
1940
|
+
if (resolved.kind === "unknown")
|
|
1941
|
+
return { done: false, state: { snapshot: observed.snapshot, degraded: resolved.read } };
|
|
1942
|
+
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));
|
|
1943
|
+
return done ? { done: true, value: true } : { done: false, state: { snapshot: observed.snapshot } };
|
|
1768
1944
|
}, timeoutMs);
|
|
1769
1945
|
if (result.status === "done")
|
|
1770
1946
|
return;
|
|
1947
|
+
const last = result.last;
|
|
1948
|
+
if (last?.degraded !== undefined)
|
|
1949
|
+
throw this.degradedFailure(last.degraded, timeoutMs, last.snapshot);
|
|
1771
1950
|
const message = `${this} did not become ${state} within ${timeoutMs} ms`;
|
|
1772
|
-
throw new E2eError2("TIMEOUT", message,
|
|
1951
|
+
throw new E2eError2("TIMEOUT", message, last === undefined ? undefined : this.rt.excerpt(last.snapshot));
|
|
1773
1952
|
}
|
|
1774
1953
|
act(verb, run, suffix = "") {
|
|
1775
1954
|
return this.rt.step(`${verb} ${this}${suffix}`, run);
|
|
@@ -1795,6 +1974,8 @@ class Locator {
|
|
|
1795
1974
|
}
|
|
1796
1975
|
if (seen?.kind === "driver")
|
|
1797
1976
|
throw new E2eError2("DRIVER", `snapshot kept failing: ${seen.message}`);
|
|
1977
|
+
if (seen?.kind === "degraded")
|
|
1978
|
+
throw this.degradedFailure(seen.read, timeoutMs, seen.snapshot);
|
|
1798
1979
|
throw new E2eError2("LOCATOR_NOT_FOUND", `${this} matched no elements within ${timeoutMs} ms`, seen === undefined ? undefined : this.rt.excerpt(seen.snapshot));
|
|
1799
1980
|
}
|
|
1800
1981
|
async actionableLook(spec, allowReact, anyFrame) {
|
|
@@ -1909,7 +2090,7 @@ class Locator {
|
|
|
1909
2090
|
watch.unchanged = 0;
|
|
1910
2091
|
return { done: false, state: undefined };
|
|
1911
2092
|
}
|
|
1912
|
-
if (until.
|
|
2093
|
+
if (await until.shownIn(observation.observed))
|
|
1913
2094
|
return { done: true, value: "arrived" };
|
|
1914
2095
|
if (snapshotHash(observation.observed.snapshot) === watch.pressedOn)
|
|
1915
2096
|
watch.unchanged += 1;
|
|
@@ -2034,10 +2215,17 @@ class Locator {
|
|
|
2034
2215
|
return scrollUntilVisible(this.rt, this, options);
|
|
2035
2216
|
}
|
|
2036
2217
|
async reactStep(spec, observed, allowReact) {
|
|
2037
|
-
const
|
|
2218
|
+
const read = degradedRead(observed.snapshot);
|
|
2219
|
+
const testId = plainTestId(this.expr);
|
|
2220
|
+
const lookup = testId === undefined ? undefined : await this.rt.reactLookup(testId, observed);
|
|
2221
|
+
const found = lookup?.answered === true ? lookup.matches : [];
|
|
2038
2222
|
const [match, ...others] = found;
|
|
2039
|
-
if (match === undefined)
|
|
2223
|
+
if (match === undefined) {
|
|
2224
|
+
if (read !== undefined && lookup?.answered !== true) {
|
|
2225
|
+
return { done: false, state: { kind: "degraded", read, snapshot: observed.snapshot } };
|
|
2226
|
+
}
|
|
2040
2227
|
return { done: false, state: { kind: "none", snapshot: observed.snapshot } };
|
|
2228
|
+
}
|
|
2041
2229
|
if (!allowReact)
|
|
2042
2230
|
return { done: false, state: { kind: "react", snapshot: observed.snapshot, matches: found.length } };
|
|
2043
2231
|
if (others.length > 0) {
|
|
@@ -2176,6 +2364,18 @@ function reached(state, entry) {
|
|
|
2176
2364
|
return entry === undefined || !entry.visible;
|
|
2177
2365
|
}
|
|
2178
2366
|
}
|
|
2367
|
+
function reachedByReact(state, visible) {
|
|
2368
|
+
switch (state) {
|
|
2369
|
+
case "attached":
|
|
2370
|
+
return true;
|
|
2371
|
+
case "detached":
|
|
2372
|
+
return false;
|
|
2373
|
+
case "visible":
|
|
2374
|
+
return visible;
|
|
2375
|
+
case "hidden":
|
|
2376
|
+
return !visible;
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2179
2379
|
function blockedReason(entry, spec, observed) {
|
|
2180
2380
|
if (!entry.visible)
|
|
2181
2381
|
return "is not visible";
|
|
@@ -2189,7 +2389,11 @@ function blockedReason(entry, spec, observed) {
|
|
|
2189
2389
|
function isOnScreenEntry(entry, observed) {
|
|
2190
2390
|
return entry?.visible === true && isOnScreen(tapPointOf(entry), observed.snapshot.screen);
|
|
2191
2391
|
}
|
|
2192
|
-
function scrollGaveUp(target, absent, effort,
|
|
2392
|
+
function scrollGaveUp(target, absent, effort, observed, waitedMs) {
|
|
2393
|
+
const read = absent ? degradedRead(observed.snapshot) : undefined;
|
|
2394
|
+
if (read !== undefined)
|
|
2395
|
+
return target.degradedFailure(read, waitedMs, observed.snapshot);
|
|
2396
|
+
const screen = target.runtime.excerpt(observed.snapshot);
|
|
2193
2397
|
if (absent)
|
|
2194
2398
|
return new E2eError2("LOCATOR_NOT_FOUND", `${target} was not found after ${effort}`, screen);
|
|
2195
2399
|
return new E2eError2("NOT_ACTIONABLE", `${target} is still not on screen after ${effort}`, screen);
|
|
@@ -2218,7 +2422,8 @@ async function scrollUntilVisible(rt, target, options = {}) {
|
|
|
2218
2422
|
if (isOnScreenEntry(entry, observed))
|
|
2219
2423
|
return;
|
|
2220
2424
|
if (swipes >= maxSwipes || budget.remaining() <= 0) {
|
|
2221
|
-
|
|
2425
|
+
const effort = `${swipes} swipes ${direction}`;
|
|
2426
|
+
throw scrollGaveUp(target, entry === undefined, effort, observed, budget.total);
|
|
2222
2427
|
}
|
|
2223
2428
|
await scrollOnce(rt, observed, direction, options.momentum);
|
|
2224
2429
|
await observed.driver.settle(SCROLL_SETTLE);
|
|
@@ -4421,19 +4626,113 @@ function driverErr(code, message, extra) {
|
|
|
4421
4626
|
}
|
|
4422
4627
|
|
|
4423
4628
|
// ../../packages/e2e/src/driver/ios/simd-protocol.ts
|
|
4629
|
+
import { z as z7 } from "zod";
|
|
4630
|
+
|
|
4631
|
+
// ../../packages/e2e/src/driver/bridge-stall.ts
|
|
4424
4632
|
import { z as z6 } from "zod";
|
|
4633
|
+
var bridgeStallSchema = z6.looseObject({
|
|
4634
|
+
stage: z6.string(),
|
|
4635
|
+
readMs: z6.number().optional(),
|
|
4636
|
+
deadlineMs: z6.number().optional(),
|
|
4637
|
+
guestAgeMs: z6.number().optional(),
|
|
4638
|
+
cold: z6.boolean(),
|
|
4639
|
+
cooldownRemainingMs: z6.number().optional(),
|
|
4640
|
+
probes: z6.number(),
|
|
4641
|
+
recycles: z6.number().optional(),
|
|
4642
|
+
recyclesExhausted: z6.boolean().optional()
|
|
4643
|
+
});
|
|
4644
|
+
var SPAN_FIELDS = [
|
|
4645
|
+
["stallStage", "stage"],
|
|
4646
|
+
["stallReadMs", "readMs"],
|
|
4647
|
+
["stallDeadlineMs", "deadlineMs"],
|
|
4648
|
+
["stallGuestAgeMs", "guestAgeMs"],
|
|
4649
|
+
["stallCold", "cold"],
|
|
4650
|
+
["stallCooldownMs", "cooldownRemainingMs"],
|
|
4651
|
+
["stallProbes", "probes"],
|
|
4652
|
+
["stallRecycles", "recycles"],
|
|
4653
|
+
["stallRecyclesExhausted", "recyclesExhausted"]
|
|
4654
|
+
];
|
|
4655
|
+
function toBridgeStall(wire) {
|
|
4656
|
+
const stall = { stage: wire.stage, cold: wire.cold, probes: wire.probes };
|
|
4657
|
+
if (wire.readMs !== undefined)
|
|
4658
|
+
stall.readMs = wire.readMs;
|
|
4659
|
+
if (wire.deadlineMs !== undefined)
|
|
4660
|
+
stall.deadlineMs = wire.deadlineMs;
|
|
4661
|
+
if (wire.guestAgeMs !== undefined)
|
|
4662
|
+
stall.guestAgeMs = wire.guestAgeMs;
|
|
4663
|
+
if (wire.cooldownRemainingMs !== undefined)
|
|
4664
|
+
stall.cooldownRemainingMs = wire.cooldownRemainingMs;
|
|
4665
|
+
if (wire.recycles !== undefined)
|
|
4666
|
+
stall.recycles = wire.recycles;
|
|
4667
|
+
if (wire.recyclesExhausted !== undefined)
|
|
4668
|
+
stall.recyclesExhausted = wire.recyclesExhausted;
|
|
4669
|
+
return stall;
|
|
4670
|
+
}
|
|
4671
|
+
function noteBridgeStall(stall) {
|
|
4672
|
+
for (const [key, field] of SPAN_FIELDS) {
|
|
4673
|
+
const value = stall[field];
|
|
4674
|
+
if (value !== undefined)
|
|
4675
|
+
noteSpanDetail(key, value);
|
|
4676
|
+
}
|
|
4677
|
+
}
|
|
4678
|
+
function bridgeStallFromSpan(detail) {
|
|
4679
|
+
const stage = detail?.stallStage;
|
|
4680
|
+
if (detail === undefined || typeof stage !== "string")
|
|
4681
|
+
return;
|
|
4682
|
+
const stall = {
|
|
4683
|
+
stage,
|
|
4684
|
+
cold: detail.stallCold === true,
|
|
4685
|
+
probes: typeof detail.stallProbes === "number" ? detail.stallProbes : 0
|
|
4686
|
+
};
|
|
4687
|
+
const numbers = [
|
|
4688
|
+
["stallReadMs", "readMs"],
|
|
4689
|
+
["stallDeadlineMs", "deadlineMs"],
|
|
4690
|
+
["stallGuestAgeMs", "guestAgeMs"],
|
|
4691
|
+
["stallCooldownMs", "cooldownRemainingMs"],
|
|
4692
|
+
["stallRecycles", "recycles"]
|
|
4693
|
+
];
|
|
4694
|
+
for (const [key, field] of numbers) {
|
|
4695
|
+
const value = detail[key];
|
|
4696
|
+
if (typeof value === "number")
|
|
4697
|
+
stall[field] = value;
|
|
4698
|
+
}
|
|
4699
|
+
if (typeof detail.stallRecyclesExhausted === "boolean")
|
|
4700
|
+
stall.recyclesExhausted = detail.stallRecyclesExhausted;
|
|
4701
|
+
return stall;
|
|
4702
|
+
}
|
|
4703
|
+
var seconds = (ms) => `${(ms / 1000).toFixed(1)} s`;
|
|
4704
|
+
function formatBridgeStall(stall) {
|
|
4705
|
+
const parts = [`stage ${stall.stage}`];
|
|
4706
|
+
if (stall.readMs !== undefined) {
|
|
4707
|
+
parts.push(stall.deadlineMs === undefined ? `read ${stall.readMs} ms` : `read ${stall.readMs} ms of a ${stall.deadlineMs} ms deadline`);
|
|
4708
|
+
} else if (stall.deadlineMs !== undefined)
|
|
4709
|
+
parts.push(`${stall.deadlineMs} ms deadline`);
|
|
4710
|
+
parts.push(stall.cold ? "cold (first read)" : "warm");
|
|
4711
|
+
if (stall.guestAgeMs !== undefined)
|
|
4712
|
+
parts.push(`guest ${seconds(stall.guestAgeMs)} old`);
|
|
4713
|
+
if (stall.cooldownRemainingMs !== undefined)
|
|
4714
|
+
parts.push(`cooldown ${seconds(stall.cooldownRemainingMs)} left`);
|
|
4715
|
+
parts.push(`${stall.probes} failed bridge reads in a row`);
|
|
4716
|
+
if (stall.recycles !== undefined) {
|
|
4717
|
+
const guests = stall.recycles === 1 ? "guest" : "guests";
|
|
4718
|
+
parts.push(`${stall.recycles} stalled ${guests} recycled${stall.recyclesExhausted === true ? ", none left" : ""}`);
|
|
4719
|
+
}
|
|
4720
|
+
return parts.join(" \xB7 ");
|
|
4721
|
+
}
|
|
4722
|
+
|
|
4723
|
+
// ../../packages/e2e/src/driver/ios/simd-protocol.ts
|
|
4425
4724
|
var protocolVersion = 1;
|
|
4426
|
-
var rectSchema2 =
|
|
4427
|
-
x:
|
|
4428
|
-
y:
|
|
4429
|
-
width:
|
|
4430
|
-
height:
|
|
4725
|
+
var rectSchema2 = z7.object({
|
|
4726
|
+
x: z7.number(),
|
|
4727
|
+
y: z7.number(),
|
|
4728
|
+
width: z7.number(),
|
|
4729
|
+
height: z7.number()
|
|
4431
4730
|
});
|
|
4432
|
-
var screenInfoSchema =
|
|
4433
|
-
width:
|
|
4434
|
-
height:
|
|
4435
|
-
scale:
|
|
4436
|
-
rotation:
|
|
4731
|
+
var screenInfoSchema = z7.object({
|
|
4732
|
+
width: z7.number(),
|
|
4733
|
+
height: z7.number(),
|
|
4734
|
+
scale: z7.number(),
|
|
4735
|
+
rotation: z7.number().optional()
|
|
4437
4736
|
});
|
|
4438
4737
|
var ROLES = [
|
|
4439
4738
|
"button",
|
|
@@ -4460,29 +4759,29 @@ var ROLES = [
|
|
|
4460
4759
|
"application",
|
|
4461
4760
|
"other"
|
|
4462
4761
|
];
|
|
4463
|
-
var pointSchema =
|
|
4464
|
-
var wireElementSchema =
|
|
4465
|
-
id:
|
|
4466
|
-
role:
|
|
4467
|
-
rawType:
|
|
4468
|
-
label:
|
|
4469
|
-
identifier:
|
|
4470
|
-
value:
|
|
4471
|
-
text:
|
|
4472
|
-
placeholder:
|
|
4762
|
+
var pointSchema = z7.object({ x: z7.number(), y: z7.number() });
|
|
4763
|
+
var wireElementSchema = z7.lazy(() => z7.object({
|
|
4764
|
+
id: z7.string().nullish(),
|
|
4765
|
+
role: z7.enum(ROLES),
|
|
4766
|
+
rawType: z7.string(),
|
|
4767
|
+
label: z7.string().nullish(),
|
|
4768
|
+
identifier: z7.string().nullish(),
|
|
4769
|
+
value: z7.string().nullish(),
|
|
4770
|
+
text: z7.string().nullish(),
|
|
4771
|
+
placeholder: z7.string().nullish(),
|
|
4473
4772
|
frame: rectSchema2,
|
|
4474
4773
|
normFrame: rectSchema2.nullish(),
|
|
4475
|
-
traits:
|
|
4476
|
-
enabled:
|
|
4477
|
-
focused:
|
|
4478
|
-
hidden:
|
|
4479
|
-
selected:
|
|
4480
|
-
checked:
|
|
4481
|
-
hittable:
|
|
4774
|
+
traits: z7.array(z7.string()).nullish(),
|
|
4775
|
+
enabled: z7.boolean().nullish(),
|
|
4776
|
+
focused: z7.boolean().nullish(),
|
|
4777
|
+
hidden: z7.boolean().nullish(),
|
|
4778
|
+
selected: z7.boolean().nullish(),
|
|
4779
|
+
checked: z7.boolean().nullish(),
|
|
4780
|
+
hittable: z7.boolean().nullish(),
|
|
4482
4781
|
tapPoint: pointSchema.nullish(),
|
|
4483
|
-
pid:
|
|
4484
|
-
depth:
|
|
4485
|
-
children:
|
|
4782
|
+
pid: z7.number().nullish(),
|
|
4783
|
+
depth: z7.number().nullish(),
|
|
4784
|
+
children: z7.array(wireElementSchema).nullish()
|
|
4486
4785
|
}));
|
|
4487
4786
|
var ROLE_SET = new Set(ROLES);
|
|
4488
4787
|
var isBag = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -4520,33 +4819,33 @@ function wireElementProblem(value) {
|
|
|
4520
4819
|
const issue = parsed.error.issues[0];
|
|
4521
4820
|
return issue ? `${issue.path.join(".") || "(element)"}: ${issue.message}` : "invalid element";
|
|
4522
4821
|
}
|
|
4523
|
-
var wireErrorSchema =
|
|
4524
|
-
code:
|
|
4525
|
-
message:
|
|
4526
|
-
retryable:
|
|
4527
|
-
detail:
|
|
4822
|
+
var wireErrorSchema = z7.object({
|
|
4823
|
+
code: z7.string(),
|
|
4824
|
+
message: z7.string(),
|
|
4825
|
+
retryable: z7.boolean().optional(),
|
|
4826
|
+
detail: z7.unknown().optional()
|
|
4528
4827
|
});
|
|
4529
|
-
var readyEventSchema =
|
|
4530
|
-
event:
|
|
4531
|
-
protocol:
|
|
4532
|
-
version:
|
|
4533
|
-
udid:
|
|
4534
|
-
hid:
|
|
4535
|
-
ax:
|
|
4828
|
+
var readyEventSchema = z7.object({
|
|
4829
|
+
event: z7.literal("ready"),
|
|
4830
|
+
protocol: z7.number(),
|
|
4831
|
+
version: z7.string(),
|
|
4832
|
+
udid: z7.string(),
|
|
4833
|
+
hid: z7.object({ transport: z7.string() }),
|
|
4834
|
+
ax: z7.object({ default: z7.string(), bridge: z7.string() }),
|
|
4536
4835
|
screen: screenInfoSchema
|
|
4537
4836
|
});
|
|
4538
|
-
var logEventSchema =
|
|
4539
|
-
event:
|
|
4540
|
-
level:
|
|
4541
|
-
message:
|
|
4542
|
-
op:
|
|
4543
|
-
id:
|
|
4837
|
+
var logEventSchema = z7.object({
|
|
4838
|
+
event: z7.literal("log"),
|
|
4839
|
+
level: z7.enum(["debug", "info", "warn", "error"]),
|
|
4840
|
+
message: z7.string(),
|
|
4841
|
+
op: z7.string().optional(),
|
|
4842
|
+
id: z7.string().optional()
|
|
4544
4843
|
});
|
|
4545
|
-
var fatalEventSchema =
|
|
4546
|
-
var eventSchema =
|
|
4547
|
-
var responseSchema =
|
|
4548
|
-
|
|
4549
|
-
|
|
4844
|
+
var fatalEventSchema = z7.object({ event: z7.literal("fatal"), error: wireErrorSchema });
|
|
4845
|
+
var eventSchema = z7.discriminatedUnion("event", [readyEventSchema, logEventSchema, fatalEventSchema]);
|
|
4846
|
+
var responseSchema = z7.discriminatedUnion("ok", [
|
|
4847
|
+
z7.object({ id: z7.string(), ok: z7.literal(true), data: z7.unknown().optional() }),
|
|
4848
|
+
z7.object({ id: z7.string(), ok: z7.literal(false), error: wireErrorSchema })
|
|
4550
4849
|
]);
|
|
4551
4850
|
function parseLine(line) {
|
|
4552
4851
|
let json;
|
|
@@ -4562,74 +4861,80 @@ function parseLine(line) {
|
|
|
4562
4861
|
const response = responseSchema.safeParse(json);
|
|
4563
4862
|
return response.success ? { success: true, message: { kind: "response", response: response.data } } : { success: false, reason: `bad response: ${response.error.message}` };
|
|
4564
4863
|
}
|
|
4565
|
-
var healthDataSchema =
|
|
4566
|
-
version:
|
|
4567
|
-
udid:
|
|
4568
|
-
hid:
|
|
4569
|
-
ax:
|
|
4570
|
-
default:
|
|
4571
|
-
bridge:
|
|
4572
|
-
error:
|
|
4573
|
-
lastError:
|
|
4864
|
+
var healthDataSchema = z7.looseObject({
|
|
4865
|
+
version: z7.string(),
|
|
4866
|
+
udid: z7.string(),
|
|
4867
|
+
hid: z7.object({ transport: z7.string() }),
|
|
4868
|
+
ax: z7.object({
|
|
4869
|
+
default: z7.string(),
|
|
4870
|
+
bridge: z7.enum(["available", "degraded", "missing", "failed"]),
|
|
4871
|
+
error: z7.string().optional(),
|
|
4872
|
+
lastError: z7.object({ message: z7.string(), agoMs: z7.number() }).optional()
|
|
4574
4873
|
}),
|
|
4575
4874
|
screen: screenInfoSchema,
|
|
4576
|
-
socket:
|
|
4577
|
-
idb:
|
|
4578
|
-
xcode:
|
|
4579
|
-
builtWith:
|
|
4580
|
-
coreSimulatorVersion:
|
|
4581
|
-
frontmost:
|
|
4582
|
-
|
|
4583
|
-
|
|
4875
|
+
socket: z7.object({ path: z7.string(), clients: z7.number() }).optional(),
|
|
4876
|
+
idb: z7.string().optional(),
|
|
4877
|
+
xcode: z7.string().optional(),
|
|
4878
|
+
builtWith: z7.object({ xcode: z7.string().optional(), idb: z7.string().optional() }).optional(),
|
|
4879
|
+
coreSimulatorVersion: z7.string().nullish(),
|
|
4880
|
+
frontmost: z7.object({ unresolvedAgoMs: z7.number(), method: z7.string() }).optional(),
|
|
4881
|
+
bridgeRecycles: z7.object({ count: z7.number(), exhausted: z7.boolean() }).optional(),
|
|
4882
|
+
state: z7.string().optional(),
|
|
4883
|
+
uptimeMs: z7.number().optional()
|
|
4584
4884
|
});
|
|
4585
|
-
var snapshotDataSchema =
|
|
4586
|
-
backend:
|
|
4885
|
+
var snapshotDataSchema = z7.looseObject({
|
|
4886
|
+
backend: z7.enum(["axbridge", "ax", "uiautomator"]),
|
|
4587
4887
|
screen: screenInfoSchema,
|
|
4588
|
-
modal:
|
|
4589
|
-
truncated:
|
|
4590
|
-
elements:
|
|
4591
|
-
ms:
|
|
4592
|
-
fallback:
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4888
|
+
modal: z7.object({ pid: z7.number().optional(), description: z7.string().optional() }).nullish(),
|
|
4889
|
+
truncated: z7.boolean(),
|
|
4890
|
+
elements: z7.array(z7.custom(isWireElement, { error: (issue) => wireElementProblem(issue.input) })),
|
|
4891
|
+
ms: z7.number(),
|
|
4892
|
+
fallback: z7.object({
|
|
4893
|
+
from: z7.string(),
|
|
4894
|
+
to: z7.string(),
|
|
4895
|
+
reason: z7.string(),
|
|
4896
|
+
stall: bridgeStallSchema.optional()
|
|
4897
|
+
}).optional(),
|
|
4898
|
+
target: z7.object({ pid: z7.number(), source: z7.string() }).optional(),
|
|
4899
|
+
readMs: z7.number().optional(),
|
|
4900
|
+
nodes: z7.number().optional()
|
|
4596
4901
|
});
|
|
4597
4902
|
var elementAtPointDataSchema = wireElementSchema.nullable();
|
|
4598
|
-
var screenshotDataSchema =
|
|
4599
|
-
path:
|
|
4600
|
-
png:
|
|
4601
|
-
width:
|
|
4602
|
-
height:
|
|
4903
|
+
var screenshotDataSchema = z7.looseObject({
|
|
4904
|
+
path: z7.string().optional(),
|
|
4905
|
+
png: z7.string().optional(),
|
|
4906
|
+
width: z7.number().optional(),
|
|
4907
|
+
height: z7.number().optional()
|
|
4603
4908
|
});
|
|
4604
|
-
var settleDataSchema =
|
|
4605
|
-
quiet:
|
|
4606
|
-
waitedMs:
|
|
4607
|
-
via:
|
|
4608
|
-
reason:
|
|
4609
|
-
frontmostPid:
|
|
4909
|
+
var settleDataSchema = z7.looseObject({
|
|
4910
|
+
quiet: z7.boolean(),
|
|
4911
|
+
waitedMs: z7.number(),
|
|
4912
|
+
via: z7.enum(["stream", "snapshot"]).optional().catch(undefined),
|
|
4913
|
+
reason: z7.string().optional(),
|
|
4914
|
+
frontmostPid: z7.number().optional()
|
|
4610
4915
|
});
|
|
4611
|
-
var rebindDataSchema =
|
|
4612
|
-
bound:
|
|
4613
|
-
waitedMs:
|
|
4614
|
-
pid:
|
|
4615
|
-
restarts:
|
|
4616
|
-
recycled:
|
|
4617
|
-
reason:
|
|
4916
|
+
var rebindDataSchema = z7.looseObject({
|
|
4917
|
+
bound: z7.boolean(),
|
|
4918
|
+
waitedMs: z7.number(),
|
|
4919
|
+
pid: z7.number().optional(),
|
|
4920
|
+
restarts: z7.number().optional(),
|
|
4921
|
+
recycled: z7.boolean().optional(),
|
|
4922
|
+
reason: z7.string().optional()
|
|
4618
4923
|
});
|
|
4619
|
-
var alertButtonsDataSchema =
|
|
4620
|
-
title:
|
|
4621
|
-
message:
|
|
4622
|
-
buttons:
|
|
4924
|
+
var alertButtonsDataSchema = z7.object({
|
|
4925
|
+
title: z7.string().optional(),
|
|
4926
|
+
message: z7.string().optional(),
|
|
4927
|
+
buttons: z7.array(wireElementSchema)
|
|
4623
4928
|
}).nullable();
|
|
4624
|
-
var frontmostDataSchema =
|
|
4625
|
-
frontmost:
|
|
4626
|
-
pid:
|
|
4627
|
-
frontmostPid:
|
|
4929
|
+
var frontmostDataSchema = z7.looseObject({
|
|
4930
|
+
frontmost: z7.boolean(),
|
|
4931
|
+
pid: z7.number().optional(),
|
|
4932
|
+
frontmostPid: z7.number().optional()
|
|
4628
4933
|
});
|
|
4629
|
-
var launchDataSchema =
|
|
4630
|
-
var terminateDataSchema =
|
|
4631
|
-
var orientationDataSchema =
|
|
4632
|
-
orientation:
|
|
4934
|
+
var launchDataSchema = z7.looseObject({ pid: z7.number() });
|
|
4935
|
+
var terminateDataSchema = z7.looseObject({ terminated: z7.boolean() });
|
|
4936
|
+
var orientationDataSchema = z7.object({
|
|
4937
|
+
orientation: z7.enum([
|
|
4633
4938
|
"portrait",
|
|
4634
4939
|
"portraitUpsideDown",
|
|
4635
4940
|
"landscapeLeft",
|
|
@@ -4638,7 +4943,7 @@ var orientationDataSchema = z6.object({
|
|
|
4638
4943
|
"faceDown",
|
|
4639
4944
|
"unknown"
|
|
4640
4945
|
]),
|
|
4641
|
-
source:
|
|
4946
|
+
source: z7.enum(["device", "written", "assumed"]).optional()
|
|
4642
4947
|
});
|
|
4643
4948
|
var opSchemas = {
|
|
4644
4949
|
health: healthDataSchema,
|
|
@@ -5079,7 +5384,7 @@ async function createSimdClient(factory, options = {}) {
|
|
|
5079
5384
|
const transport = session.data.transport;
|
|
5080
5385
|
if (!transport)
|
|
5081
5386
|
return { success: false, error: driverError("E_INTERNAL", "warden-simd transport missing") };
|
|
5082
|
-
const timeoutMs = opts.timeoutMs ?? defaultTimeoutMs;
|
|
5387
|
+
const timeoutMs = Math.max(opts.timeoutMs ?? defaultTimeoutMs, opts.minTimeoutMs ?? 0);
|
|
5083
5388
|
const id = String(++seq);
|
|
5084
5389
|
const result = await new Promise((resolve) => {
|
|
5085
5390
|
const timer = setTimeout(() => {
|
|
@@ -5342,7 +5647,7 @@ function traceDriver(driver, options) {
|
|
|
5342
5647
|
}
|
|
5343
5648
|
|
|
5344
5649
|
// ../../packages/core/src/a11y/a11y.config.ts
|
|
5345
|
-
import { z as
|
|
5650
|
+
import { z as z8 } from "zod";
|
|
5346
5651
|
var A11Y_RULE_IDS = [
|
|
5347
5652
|
"missing-name",
|
|
5348
5653
|
"image-no-name",
|
|
@@ -5355,11 +5660,11 @@ var A11Y_RULE_IDS = [
|
|
|
5355
5660
|
"text-clipped",
|
|
5356
5661
|
"native"
|
|
5357
5662
|
];
|
|
5358
|
-
var ruleId =
|
|
5359
|
-
var a11yAuditConfigSchema =
|
|
5360
|
-
ignore:
|
|
5361
|
-
minSeverity:
|
|
5362
|
-
rules:
|
|
5663
|
+
var ruleId = z8.enum(A11Y_RULE_IDS);
|
|
5664
|
+
var a11yAuditConfigSchema = z8.object({
|
|
5665
|
+
ignore: z8.array(z8.object({ rule: ruleId, identifier: z8.string().min(1).optional() }).strict()).optional(),
|
|
5666
|
+
minSeverity: z8.enum(["error", "warning"]).optional(),
|
|
5667
|
+
rules: z8.array(ruleId).min(1).optional()
|
|
5363
5668
|
}).strict();
|
|
5364
5669
|
function parseA11yAuditEnv(raw) {
|
|
5365
5670
|
let json;
|
|
@@ -5375,7 +5680,7 @@ function parseA11yAuditEnv(raw) {
|
|
|
5375
5680
|
}
|
|
5376
5681
|
|
|
5377
5682
|
// ../../packages/core/src/conditions/conditions.config.ts
|
|
5378
|
-
import { z as
|
|
5683
|
+
import { z as z9 } from "zod";
|
|
5379
5684
|
|
|
5380
5685
|
// ../../packages/core/src/duration.ts
|
|
5381
5686
|
var UNIT_MS = { ms: 1, s: 1000, m: 60000, h: 3600000, d: 86400000 };
|
|
@@ -5536,51 +5841,51 @@ function appliedA11y(op, applied) {
|
|
|
5536
5841
|
|
|
5537
5842
|
// ../../packages/core/src/conditions/conditions.config.ts
|
|
5538
5843
|
var NETWORK_WORDS = ["online", "offline", ...NETWORK_PRESET_NAMES];
|
|
5539
|
-
var nonNegative2 =
|
|
5540
|
-
var customNetworkSchema =
|
|
5844
|
+
var nonNegative2 = z9.number().nonnegative().finite();
|
|
5845
|
+
var customNetworkSchema = z9.object({
|
|
5541
5846
|
latencyMs: nonNegative2.optional(),
|
|
5542
5847
|
jitterMs: nonNegative2.optional(),
|
|
5543
5848
|
downKbps: nonNegative2.optional(),
|
|
5544
5849
|
upKbps: nonNegative2.optional(),
|
|
5545
|
-
lossPct:
|
|
5850
|
+
lossPct: z9.number().min(0).max(100).optional()
|
|
5546
5851
|
}).strict();
|
|
5547
|
-
var isoDate =
|
|
5548
|
-
var offsetDuration =
|
|
5549
|
-
var textSize =
|
|
5550
|
-
var a11yConfigSchema =
|
|
5852
|
+
var isoDate = z9.string().refine((v) => !Number.isNaN(Date.parse(v)), { message: "invalid date (use ISO 8601)" });
|
|
5853
|
+
var offsetDuration = z9.string().refine((v) => parseDuration(v).success, { message: "invalid duration (use e.g. 2d)" });
|
|
5854
|
+
var textSize = z9.union([z9.enum(TEXT_SIZE_NAMES), z9.number().positive().finite()]);
|
|
5855
|
+
var a11yConfigSchema = z9.object({
|
|
5551
5856
|
textSize: textSize.optional(),
|
|
5552
|
-
boldText:
|
|
5553
|
-
contrast:
|
|
5554
|
-
reduceMotion:
|
|
5857
|
+
boldText: z9.boolean().optional(),
|
|
5858
|
+
contrast: z9.enum(["increased", "normal"]).optional(),
|
|
5859
|
+
reduceMotion: z9.boolean().optional()
|
|
5555
5860
|
}).strict();
|
|
5556
|
-
var conditionsConfigSchema =
|
|
5557
|
-
network:
|
|
5558
|
-
location:
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
lat:
|
|
5562
|
-
lon:
|
|
5563
|
-
altM:
|
|
5861
|
+
var conditionsConfigSchema = z9.object({
|
|
5862
|
+
network: z9.union([z9.enum(NETWORK_WORDS), customNetworkSchema]).optional(),
|
|
5863
|
+
location: z9.union([
|
|
5864
|
+
z9.enum(["city-run", "city-bike", "freeway"]),
|
|
5865
|
+
z9.object({
|
|
5866
|
+
lat: z9.number().min(-90).max(90),
|
|
5867
|
+
lon: z9.number().min(-180).max(180),
|
|
5868
|
+
altM: z9.number().finite().optional()
|
|
5564
5869
|
}).strict()
|
|
5565
5870
|
]).optional(),
|
|
5566
|
-
clock:
|
|
5871
|
+
clock: z9.union([
|
|
5567
5872
|
isoDate,
|
|
5568
|
-
|
|
5569
|
-
|
|
5873
|
+
z9.object({ at: isoDate, frozen: z9.boolean().optional() }).strict(),
|
|
5874
|
+
z9.object({ offset: offsetDuration }).strict()
|
|
5570
5875
|
]).optional(),
|
|
5571
|
-
permissions:
|
|
5572
|
-
locale:
|
|
5573
|
-
timezone:
|
|
5876
|
+
permissions: z9.partialRecord(z9.enum(PERMISSION_NAMES), z9.enum(["granted", "denied", "unset"])).optional(),
|
|
5877
|
+
locale: z9.string().min(1).optional(),
|
|
5878
|
+
timezone: z9.string().min(1).optional(),
|
|
5574
5879
|
a11y: a11yConfigSchema.optional()
|
|
5575
5880
|
}).strict();
|
|
5576
|
-
var cameraFeedInput =
|
|
5577
|
-
|
|
5578
|
-
|
|
5881
|
+
var cameraFeedInput = z9.union([
|
|
5882
|
+
z9.string().min(1),
|
|
5883
|
+
z9.object({ path: z9.string().min(1), loop: z9.boolean().optional() }).strict()
|
|
5579
5884
|
]);
|
|
5580
|
-
var cameraConfigSchema =
|
|
5581
|
-
var cameraFeedsSchema =
|
|
5582
|
-
back:
|
|
5583
|
-
front:
|
|
5885
|
+
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" });
|
|
5886
|
+
var cameraFeedsSchema = z9.object({
|
|
5887
|
+
back: z9.object({ path: z9.string().min(1), loop: z9.boolean() }).strict().optional(),
|
|
5888
|
+
front: z9.object({ path: z9.string().min(1), loop: z9.boolean() }).strict().optional()
|
|
5584
5889
|
}).strict();
|
|
5585
5890
|
function parseCameraFeedsEnv(raw) {
|
|
5586
5891
|
let json;
|
|
@@ -5662,7 +5967,7 @@ function parseConditionsEnv(raw) {
|
|
|
5662
5967
|
}
|
|
5663
5968
|
|
|
5664
5969
|
// ../../packages/e2e/src/env.ts
|
|
5665
|
-
import { z as
|
|
5970
|
+
import { z as z10 } from "zod";
|
|
5666
5971
|
var ENV_NAMES = {
|
|
5667
5972
|
udid: "WARDEN_UDID",
|
|
5668
5973
|
deviceName: "WARDEN_DEVICE_NAME",
|
|
@@ -5700,68 +6005,68 @@ var ENV_NAMES = {
|
|
|
5700
6005
|
var DEFAULT_TIMEOUT_MS5 = 120000;
|
|
5701
6006
|
var DEFAULT_ACTION_TIMEOUT_MS = 30000;
|
|
5702
6007
|
var DEFAULT_ASSERTION_TIMEOUT_MS = 5000;
|
|
5703
|
-
var toggle =
|
|
5704
|
-
var millis =
|
|
5705
|
-
var launchArgs =
|
|
6008
|
+
var toggle = z10.enum(["1", "true", "0", "false"]).transform((v) => v === "1" || v === "true");
|
|
6009
|
+
var millis = z10.string().regex(/^\d+$/, "must be a whole number of milliseconds").transform(Number).pipe(z10.number().int().positive());
|
|
6010
|
+
var launchArgs = z10.string().transform((raw, ctx) => {
|
|
5706
6011
|
try {
|
|
5707
|
-
const parsed =
|
|
6012
|
+
const parsed = z10.array(z10.string()).safeParse(JSON.parse(raw));
|
|
5708
6013
|
if (parsed.success)
|
|
5709
6014
|
return parsed.data;
|
|
5710
6015
|
} catch {}
|
|
5711
6016
|
ctx.addIssue({ code: "custom", message: "must be a JSON array of strings" });
|
|
5712
|
-
return
|
|
6017
|
+
return z10.NEVER;
|
|
5713
6018
|
});
|
|
5714
|
-
var conditions =
|
|
6019
|
+
var conditions = z10.string().transform((raw, ctx) => {
|
|
5715
6020
|
const parsed = parseConditionsEnv(raw);
|
|
5716
6021
|
if (parsed.success)
|
|
5717
6022
|
return parsed.data;
|
|
5718
6023
|
ctx.addIssue({ code: "custom", message: parsed.error });
|
|
5719
|
-
return
|
|
6024
|
+
return z10.NEVER;
|
|
5720
6025
|
});
|
|
5721
|
-
var a11yAudit =
|
|
6026
|
+
var a11yAudit = z10.string().transform((raw, ctx) => {
|
|
5722
6027
|
const parsed = parseA11yAuditEnv(raw);
|
|
5723
6028
|
if (parsed.success)
|
|
5724
6029
|
return parsed.data;
|
|
5725
6030
|
ctx.addIssue({ code: "custom", message: parsed.error });
|
|
5726
|
-
return
|
|
6031
|
+
return z10.NEVER;
|
|
5727
6032
|
});
|
|
5728
|
-
var cameraFeeds =
|
|
6033
|
+
var cameraFeeds = z10.string().transform((raw, ctx) => {
|
|
5729
6034
|
const parsed = parseCameraFeedsEnv(raw);
|
|
5730
6035
|
if (parsed.success)
|
|
5731
6036
|
return parsed.data;
|
|
5732
6037
|
ctx.addIssue({ code: "custom", message: parsed.error });
|
|
5733
|
-
return
|
|
6038
|
+
return z10.NEVER;
|
|
5734
6039
|
});
|
|
5735
6040
|
var REQUIRED = "required when WARDEN_UDID is set";
|
|
5736
|
-
var schema =
|
|
5737
|
-
udid:
|
|
5738
|
-
deviceName:
|
|
5739
|
-
platform:
|
|
5740
|
-
bundleId:
|
|
5741
|
-
appPath:
|
|
5742
|
-
metroUrl:
|
|
5743
|
-
devClientScheme:
|
|
6041
|
+
var schema = z10.object({
|
|
6042
|
+
udid: z10.string().min(1),
|
|
6043
|
+
deviceName: z10.string().optional(),
|
|
6044
|
+
platform: z10.enum(["ios", "android"]).default("ios"),
|
|
6045
|
+
bundleId: z10.string({ error: REQUIRED }).min(1, REQUIRED),
|
|
6046
|
+
appPath: z10.string().optional(),
|
|
6047
|
+
metroUrl: z10.string().optional(),
|
|
6048
|
+
devClientScheme: z10.string().min(1).optional(),
|
|
5744
6049
|
launchArgs: launchArgs.default([]),
|
|
5745
|
-
out:
|
|
6050
|
+
out: z10.string().optional(),
|
|
5746
6051
|
timeout: millis.default(DEFAULT_TIMEOUT_MS5),
|
|
5747
6052
|
actionTimeout: millis.default(DEFAULT_ACTION_TIMEOUT_MS),
|
|
5748
6053
|
assertionTimeout: millis.default(DEFAULT_ASSERTION_TIMEOUT_MS),
|
|
5749
|
-
specsDir:
|
|
5750
|
-
helperDir:
|
|
5751
|
-
simd:
|
|
5752
|
-
simdSocket:
|
|
5753
|
-
iosRunnerSocket:
|
|
6054
|
+
specsDir: z10.string().optional(),
|
|
6055
|
+
helperDir: z10.string().optional(),
|
|
6056
|
+
simd: z10.string().optional(),
|
|
6057
|
+
simdSocket: z10.string().optional(),
|
|
6058
|
+
iosRunnerSocket: z10.string().optional(),
|
|
5754
6059
|
logTimestamps: toggle.default(false),
|
|
5755
|
-
deviceKind:
|
|
6060
|
+
deviceKind: z10.enum(["physical"]).optional(),
|
|
5756
6061
|
iosRunnerRestart: launchArgs.optional(),
|
|
5757
6062
|
afterReboot: launchArgs.optional(),
|
|
5758
|
-
version:
|
|
5759
|
-
bin:
|
|
5760
|
-
perf:
|
|
5761
|
-
perfBudgets:
|
|
6063
|
+
version: z10.string().optional(),
|
|
6064
|
+
bin: z10.string().optional(),
|
|
6065
|
+
perf: z10.string().optional(),
|
|
6066
|
+
perfBudgets: z10.string().optional(),
|
|
5762
6067
|
conditions: conditions.optional(),
|
|
5763
|
-
leaseId:
|
|
5764
|
-
netproxyCommand: launchArgs.pipe(
|
|
6068
|
+
leaseId: z10.string().min(1).optional(),
|
|
6069
|
+
netproxyCommand: launchArgs.pipe(z10.array(z10.string()).min(1)).optional(),
|
|
5765
6070
|
biometrics: toggle.optional(),
|
|
5766
6071
|
a11yAudit: a11yAudit.optional(),
|
|
5767
6072
|
cameraFeeds: cameraFeeds.optional()
|
|
@@ -5771,7 +6076,7 @@ function defined2(values) {
|
|
|
5771
6076
|
}
|
|
5772
6077
|
function parseArgv(raw) {
|
|
5773
6078
|
try {
|
|
5774
|
-
const parsed =
|
|
6079
|
+
const parsed = z10.array(z10.string()).min(1).safeParse(JSON.parse(raw));
|
|
5775
6080
|
if (parsed.success)
|
|
5776
6081
|
return parsed.data;
|
|
5777
6082
|
} catch {}
|
|
@@ -5841,25 +6146,43 @@ function readEnv(env, opts = {}) {
|
|
|
5841
6146
|
// ../../packages/e2e/src/runner/results.ts
|
|
5842
6147
|
import { appendFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
5843
6148
|
import { dirname as dirname3 } from "path";
|
|
5844
|
-
import { z as
|
|
5845
|
-
var
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
6149
|
+
import { z as z11 } from "zod";
|
|
6150
|
+
var bridgeReadSchema = z11.object({
|
|
6151
|
+
reason: z11.string().optional(),
|
|
6152
|
+
code: z11.string().optional(),
|
|
6153
|
+
stage: z11.string().optional(),
|
|
6154
|
+
readMs: z11.number().optional(),
|
|
6155
|
+
deadlineMs: z11.number().optional(),
|
|
6156
|
+
guestAgeMs: z11.number().optional(),
|
|
6157
|
+
cold: z11.boolean().optional(),
|
|
6158
|
+
cooldownRemainingMs: z11.number().optional(),
|
|
6159
|
+
probes: z11.number().optional(),
|
|
6160
|
+
recycles: z11.number().optional(),
|
|
6161
|
+
recyclesExhausted: z11.boolean().optional()
|
|
6162
|
+
});
|
|
6163
|
+
var testStatusSchema = z11.enum(["passed", "failed", "skipped", "timed-out"]);
|
|
6164
|
+
var testResultSchema = z11.object({
|
|
6165
|
+
file: z11.string(),
|
|
6166
|
+
title: z11.array(z11.string()),
|
|
5849
6167
|
status: testStatusSchema,
|
|
5850
|
-
durationMs:
|
|
5851
|
-
startedAt:
|
|
5852
|
-
only:
|
|
5853
|
-
error:
|
|
5854
|
-
message:
|
|
5855
|
-
code:
|
|
5856
|
-
stack:
|
|
6168
|
+
durationMs: z11.number(),
|
|
6169
|
+
startedAt: z11.number(),
|
|
6170
|
+
only: z11.boolean().optional(),
|
|
6171
|
+
error: z11.object({
|
|
6172
|
+
message: z11.string(),
|
|
6173
|
+
code: z11.string().optional(),
|
|
6174
|
+
stack: z11.string().optional()
|
|
6175
|
+
}).optional(),
|
|
6176
|
+
artifacts: z11.object({ dir: z11.string(), files: z11.array(z11.string()) }).optional(),
|
|
6177
|
+
bridge: z11.object({
|
|
6178
|
+
fallbacks: z11.number(),
|
|
6179
|
+
first: bridgeReadSchema,
|
|
6180
|
+
last: bridgeReadSchema
|
|
5857
6181
|
}).optional(),
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
name: z10.string().optional()
|
|
6182
|
+
device: z11.object({
|
|
6183
|
+
udid: z11.string(),
|
|
6184
|
+
platform: z11.enum(["ios", "android"]),
|
|
6185
|
+
name: z11.string().optional()
|
|
5863
6186
|
})
|
|
5864
6187
|
});
|
|
5865
6188
|
function openResults(path) {
|
|
@@ -9327,6 +9650,6 @@ function onlyWasSeen() {
|
|
|
9327
9650
|
|
|
9328
9651
|
// ../../packages/e2e/src/version.ts
|
|
9329
9652
|
var WORKSPACE_VERSION = "0.0.0-workspace";
|
|
9330
|
-
var WARDEN_E2E_VERSION2 = "0.
|
|
9653
|
+
var WARDEN_E2E_VERSION2 = "0.14.0";
|
|
9331
9654
|
|
|
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,
|
|
9655
|
+
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, 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, 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 };
|