who_need_help/e2e/tests/zz-resilience.spec.ts

94 lines
3.0 KiB
TypeScript

import { expect, test } from "@playwright/test";
import {
gotoLiveView,
projectEmail,
projectText,
registerAndConfirm,
selectOptionContaining,
setRequestLocation,
waitForLiveViewConnected,
} from "./helpers";
test("a disconnected LiveView recovers without leaving a stale error", async ({
browser,
request,
}, testInfo) => {
const user = await registerAndConfirm(
browser,
request,
projectEmail("resilience", testInfo.project.name),
"E2E Resilience",
);
const title = projectText("Connection recovery request", testInfo.project.name);
await gotoLiveView(user.page, "/requests/new");
await selectOptionContaining(user.page, "Category", "Medicine pickup");
await user.page.getByLabel("Medicine pickup status").selectOption("reserved");
await user.page.getByLabel("Short title").fill(title);
await user.page
.getByLabel("What help do you need?")
.fill("A reserved medicine pickup used to verify visible connection recovery.");
await user.page.getByLabel("Urgency").selectOption("now");
await user.page.getByRole("button", { name: "In 3 hours" }).click();
await setRequestLocation(user.page, {
label: "Connection recovery area",
mode: "hidden",
});
await user.page.locator("#request-form input[type=checkbox]").last().check();
await user.page.getByRole("button", { name: "Publish request" }).click();
await expect(user.page.getByRole("heading", { name: title })).toBeVisible();
await waitForLiveViewConnected(user.page);
const runtimeNode = await user.page
.locator("#e2e-runtime-node")
.getAttribute("data-node");
expect(runtimeNode).toBeTruthy();
const serverError = user.page.locator("#server-error");
await expect(serverError).toHaveAttribute("role", "alert");
await expect(serverError).toContainText("Attempting to reconnect");
await user.page.evaluate(() => {
const state = { sawDisconnected: false };
(
window as typeof window & {
__wnhRecoveryState?: { sawDisconnected: boolean };
}
).__wnhRecoveryState = state;
window.addEventListener("phx:page-loading-start", (event) => {
const detail = (event as CustomEvent<{ kind?: string }>).detail;
if (detail?.kind === "error") state.sawDisconnected = true;
});
});
const crash = await request.post("/__e2e__/crash-node", {
data: {
confirmation: "crash-exact-e2e-node",
node: runtimeNode,
},
});
expect(crash.status()).toBe(202);
await expect
.poll(
() =>
user.page.evaluate(
() =>
(
window as typeof window & {
__wnhRecoveryState?: { sawDisconnected: boolean };
}
).__wnhRecoveryState?.sawDisconnected ?? false,
),
{ timeout: 30_000 },
)
.toBe(true);
await waitForLiveViewConnected(user.page);
await expect(serverError).toBeHidden();
await expect(user.page.locator("#client-error")).toBeHidden();
await expect(user.page.getByRole("heading", { name: title })).toBeVisible();
await user.context.close();
});