test: wait until the page shows a screen, not only until it lays out #504

Merged
clawbot merged 1 commits from issue-502-harness-screen-wait into next 2026-10-08 12:49:44 +02:00
3 changed files with 44 additions and 3 deletions
Showing only changes of commit fbfff359b1 - Show all commits
+10
View File
@@ -44,6 +44,16 @@ then continue tagging as milestones land.
# 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-08: Switching the network in Settings now tells open pages
([#500](https://git.eeqj.de/sneak/AutistMask/issues/500)). Once the switch is
saved, Settings asks the background to send `chainChanged` with the new chain
+8 -2
View File
@@ -279,12 +279,18 @@ class Driver {
// 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
// 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) {
return this.waitFor(
"selector " + selector + " to be visible",
`const el = document.querySelector(arguments[0]);
if (!el) return false;
if (document.readyState !== "complete" || !el) return false;
if (el.closest(".hidden")) return false;
if (getComputedStyle(el).visibility !== "visible") return false;
const r = el.getBoundingClientRect();
return r.width > 0 && r.height > 0;`,
[selector],
+26 -1
View File
@@ -333,8 +333,33 @@ async function launch(routeOpts) {
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) {
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;
if (getComputedStyle(el).visibility !== "visible") 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