diff --git a/CLAUDE.md b/CLAUDE.md index ca7463347..db38d1a1b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -57,8 +57,9 @@ need an ssh-agent use the `sshAuthSock` fixture and create a peer with a `passphrase`. When a fixture depends on one peer seeing another's changes, wait for the node event with `waitForEvent` instead of sleeping. Reload pages with `reload(page)` from `@tests/support/fixtures.js`, not -`page.reload()`: the app polls the backend, and the harness would otherwise -fail the test on the request the reload cancels. +`page.reload()`, and navigate a page that already shows the app with +`goto(page, url)`: the app polls the backend, and the harness would otherwise +fail the test on the request the navigation cancels. Tests run against a production build in `tests/tmp/build`, served by `vite preview`; the build takes a few seconds at startup. Set diff --git a/tests/e2e/repo/permissions.spec.ts b/tests/e2e/repo/permissions.spec.ts index f34e09e84..f75e55e15 100644 --- a/tests/e2e/repo/permissions.spec.ts +++ b/tests/e2e/repo/permissions.spec.ts @@ -8,6 +8,7 @@ import { } from "@tests/support/collaboration.js"; import { expect, + goto, test, useBackend, waitForCommand, @@ -124,7 +125,7 @@ test("a contributor can't resolve someone else's review comment", async ({ // Now as eve. await eve.startHttpd(); await useBackend(page, eve); - await page.goto(`/repos/${rid}/patches/${patchId}?view=changes`); + await goto(page, `/repos/${rid}/patches/${patchId}?view=changes`); const thread = page.getByRole("group").filter({ hasText: "Keep it loud" }); await thread.hover(); await expect(thread.getByTitle("Reply")).toBeVisible(); diff --git a/tests/support/fixtures.ts b/tests/support/fixtures.ts index 455699913..4bbcd978e 100644 --- a/tests/support/fixtures.ts +++ b/tests/support/fixtures.ts @@ -62,7 +62,7 @@ export const test = base.extend<{ if (tearingDown.has(page)) { return; } - if (reloading.has(page) && isCancelledFetch(msg)) { + if (navigating.has(page) && isCancelledFetch(msg)) { return; } // Only says some resize notifications waited for the next frame. @@ -173,7 +173,7 @@ export const test = base.extend<{ }, }); -const reloading = new WeakSet(); +const navigating = new WeakSet(); const tearingDown = new WeakSet(); // WebKit reports a fetch that was cancelled because the page went away as an @@ -184,18 +184,27 @@ function isCancelledFetch(error: Error) { ); } -export async function reload(page: Page) { - reloading.add(page); +async function navigate(page: Page, action: () => Promise) { + navigating.add(page); try { - await page.reload(); + await action(); // WebKit reports fetches the old page had in flight after the new one // has loaded, so keep ignoring them until the network settles. await page.waitForLoadState("networkidle"); } finally { - reloading.delete(page); + navigating.delete(page); } } +export async function reload(page: Page) { + await navigate(page, () => page.reload()); +} + +// Use instead of `page.goto` when the page already shows the app. +export async function goto(page: Page, url: string) { + await navigate(page, () => page.goto(url)); +} + // Runs `action` and waits for the backend command it sends to finish. The UI // often updates before the write lands, and a reload would cancel it. export async function waitForCommand(