Files
govoplan-core/webui/conformance/tests/campaign-workspace.spec.ts
T

128 lines
6.6 KiB
TypeScript

import { expect, test, type Page, type Route } from "@playwright/test";
function deferred() {
let resolve!: () => void;
const promise = new Promise<void>((done) => { resolve = done; });
return { promise, resolve };
}
function response(campaignId = "campaign-a", revision = 1, versionId = `${campaignId}-version`, hasMore = false) {
const version = { id: versionId, campaign_id: campaignId, version_number: 1, edit_revision: revision, raw_json: {} };
return {
campaign: { id: campaignId, current_version_id: versionId },
versions: [version], current_version: version, summary: null,
deleted: [], watermark: `watermark-${campaignId}-${revision}`, has_more: hasMore, full: true
};
}
async function fixture(page: Page) {
const requests: URL[] = [];
const state = {
handler: async (route: Route) => {
const url = new URL(route.request().url());
const campaignId = url.pathname.split("/")[4];
await route.fulfill({ json: response(campaignId, 1, url.searchParams.get("version_id") ?? undefined) });
}
};
await page.route((url) => url.pathname.startsWith("/api/"), async (route) => {
const url = new URL(route.request().url());
if (url.pathname.endsWith("/workspace/delta")) {
requests.push(url);
await state.handler(route);
} else await route.fulfill({ json: {} });
});
await page.goto("/?campaign-workspace");
await expect(page.getByTestId("workspace-version")).toHaveText("campaign-a-version");
await expect(page.getByTestId("workspace-loading")).toHaveText("false");
requests.length = 0;
return { state, requests };
}
test("failed refresh retains saved workspace and retries without a stale watermark", async ({ page }) => {
const { state, requests } = await fixture(page);
state.handler = async (route) => { await route.fulfill({ status: 503, json: { detail: "Refresh unavailable" } }); };
await page.getByRole("button", { name: "Force reload workspace", exact: true }).click();
await expect(page.getByTestId("workspace-error")).toContainText("Refresh unavailable");
await expect(page.getByTestId("workspace-loading")).toHaveText("false");
await expect(page.getByTestId("workspace-version")).toHaveText("campaign-a-version");
state.handler = async (route) => { await route.fulfill({ json: response("campaign-a", 2) }); };
await page.getByRole("button", { name: "Reload workspace", exact: true }).click();
await expect(page.getByTestId("workspace-revision")).toHaveText("2");
expect(requests[requests.length - 1].searchParams.has("since")).toBe(false);
await expect(page.getByTestId("workspace-error")).toBeEmpty();
});
for (const staleFails of [false, true]) {
test(`newer reload wins over an older ${staleFails ? "failed" : "successful"} response`, async ({ page }) => {
const { state } = await fixture(page);
const pending = deferred(); const finished = deferred();
let requestCount = 0;
state.handler = async (route) => {
requestCount += 1;
if (requestCount === 1) {
await pending.promise;
await route.fulfill(staleFails ? { status: 503, json: { detail: "Obsolete error" } } : { json: response("campaign-a", 2) });
finished.resolve();
} else await route.fulfill({ json: response("campaign-a", 3) });
};
await page.getByRole("button", { name: "Reload workspace", exact: true }).click();
await expect.poll(() => requestCount).toBe(1);
await page.getByRole("button", { name: "Reload workspace", exact: true }).click();
await expect(page.getByTestId("workspace-revision")).toHaveText("3");
pending.resolve(); await finished.promise;
await page.evaluate(() => new Promise((done) => requestAnimationFrame(() => requestAnimationFrame(done))));
await expect(page.getByTestId("workspace-revision")).toHaveText("3");
await expect(page.getByTestId("workspace-loading")).toHaveText("false");
await expect(page.getByTestId("workspace-error")).toBeEmpty();
});
}
for (const change of ["campaign", "identity", "version"] as const) {
test(`changing ${change} discards old responses and cancels obsolete pagination`, async ({ page }) => {
const { state, requests } = await fixture(page);
const pending = deferred(); const finished = deferred();
let requestCount = 0;
state.handler = async (route) => {
requestCount += 1;
if (requestCount === 1) {
await pending.promise;
await route.fulfill({ json: response("campaign-a", 99, "obsolete-version", true) });
finished.resolve();
} else await route.fulfill({ json: response(change === "campaign" ? "campaign-b" : "campaign-a", 2, "fresh-version") });
};
await page.getByRole("button", { name: "Reload workspace", exact: true }).click();
await expect.poll(() => requestCount).toBe(1);
await page.getByRole("button", { name: { campaign: "Switch campaign", identity: "Switch identity", version: "Select version" }[change] }).click();
await expect(page.getByTestId("workspace-version")).toHaveText("fresh-version");
pending.resolve(); await finished.promise;
await page.evaluate(() => new Promise((done) => requestAnimationFrame(() => requestAnimationFrame(done))));
await expect(page.getByTestId("workspace-version")).toHaveText("fresh-version");
expect(requests).toHaveLength(2);
expect(requests[1].searchParams.has("since")).toBe(false);
});
}
test("failed initial load for a different campaign never reveals the old campaign", async ({ page }) => {
const { state } = await fixture(page);
state.handler = async (route) => { await route.fulfill({ status: 403, json: { detail: "Campaign unavailable" } }); };
await page.getByRole("button", { name: "Switch campaign" }).click();
await expect(page.getByTestId("workspace-error")).toContainText("Campaign unavailable");
await expect(page.getByTestId("workspace-campaign")).toHaveText("none");
await expect(page.getByTestId("workspace-version")).toHaveText("none");
});
test("a failed later page never publishes a partially refreshed workspace", async ({ page }) => {
const { state } = await fixture(page);
let requestCount = 0;
state.handler = async (route) => {
requestCount += 1;
await route.fulfill(requestCount === 1
? { json: response("campaign-a", 4, "partial-version", true) }
: { status: 503, json: { detail: "Second page unavailable" } });
};
await page.getByRole("button", { name: "Reload workspace", exact: true }).click();
await expect(page.getByTestId("workspace-error")).toContainText("Second page unavailable");
await expect(page.getByTestId("workspace-version")).toHaveText("campaign-a-version");
await expect(page.getByTestId("workspace-revision")).toHaveText("1");
});