/** * Navigation route smoke test — runs against the live dev server (port 3100). * * Verifies that every sidebar destination in AppShell (navSections + adminNavEntries) * returns a real page (not 404) for an authenticated ADMIN user. * * Config: playwright.dev.config.ts * Auth: e2e/dev-system/.auth/admin.json (created by global-setup.ts) * * Run: * pnpm --filter @capakraken/web exec playwright test \ * --config playwright.dev.config.ts \ * e2e/dev-system/nav-smoke.spec.ts */ import * as path from "path"; import { expect, test } from "@playwright/test"; // ── Standalone href list ──────────────────────────────────────────────────── // Mirrors AppShell.tsx navSections + adminNavEntries. // DO NOT import AppShell here — that pulls in the full Next.js component tree. // Keep in sync with apps/web/src/components/layout/AppShell.tsx. const REGULAR_NAV_HREFS = [ // Planning "/dashboard", "/timeline", "/allocations", "/staffing", "/notifications", // Estimating "/estimates", "/admin/rate-cards", "/admin/effort-rules", "/admin/experience-multipliers", // Resources "/resources", "/projects", "/roles", // Analytics "/analytics/skills", "/reports/chargeability", "/reports/builder", "/analytics/computation-graph", "/analytics/insights", // Time Off "/vacations/my", "/vacations", // Account "/account/security", ] as const; const ADMIN_NAV_HREFS = [ "/admin/blueprints", "/admin/clients", "/admin/countries", "/admin/org-units", "/admin/utilization-categories", "/admin/management-levels", "/admin/imports", "/admin/calculation-rules", "/admin/vacations", "/admin/users", "/admin/system-roles", "/admin/settings", "/admin/notifications", "/admin/webhooks", "/admin/activity-log", ] as const; const ALL_HREFS = [...REGULAR_NAV_HREFS, ...ADMIN_NAV_HREFS] as const; // ── Auth state ────────────────────────────────────────────────────────────── // Reuse the saved admin session from global-setup — avoids hitting the rate limiter. test.use({ storageState: path.join(__dirname, ".auth/admin.json"), }); // ── Tests ─────────────────────────────────────────────────────────────────── test.describe("nav smoke — all sidebar routes resolve for admin (no 404)", () => { for (const href of ALL_HREFS) { test(href, async ({ page }) => { // waitUntil: "commit" — only wait for HTTP response headers, not full render. // Fast enough for a 404 check; avoids timeouts on data-heavy pages. // Generous timeout: analytics/insights may need JIT compile on first visit (~15 s). const response = await page.goto(href, { waitUntil: "commit", timeout: 60_000, }); // HTTP response must not be 404 expect( response?.status(), `${href} returned HTTP ${response?.status()} — expected any status except 404`, ).not.toBe(404); // Belt-and-suspenders: also check the rendered page doesn't contain Next.js 404 text await expect( page.locator("text=This page could not be found"), `${href} rendered a Next.js 404 page`, ).not.toBeVisible({ timeout: 15_000 }); }); } });