stop background flash on tab switches, unblock Audit/Usage demos (#6562)

This commit is contained in:
Anthony Stirling
2026-06-09 17:59:53 +01:00
committed by GitHub
parent 1e739b6f6f
commit 1a0beaffc2
3 changed files with 141 additions and 53 deletions
@@ -121,6 +121,81 @@ test.describe("Settings dialog", () => {
await restored.click();
});
test("intra-modal tab switching updates URL via replaceState, never pushState", async ({
page,
}) => {
// Mechanism test for the "background flash" fix. Before the fix, every
// tab click called `navigate(...)` which fired React Router's location
// subscribers - HomePage, QuickAccessBar, FileManagerView, ... - and the
// layer behind the Mantine overlay repainted, causing backdrop-filter
// blur to recompute and visibly flash. After the fix, only the very
// first nav into /settings/* is allowed to go through React Router (so
// HomePage's location-watching effect opens the modal and the back
// button has a real history entry to pop). Every subsequent tab click
// updates the URL bar via raw `window.history.replaceState`, which
// React Router does NOT subscribe to. We assert this directly by
// counting calls.
await page.addInitScript(() => {
const w = window as unknown as {
__historyOps: { push: number; replace: number };
};
w.__historyOps = { push: 0, replace: 0 };
const origPush = window.history.pushState.bind(window.history);
const origReplace = window.history.replaceState.bind(window.history);
window.history.pushState = function (...args) {
w.__historyOps.push++;
return origPush(
...(args as Parameters<typeof window.history.pushState>),
);
};
window.history.replaceState = function (...args) {
w.__historyOps.replace++;
return origReplace(
...(args as Parameters<typeof window.history.replaceState>),
);
};
});
await page.goto("/", { waitUntil: "domcontentloaded" });
await openSettings(page);
const generalNav = page.locator('[data-tour="admin-general-nav"]').first();
const hotkeysNav = page.locator('[data-tour="admin-hotkeys-nav"]').first();
await expect(generalNav).toBeVisible({ timeout: 5_000 });
// First nav into /settings/* takes the React Router path (push). We
// snapshot both counters AFTER this to isolate the intra-modal delta.
await generalNav.click();
await page.waitForURL(/\/settings\/general/, { timeout: 5_000 });
const baseline = await page.evaluate(() => {
const w = window as unknown as {
__historyOps: { push: number; replace: number };
};
return { ...w.__historyOps };
});
// Now do 4 round-trips between two tabs - 8 intra-modal clicks total.
for (let i = 0; i < 4; i++) {
await hotkeysNav.click();
await page.waitForURL(/\/settings\/hotkeys/, { timeout: 5_000 });
await generalNav.click();
await page.waitForURL(/\/settings\/general/, { timeout: 5_000 });
}
const after = await page.evaluate(() => {
const w = window as unknown as {
__historyOps: { push: number; replace: number };
};
return { ...w.__historyOps };
});
// Zero pushes during 8 intra-modal clicks - the regression would show
// up here as `after.push - baseline.push >= 1`.
expect(after.push - baseline.push).toBe(0);
// Exactly 8 replaces - one per click.
expect(after.replace - baseline.replace).toBe(8);
});
test("close returns to origin URL even after switching tabs (no history pile-up)", async ({
page,
}) => {