89 lines
3.8 KiB
TypeScript
89 lines
3.8 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import { installMockApi } from "./mockApi";
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
await installMockApi(page);
|
|
});
|
|
|
|
test("object detail renders header metadata and parsed ROA projection", async ({ page }) => {
|
|
await page.goto("/objects/obj-roa-0001");
|
|
|
|
await expect(page.getByText("ROA object")).toBeVisible();
|
|
await expect(page.getByText("rsync://repo-a.example/ca1/alice.roa").first()).toBeVisible();
|
|
|
|
// Parsed tab is the default and renders structured ROA content
|
|
await expect(page.getByText("AS ID")).toBeVisible();
|
|
await expect(page.getByText("65001")).toBeVisible();
|
|
await expect(page.getByText("203.0.113.0/24")).toBeVisible();
|
|
await expect(page.getByText("2001:db8::/32")).toBeVisible();
|
|
});
|
|
|
|
test("tabs lazy-load: chain and validation requests fire only on activation", async ({ page }) => {
|
|
const requests: string[] = [];
|
|
page.on("request", (req) => requests.push(req.url()));
|
|
|
|
await page.goto("/objects/obj-roa-0001");
|
|
await expect(page.getByText("65001")).toBeVisible();
|
|
expect(requests.some((u) => u.includes("/chain"))).toBe(false);
|
|
expect(requests.some((u) => u.includes("/validation"))).toBe(false);
|
|
|
|
await page.getByRole("tab", { name: "Chain" }).click();
|
|
await expect.poll(() => requests.some((u) => u.includes("/chain"))).toBe(true);
|
|
await expect(page.getByText("issued_by")).toBeVisible();
|
|
|
|
await page.getByRole("tab", { name: "Validation" }).click();
|
|
await expect.poll(() => requests.some((u) => u.includes("/validation"))).toBe(true);
|
|
await expect(page.getByText("Final status")).toBeVisible();
|
|
});
|
|
|
|
test("validation explain POSTs and renders the audit-projection notice", async ({ page }) => {
|
|
await page.goto("/objects/obj-roa-0001?tab=validation");
|
|
const posts: string[] = [];
|
|
page.on("request", (req) => {
|
|
if (req.method() === "POST" && req.url().includes("/validation/explain")) posts.push(req.url());
|
|
});
|
|
|
|
await page.getByRole("button", { name: "Run explain" }).click();
|
|
await expect.poll(() => posts.length).toBe(1);
|
|
await expect(page.getByText("audit_projection").first()).toBeVisible();
|
|
await expect(page.getByText("not a full revalidation")).toBeVisible();
|
|
});
|
|
|
|
test("manifest object renders the file list", async ({ page }) => {
|
|
await page.goto("/objects/obj-mft-0001");
|
|
await expect(page.getByText("Manifest number")).toBeVisible();
|
|
await expect(page.getByText("0A2F")).toBeVisible();
|
|
await expect(page.getByRole("cell", { name: "alice.roa" })).toBeVisible();
|
|
});
|
|
|
|
test("object without projection shows the explicit unavailable state", async ({ page }) => {
|
|
await page.goto("/objects/obj-asa-0001");
|
|
await expect(page.getByText("Parsed projection unavailable")).toBeVisible();
|
|
});
|
|
|
|
test("download raw triggers a browser download", async ({ page }) => {
|
|
await page.goto("/objects/obj-roa-0001");
|
|
const downloadPromise = page.waitForEvent("download");
|
|
await page.getByRole("button", { name: "Download raw" }).click();
|
|
const download = await downloadPromise;
|
|
expect(download.suggestedFilename()).toBe("alice.roa");
|
|
});
|
|
|
|
test("export object set starts a job and offers the tarball when complete", async ({ page }) => {
|
|
await page.goto("/objects/obj-roa-0001");
|
|
const posts: string[] = [];
|
|
page.on("request", (req) => {
|
|
if (req.method() === "POST" && req.url().includes("/exports")) posts.push(req.url());
|
|
});
|
|
|
|
await page.getByRole("button", { name: "Export object set" }).click();
|
|
await expect.poll(() => posts.length).toBe(1);
|
|
// Mock completes the job after the first poll.
|
|
await expect(page.getByRole("link", { name: "Download tar" })).toBeVisible({ timeout: 10_000 });
|
|
});
|
|
|
|
test("missing object shows an error state", async ({ page }) => {
|
|
await page.goto("/objects/obj-does-not-exist");
|
|
await expect(page.getByRole("alert")).toContainText("Failed to load object");
|
|
});
|