c901b1135d
* feat: flip routing — customer portal at /, admin at /admin Move all admin dashboard routes under /admin prefix and mount the customer portal at root (/). This gives customers clean, shareable URLs while staff bookmark /admin. - Admin routes: /admin, /admin/clients, /admin/services, etc. - Customer portal: / (root) - Admin nav "Customer Portal" link points to / for staff preview - Updated tests for new route structure and fixed React 19 act compat Closes #56 Co-Authored-By: Paperclip <noreply@paperclip.ing> * fix(e2e): update tests for routing flip — admin at /admin, portal at / All E2E tests now use /admin prefix for admin routes (clients, services, staff, invoices, reports, book). Adds customer portal smoke test at /. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(e2e): use specific locator for customer portal test getByText('Paws & Reflect') matched 3 elements causing strict mode violation. Scope to navigation role for unique match. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Groom Book CTO <cto@groombook.dev> Co-authored-by: Paperclip <noreply@paperclip.ing> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
91 lines
3.3 KiB
TypeScript
91 lines
3.3 KiB
TypeScript
import { test, expect } from "@playwright/test";
|
|
|
|
/**
|
|
* Navigation smoke tests — verifies that each page loads without errors.
|
|
* These tests mock all API calls so they can run without a live backend.
|
|
*/
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
// Intercept all API calls and return empty defaults so pages render.
|
|
// Reports endpoints need shaped responses (not bare []) to avoid render crashes.
|
|
await page.route("/api/**", (route) => {
|
|
const url = route.request().url();
|
|
if (url.includes("/api/reports/summary")) {
|
|
return route.fulfill({
|
|
json: {
|
|
from: "",
|
|
to: "",
|
|
revenue: { totalCents: 0, paidInvoices: 0 },
|
|
appointments: { total: 0, completed: 0, cancelled: 0, noShow: 0 },
|
|
clients: { total: 0, new: 0 },
|
|
},
|
|
});
|
|
}
|
|
if (url.includes("/api/reports/revenue")) {
|
|
return route.fulfill({ json: { byPeriod: [], byGroomer: [] } });
|
|
}
|
|
if (url.includes("/api/reports/appointments")) {
|
|
return route.fulfill({ json: { byPeriod: [] } });
|
|
}
|
|
if (url.includes("/api/reports/services")) {
|
|
return route.fulfill({ json: { rows: [] } });
|
|
}
|
|
if (url.includes("/api/reports/clients")) {
|
|
return route.fulfill({
|
|
json: { newClients: [], activeInPeriodCount: 0, churnRisk: [], churnRiskTotal: 0 },
|
|
});
|
|
}
|
|
// Appointments, clients, services, staff, invoices, book, etc.
|
|
return route.fulfill({ json: [] });
|
|
});
|
|
});
|
|
|
|
test("customer portal loads at root", async ({ page }) => {
|
|
await page.goto("/");
|
|
await expect(page.getByRole("navigation").getByText("Paws & Reflect")).toBeVisible();
|
|
await expect(page.locator("nav")).toBeVisible();
|
|
});
|
|
|
|
test("admin appointments page loads", async ({ page }) => {
|
|
await page.goto("/admin");
|
|
await expect(page.getByText("Groom Book")).toBeVisible();
|
|
// Calendar/appointments view renders
|
|
await expect(page.locator("nav")).toBeVisible();
|
|
});
|
|
|
|
test("admin clients page loads", async ({ page }) => {
|
|
await page.goto("/admin/clients");
|
|
await expect(page.getByText("Groom Book")).toBeVisible();
|
|
await expect(page.getByRole("link", { name: "Clients" })).toBeVisible();
|
|
});
|
|
|
|
test("admin services page loads", async ({ page }) => {
|
|
await page.goto("/admin/services");
|
|
await expect(page.getByText("Groom Book")).toBeVisible();
|
|
await expect(page.getByRole("link", { name: "Services" })).toBeVisible();
|
|
});
|
|
|
|
test("admin staff page loads", async ({ page }) => {
|
|
await page.goto("/admin/staff");
|
|
await expect(page.getByText("Groom Book")).toBeVisible();
|
|
await expect(page.getByRole("link", { name: "Staff" })).toBeVisible();
|
|
});
|
|
|
|
test("admin invoices page loads", async ({ page }) => {
|
|
await page.goto("/admin/invoices");
|
|
await expect(page.getByText("Groom Book")).toBeVisible();
|
|
await expect(page.getByRole("link", { name: "Invoices" })).toBeVisible();
|
|
});
|
|
|
|
test("admin reports page loads", async ({ page }) => {
|
|
await page.goto("/admin/reports");
|
|
await expect(page.getByText("Groom Book")).toBeVisible();
|
|
await expect(page.getByRole("link", { name: "Reports" })).toBeVisible();
|
|
});
|
|
|
|
test("admin booking portal loads", async ({ page }) => {
|
|
await page.goto("/admin/book");
|
|
await expect(page.getByText("Book an Appointment")).toBeVisible();
|
|
await expect(page.getByText("Choose a service")).toBeVisible();
|
|
});
|