94 lines
3.0 KiB
TypeScript
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();
|
|
});
|