SPB Git

spb/akos

Public
3.7 KB · 80 lines typescript
1/** Mobile (iPhone 14, 390×844) end-to-end walk of the AKOS dashboard against a live deployment.2 *  Env: AKOS_BASE_URL, AKOS_E2E_EMAIL, AKOS_E2E_PASSWORD. Asserts real data renders (no "undefined"/"NaN"), no console errors, drawer works. */3import { test, expect, type Page } from "@playwright/test";45const EMAIL = process.env.AKOS_E2E_EMAIL ?? "";6const PASSWORD = process.env.AKOS_E2E_PASSWORD ?? "";78async function noJunk(page: Page) {9  await page.waitForLoadState("networkidle");10  await expect(page.locator(".loading")).toHaveCount(0, { timeout: 20_000 });11  const text = await page.locator("main").innerText();12  expect(text).not.toMatch(/\bundefined\b/);13  expect(text).not.toMatch(/\bNaN\b/);14  expect(text).not.toMatch(/\[object Object\]/);15}1617test.describe("AKOS mobile dashboard", () => {18  const errors: string[] = [];19  test.beforeEach(async ({ page }) => {20    page.on("console", (m) => { if (m.type() === "error") errors.push(m.text()); });21    page.on("pageerror", (e) => errors.push(String(e)));22    await page.goto("/login");23    await page.getByLabel("Email").fill(EMAIL);24    await page.getByLabel("Password").fill(PASSWORD);25    await page.getByRole("button", { name: "Sign in" }).click();26    await expect(page).toHaveURL(/\/$/);27  });28  test.afterEach(() => { expect(errors, errors.join("\n")).toEqual([]); errors.length = 0; });2930  test("overview → apis → api detail", async ({ page }) => {31    await noJunk(page);32    await expect(page.getByRole("heading", { name: "Overview" })).toBeVisible();33    await expect(page.locator(".tile").first()).toBeVisible();34    await page.getByRole("button", { name: "Open navigation" }).click();35    await expect(page.locator("#drawer.open")).toBeVisible();36    await page.locator("#drawer").getByRole("link", { name: "API Atlas" }).click();37    await expect(page.getByRole("heading", { name: "API Atlas" })).toBeVisible();38    await noJunk(page);39    const first = page.locator("table.tbl tbody tr a").first();40    await expect(first).toBeVisible();41    await first.click();42    await noJunk(page);43    await expect(page.getByRole("tab", { name: "Endpoints" })).toBeVisible();44    await page.getByRole("tab", { name: "Evidence" }).click();45    await noJunk(page);46  });4748  test("executions → detail", async ({ page }) => {49    await page.goto("/executions");50    await noJunk(page);51    const first = page.locator("table.tbl tbody tr a").first();52    await expect(first).toBeVisible();53    await first.click();54    await noJunk(page);55    await expect(page.getByRole("heading", { name: /Execution/ })).toBeVisible();56    await expect(page.getByText("Policy decision")).toBeVisible();57  });5859  test("lineage, debt, policy, operations, settings", async ({ page }) => {60    for (const [path, heading] of [["/lineage", "Research Lineage"], ["/debt", "Knowledge Debt"], ["/policy", "Policy Center"], ["/operations", "Operations"], ["/settings", "Settings"]] as const) {61      await page.goto(path);62      await expect(page.getByRole("heading", { name: heading, level: 1 })).toBeVisible();63      await noJunk(page);64    }65    await page.getByRole("tab", { name: "Audit" }).click().catch(() => {});66    await page.goto("/operations");67    await page.getByRole("tab", { name: "Audit" }).click();68    await page.getByRole("button", { name: "Verify chain" }).click();69    await expect(page.getByText(/Chain intact/)).toBeVisible({ timeout: 20_000 });70  });7172  test("dark mode toggle persists", async ({ page }) => {73    await page.getByRole("button", { name: "Toggle dark mode" }).click();74    const theme = await page.evaluate(() => document.documentElement.getAttribute("data-theme"));75    expect(["dark", "light"]).toContain(theme);76    await page.reload();77    expect(await page.evaluate(() => document.documentElement.getAttribute("data-theme"))).toBe(theme);78  });79});80
Files · da58f809c01c422e65c786b05d6ffa3079c9feba
Menu

Theme