Repository Public
1import { expect, test } from "@playwright/test";23/** The studio is closed to anonymous visitors: pages redirect, APIs refuse, cross-origin writes are rejected. */45test("studio pages redirect anonymous visitors to the sign-in page", async ({ page }) => {6 for (const path of ["/studio", "/studio/projects", "/studio/projects/new", "/studio/costs", "/studio/settings", "/studio/audit", "/studio/jobs", "/studio/films"]) {7 await page.goto(path);8 await expect(page, path).toHaveURL(/\/studio\/login/);9 }10 await expect(page.getByRole("heading", { name: "Studio sign-in" })).toBeVisible();11 await expect(page.locator('meta[name="robots"]')).toHaveAttribute("content", /noindex/);12});1314test("studio APIs refuse anonymous callers", async ({ request, baseURL }) => {15 const origin = new URL(baseURL!).origin;16 const post = (path: string, data: unknown) => request.post(path, { data, headers: { Origin: origin } });17 expect((await request.get("/api/studio/costs")).status()).toBe(401);18 expect((await request.get("/api/studio/projects")).status()).toBe(401);19 expect((await request.get("/api/studio/jobs/00000000-0000-4000-8000-000000000000")).status()).toBe(401);20 expect((await post("/api/studio/concepts", { theme: "anonymous attempt" })).status()).toBe(401);21 expect((await post("/api/studio/kill-switch", { on: false })).status()).toBe(401);22 expect((await post("/api/studio/projects/00000000-0000-4000-8000-000000000000/generate", {})).status()).toBe(401);23 expect((await post("/api/studio/films/00000000-0000-4000-8000-000000000000/publish", {})).status()).toBe(401);24 expect((await post("/api/studio/shots/00000000-0000-4000-8000-000000000000/regenerate", { what: "video" })).status()).toBe(401);25});2627test("cross-origin writes are rejected before authentication is even considered", async ({ request }) => {28 const r = await request.post("/api/studio/kill-switch", { data: { on: true }, headers: { Origin: "https://evil.example" } });29 expect(r.status()).toBe(403);30 const like = await request.post("/api/films/anything/react", { data: { like: true }, headers: { Origin: "https://evil.example" } });31 expect(like.status()).toBe(403);32});3334test("a wrong password is refused with a generic message", async ({ page }) => {35 await page.goto("/studio/login");36 await page.fill("#email", "nobody@example.com");37 await page.fill("#password", "definitely-not-the-password");38 await page.getByRole("button", { name: "Sign in" }).click();39 await expect(page.locator("main [role=alert]")).toContainText(/Wrong email or password|Too many attempts/);40 await expect(page).toHaveURL(/\/studio\/login/);41});4243test("public write endpoints validate their input", async ({ request, baseURL }) => {44 const origin = new URL(baseURL!).origin;45 expect((await request.post("/api/events", { data: { filmId: "x", kind: "view" }, headers: { Origin: origin } })).status()).toBe(400);46 expect((await request.post("/api/reports", { data: { detail: "short" }, headers: { Origin: origin } })).status()).toBe(400);47});48