This repository has been archived on 2026-05-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
app/apps/e2e/tests/navigation.spec.ts
T
groombook-paperclip[bot] f2501d9972 feat: customizable business branding (name, logo, colors) (#63)
* feat: add customizable business branding (name, logo, colors)

Add admin settings for business branding with name, logo upload, and
color scheme via CSS custom properties. Includes database migration,
API endpoints, admin settings page, and dynamic branding in both
admin nav and customer portal.

Closes #61

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address review feedback on branding PR

- Replace dynamic import with static import for @groombook/db in public branding endpoint
- Restore active nav item background highlight (bg-stone-100) in CustomerPortal
- Remove non-null assertion in settings route, add proper error handling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: trigger CI

* fix: resolve lint error and test failure for branding feature

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update E2E tests for branding changes

- Update navigation test to expect "GroomBook" (default branding) instead
  of hardcoded "Paws & Reflect" since CustomerPortal now uses dynamic branding
- Add /api/branding mock to shared E2E fixtures so BrandingProvider resolves
  immediately in all tests, preventing unhandled fetch interference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: GroomBook CTO <cto@groombook.dev>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: GroomBook CTO <cto@groombook.app>
2026-03-19 11:07:07 +00:00

91 lines
3.2 KiB
TypeScript

import { test, expect } from "./fixtures.js";
/**
* 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("GroomBook")).toBeVisible();
await expect(page.locator("nav")).toBeVisible();
});
test("admin appointments page loads", async ({ page }) => {
await page.goto("/admin");
await expect(page.getByText("GroomBook")).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("GroomBook")).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("GroomBook")).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("GroomBook")).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("GroomBook")).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("GroomBook")).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();
});