import { test, expect } from "@playwright/test"; import { WARM_TIMEOUT, warm } from "./warm"; // --------------------------------------------------------------------------- // /sites: every site's articles, a site's page, its media and workspace files. // // priv/polemic-alpha published, a video + poster, linked to the project // sitews/polemic-alpha (slug in the draft's workspace) // priv/polemic-beta a draft // pub/gamma published on the public site // (e2e/fixtures/sites-fixture.mjs) // --------------------------------------------------------------------------- test.beforeAll(async ({ playwright }) => { test.setTimeout(WARM_TIMEOUT); await warm(playwright, ["/sites", "/sites/priv", "/sites/priv/polemic-alpha", "/api/sites/media?site=priv&report=polemic-alpha&file=poster.jpg", "/api/sites/workspace?ws=sitews&rel=NOTES.md"]); }); test("/sites lists every site, private first, with published and draft articles", async ({ page }) => { const res = await page.goto("/sites"); expect(res?.status()).toBe(200); // The nav calls it "articles" (the editor's /sites is the sites themselves). await expect(page.getByRole("link", { name: "articles", exact: true }).first()).toHaveAttribute("aria-current", "page"); await expect(page.getByRole("link", { name: "sites", exact: true })).toHaveCount(0); const sites = page.locator("[data-site]"); await expect(sites).toHaveCount(2); await expect(sites.nth(0)).toHaveAttribute("data-site", "priv"); await expect(sites.nth(1)).toHaveAttribute("data-site", "pub"); await expect(page.locator("[data-site='priv'] [data-audience]")).toHaveAttribute("data-audience", "private"); await expect(page.locator("[data-site='priv'] [data-counts]")).toHaveAttribute("data-counts", "1/1"); const alpha = page.locator("[data-article='priv/polemic-alpha']"); await expect(alpha).toHaveAttribute("data-status", "published"); await expect(alpha).toContainText("Alpha: the rigged vote"); await expect(alpha.locator("[data-project-link='sitews/polemic-alpha']")).toBeVisible(); await expect(alpha).toContainText("alpha.json"); await expect(alpha.locator("img")).toHaveCount(1); await expect(page.locator("[data-article='priv/polemic-beta']")).toHaveAttribute("data-status", "draft"); }); test("the filters are links, and compose", async ({ page }) => { await page.goto("/sites"); await page.getByRole("link", { name: /^draft \d+$/ }).click(); await expect(page).toHaveURL(/status=draft/); await expect(page.locator("[data-article]")).toHaveCount(1); await expect(page.locator("[data-article='priv/polemic-beta']")).toBeVisible(); await page.goto("/sites?site=pub"); await expect(page.locator("[data-site]")).toHaveCount(1); await expect(page.locator("[data-article='pub/gamma']")).toBeVisible(); await page.goto("/sites?notes=open"); await expect(page.locator("[data-article]")).toHaveCount(0); }); test("a site's page plays its report videos, lists its project's takes and its workspace", async ({ page, request }) => { await page.goto("/sites/priv"); await expect(page.locator("[data-report-video='polemic-alpha'] video")).toHaveAttribute("src", /file=video\.mp4/); const project = page.locator("[data-video-project='sitews/polemic-alpha']"); await expect(project.locator("[data-takes]")).toHaveAttribute("data-takes", "2"); await expect(project).toContainText("like 1"); // media: ranged, read-only, and nothing outside the report dir const v = await request.get("/api/sites/media?site=priv&report=polemic-alpha&file=video.mp4", { headers: { range: "bytes=0-99" } }); expect(v.status()).toBe(206); expect(v.headers()["content-type"]).toBe("video/mp4"); expect((await request.get("/api/sites/media?site=priv&report=polemic-alpha&file=../polemic-beta/report.json")).status()).toBe(404); expect((await request.get("/api/sites/media?site=priv&report=polemic-alpha&file=report.json")).status()).toBe(400); expect((await request.get("/api/sites/media?corpus=/etc/passwd")).status()).toBe(400); // workspace files: markdown renders, a draft folds, HTML is sandboxed const files = page.locator("[data-section='files']"); await files.locator("[data-file='NOTES.md']").click(); await expect(page.locator("[data-opened='md']")).toContainText("Workspace notes"); await page.locator("[data-file='polemics/drafts/alpha.json']").click(); await expect(page.locator("[data-opened='json']")).toContainText("polemic-alpha"); await page.locator("[data-file='polemics/out/alpha.html']").click(); await expect(page.locator("iframe[sandbox='']")).toHaveCount(1); const html = await request.get("/api/sites/workspace?ws=sitews&rel=polemics/out/alpha.html"); expect(html.headers()["content-security-policy"]).toContain("sandbox"); expect((await request.get("/api/sites/workspace?ws=sitews&rel=../sites/priv/site.json")).status()).toBe(404); expect((await request.get("/api/sites/workspace?ws=..&rel=NOTES.md")).status()).toBe(404); }); test("an unknown site or article is a 404", async ({ page }) => { expect((await page.goto("/sites/nope"))?.status()).toBe(404); expect((await page.goto("/sites/priv/nope"))?.status()).toBe(404); });