fix(boot): a stylesheet lost on the way is asked for again
A lost stylesheet left the page unstyled until a reload, and every e2e step that finds elements by testid still passed on it. Only axe noticed: the one-off target-size failure on eight scattered controls. Losing the main stylesheet on purpose gives those same eight.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import { test, expect, type Page } from "@playwright/test";
|
||||
import { openApp } from "./helpers";
|
||||
|
||||
// A request can be lost on the way on a loaded machine or a poor line. A lost stylesheet leaves the
|
||||
// whole page unstyled, and every test that finds its elements by testid still passes on it: only an
|
||||
// axe run ever noticed (8 controls under the target size). So this looks at the styles themselves.
|
||||
|
||||
/** Lose the first request for every stylesheet of the page; the ones after it go through. */
|
||||
async function loseEachStylesheetOnce(page: Page): Promise<string[]> {
|
||||
const lost: string[] = [];
|
||||
await page.route(/\/assets\/[^/]+\.css/, async (route) => {
|
||||
const url = route.request().url();
|
||||
if (lost.includes(url)) return route.continue();
|
||||
lost.push(url);
|
||||
return route.abort("failed");
|
||||
});
|
||||
return lost;
|
||||
}
|
||||
|
||||
/** Every stylesheet link of the page holds rules (a lost one still has a `sheet`, whose rules throw
|
||||
* on reading), and the page's own tokens are in force: `--bg` comes from the stylesheet alone, while
|
||||
* `--font-scale` would prove nothing, the app also sets it from script. */
|
||||
async function expectStyled(page: Page): Promise<void> {
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate(() => {
|
||||
const hasRules = (l: HTMLLinkElement) => {
|
||||
try {
|
||||
return (l.sheet?.cssRules.length ?? 0) > 0;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const links = [...document.querySelectorAll<HTMLLinkElement>('link[rel="stylesheet"]')];
|
||||
const root = getComputedStyle(document.documentElement);
|
||||
return {
|
||||
links: links.length > 0,
|
||||
rules: links.every(hasRules),
|
||||
tokens: root.getPropertyValue("--bg").trim() !== "",
|
||||
};
|
||||
}),
|
||||
)
|
||||
.toEqual({ links: true, rules: true, tokens: true });
|
||||
}
|
||||
|
||||
test("the app gets back a stylesheet lost on the way", async ({ page }) => {
|
||||
const lost = await loseEachStylesheetOnce(page);
|
||||
await openApp(page);
|
||||
expect(lost.length).toBeGreaterThan(0);
|
||||
await expectStyled(page);
|
||||
});
|
||||
|
||||
test("a public /watch link gets back a stylesheet lost on the way", async ({ page }) => {
|
||||
const lost = await loseEachStylesheetOnce(page);
|
||||
// No such link: the page says so, and it is the same entry with the same stylesheet.
|
||||
await page.goto("/watch/no-such-token");
|
||||
await expect(page.locator("#root")).not.toBeEmpty();
|
||||
expect(lost.length).toBeGreaterThan(0);
|
||||
await expectStyled(page);
|
||||
});
|
||||
Reference in New Issue
Block a user