test: wait until the page shows a screen, not only until it lays out (closes #502)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run

The browser suites' wait for a screen passed as soon as the element laid
out. Until the page's stylesheet has applied, every view lays out, so an
approval test could read the prompt before the page's script had filled
it. visible() in the Chrome harness and waitVisible() in the Firefox
driver now also wait for the page to finish loading and for neither the
element nor anything around it to carry the hidden class that showView()
keeps on every view but the current one. No caller changed.

Model: opus-5-5
This commit is contained in:
2026-10-08 06:04:12 +00:00
parent ff05bd50f7
commit 08270441e0
3 changed files with 42 additions and 3 deletions
+10
View File
@@ -44,6 +44,16 @@ then continue tagging as milestones land.
# Completed Steps # Completed Steps
- 2026-10-08: The browser suites no longer read a screen before the page has
shown it ([#502](https://git.eeqj.de/sneak/AutistMask/issues/502)). Their wait
for a screen used to pass as soon as the element laid out, which every view
does until the page's stylesheet has applied, so an approval test could read
the prompt's fields before the page's script had filled them. `visible()` in
`tests/e2e/harness.js` and `waitVisible()` in `tests/e2e/firefox/driver.js`
now also wait for the page to finish loading and for neither the element nor
anything around it to carry the `hidden` class that `showView()` puts on every
view but the current one. No caller changed.
- 2026-10-07: A site can no longer switch the wallet's network by itself - 2026-10-07: A site can no longer switch the wallet's network by itself
([#408](https://git.eeqj.de/sneak/AutistMask/issues/408)). A connected site's ([#408](https://git.eeqj.de/sneak/AutistMask/issues/408)). A connected site's
`wallet_switchEthereumChain` request for the other supported network opens a `wallet_switchEthereumChain` request for the other supported network opens a
+7 -2
View File
@@ -279,12 +279,17 @@ class Driver {
// Shown means shown: in the popup a view is switched by toggling a // Shown means shown: in the popup a view is switched by toggling a
// "hidden" class, and an element that is present but collapsed is not // "hidden" class, and an element that is present but collapsed is not
// the thing a test means by visible. // the thing a test means by visible. Until the page's stylesheet has
// applied that class hides nothing and every view lays out, so the page
// must also have finished loading, which it does only after its
// stylesheet, and neither the element nor anything enclosing it may
// carry the class (https://git.eeqj.de/sneak/AutistMask/issues/502).
async waitVisible(selector, timeout = DEFAULT_WAIT_MS) { async waitVisible(selector, timeout = DEFAULT_WAIT_MS) {
return this.waitFor( return this.waitFor(
"selector " + selector + " to be visible", "selector " + selector + " to be visible",
`const el = document.querySelector(arguments[0]); `const el = document.querySelector(arguments[0]);
if (!el) return false; if (document.readyState !== "complete" || !el) return false;
if (el.closest(".hidden")) return false;
const r = el.getBoundingClientRect(); const r = el.getBoundingClientRect();
return r.width > 0 && r.height > 0;`, return r.width > 0 && r.height > 0;`,
[selector], [selector],
+25 -1
View File
@@ -333,8 +333,32 @@ async function launch(routeOpts) {
const PASSWORD = "e2e-harness-password"; const PASSWORD = "e2e-harness-password";
// Waits until the page shows `selector`, not only until it lays out. Until the
// page's stylesheet has applied, the `hidden` class that showView() keeps on
// every view but the current one hides nothing and every view lays out, so a
// test could read a screen before the page's script had filled it
// (https://git.eeqj.de/sneak/AutistMask/issues/502). So the page must also
// have finished loading, which it does only after its stylesheet, and neither
// the element nor anything enclosing it may carry `hidden`. Polled on a timer:
// animation frames are not guaranteed to a window that is not in front.
async function visible(page, selector, timeout = 15000) { async function visible(page, selector, timeout = 15000) {
await page.waitForSelector(selector, { state: "visible", timeout }); await page
.waitForFunction(
(sel) => {
const el = document.querySelector(sel);
if (document.readyState !== "complete" || !el) return false;
if (el.closest(".hidden")) return false;
const r = el.getBoundingClientRect();
return r.width > 0 && r.height > 0;
},
selector,
{ polling: 50, timeout },
)
.catch((e) => {
throw new Error(
"the page did not show " + selector + ": " + e.message,
);
});
} }
// An empty WebAssembly module: magic number and version header, no // An empty WebAssembly module: magic number and version header, no