e2e/server-data.spec.ts
Linked repository file from this build.
import { expect, test } from "@playwright/test";
test("initial page data arrives with the route without a second API GET", async ({ page }) => {
await page.setViewportSize({ width: 1440, height: 900 });
await page.context().addCookies([
{ name: "qc-test-staff", value: "501", url: "http://localhost:3001" },
{ name: "qc-inbox-page-size", value: "7", url: "http://localhost:3001" },
]);
const reads: string[] = [];
const prefetches: string[] = [];
page.on("request", (request) => {
const path = new URL(request.url()).pathname;
if (
request.headers()["next-router-prefetch"] ||
request.headers()["next-router-segment-prefetch"]
)
prefetches.push(path);
if (
request.method() === "GET" &&
[
"/api/inbox",
"/api/catalog",
"/api/reports",
"/api/exports",
"/api/search",
"/api/reviews/aa1635c0-c99d-5f12-8f26-54d3f23bf13d",
].includes(path)
)
reads.push(path);
});
await page.goto("/dashboard");
await expect(page.locator('main section[aria-busy="false"] h2')).toHaveCount(4);
await expect(page.locator(".elapsed-time")).toBeVisible();
for (const [path, selector] of [
["/reviews", 'table[aria-label="Reviews in branch"] tbody tr'],
["/reports", '.report-view[aria-busy="false"]'],
["/exports", 'table[aria-label="Export eligibility by sample month"] tbody tr'],
]) {
await page.locator(`a[href="${path}"]:visible`).first().click();
await expect(page.locator(selector).first()).toBeVisible();
}
await page.goto("/search?q=60001");
await expect(
page.locator('main a[href="/reviews/aa1635c0-c99d-5f12-8f26-54d3f23bf13d"]').first(),
).toBeVisible();
await page.goto("/reviews/aa1635c0-c99d-5f12-8f26-54d3f23bf13d");
await expect(page.locator(".review-workspace #client-name")).toBeVisible();
await page.waitForTimeout(1_000);
expect(reads).toEqual([]);
expect(prefetches).toEqual([]);
});
test("fresh dashboard renders server data before responsive page-size refresh", async ({
page,
}) => {
await page
.context()
.addCookies([{ name: "qc-test-staff", value: "501", url: "http://localhost:3001" }]);
const inboxReads: string[] = [];
let release: () => void = () => {};
const gate = new Promise<void>((resolve) => {
release = resolve;
});
await page.route("**/api/inbox?**", async (route) => {
inboxReads.push(route.request().url());
await gate;
await route.continue();
});
try {
await page.goto("/dashboard");
await expect(page.locator("main section[aria-busy] h2")).toHaveCount(4);
expect(inboxReads).toHaveLength(1);
} finally {
release();
}
});
test("API server timing separates auth, data and serialization", async ({ request }) => {
for (const path of ["/api/catalog", "/api/inbox", "/api/reports", "/api/exports"]) {
const response = await request.get(path, { headers: { "x-qc-test-staff": "501" } });
expect(response.ok()).toBe(true);
expect(response.headers()["server-timing"]).toMatch(
/auth;dur=[\d.]+, data;dur=[\d.]+, serialize;dur=[\d.]+/,
);
expect(response.headers()["cache-control"]).toBe("private, no-store");
}
});
test("workspace fields render from server data with JavaScript disabled", async ({
browser,
page,
baseURL,
}) => {
const context = await browser.newContext({
baseURL,
javaScriptEnabled: false,
storageState: await page.context().storageState(),
});
try {
const workspace = await context.newPage();
await workspace.goto("/reviews/aa1635c0-c99d-5f12-8f26-54d3f23bf13d");
await expect(workspace.locator("#client-name")).toBeVisible();
await expect(workspace.locator("#client-name")).not.toHaveValue("");
} finally {
await context.close();
}
});