test(e2e): pass an unswitched auth payload through the corrupting route

The malformed-payload journey installs its /api/auth/me route before it
clicks the switch. When the owner session read its own payload again in
that window, the helper threw inside the route handler: the throw came
before fulfill, so its catch never saw it, the test failed, and the
teardown's unroute then hit a closed page. It showed up on the Playwright
1.63 branch, whose timing opens that window more often. An unswitched
payload now passes through unchanged, and the test asserts that at least
one switched response was actually corrupted before trusting the refusal.
This commit is contained in:
Marc-André Bombeck committed 2026-09-13 22:20:15 +02:00
1 parent 66b0dbb67b
commit 76d80fbed4
1 file changed
+24 -8
+24 -8
View File
@@ -171,7 +171,15 @@ async function leaveRecord(page: Page) {
);
}
function withDivergentActiveAccountAccess(body: unknown): unknown {
/**
* The switched `/api/auth/me` payload with a write level the grant never had,
* or `undefined` when the payload is not a switched one yet. The route is
* installed before the switch is clicked, and the owner session can read its
* own `/api/auth/me` again in that window; that response must pass through
* untouched instead of throwing inside the route handler, where the error
* fails the test and leaves `page.unroute` running against a closed page.
*/
function withDivergentActiveAccountAccess(body: unknown): unknown | undefined {
if (body === null || typeof body !== "object") {
throw new Error("Expected an object from /api/auth/me");
}
@@ -192,7 +200,7 @@ function withDivergentActiveAccountAccess(body: unknown): unknown {
};
};
if (!auth.accountAccess?.active) {
throw new Error("Expected a switched account-access payload");
return undefined;
}
const corrupted = {
@@ -303,6 +311,7 @@ test.describe.serial("scoped sharing browser journeys", () => {
});
let corruptAuthPayload = true;
let corruptedResponses = 0;
await page.route("**/api/auth/me", async (route) => {
// The switch this test drives ends in a full reload, and the reload
// cancels whatever `/api/auth/me` call is in flight. Playwright then
@@ -324,12 +333,13 @@ test.describe.serial("scoped sharing browser journeys", () => {
await route.fulfill({ response }).catch(() => {});
return;
}
await route
.fulfill({
response,
json: withDivergentActiveAccountAccess(await response.json()),
})
.catch(() => {});
const corrupted = withDivergentActiveAccountAccess(await response.json());
if (corrupted === undefined) {
await route.fulfill({ response }).catch(() => {});
return;
}
corruptedResponses += 1;
await route.fulfill({ response, json: corrupted }).catch(() => {});
});
const ownerOnlyReads: string[] = [];
@@ -376,6 +386,12 @@ test.describe.serial("scoped sharing browser journeys", () => {
await expect(
page.locator('[data-slot="invalid-record-access-refusal"]'),
).toBeVisible();
// The refusal has to come from the corrupted payload, not from a read
// that happened to pass through before the switch landed.
expect(
corruptedResponses,
"the switched /api/auth/me was never corrupted",
).toBeGreaterThan(0);
await expect(
page.locator('[data-slot="shared-record-unavailable-leave"]'),
).toBeVisible();