This commit is contained in:
Stefan Lazic committed 2026-08-03 21:15:24 +01:00
1 parent ec5583f972
commit 546613e677
189 files changed
+9873 -655

No files matched your search

+25 -8
View File
@@ -1,11 +1,13 @@
import { expect, test } from "@playwright/test";
import { Client } from "pg";
import { createPool } from "mariadb";
import { buildMysqlPoolConfig } from "../src/lib/db/mysql-pool-config";
import { SEEDED, completeStaffBookingFlow, signIn } from "./helpers";
/**
* The 9 barber-operations journeys required by the Phase 5 brief. Each
* drives real forms against the real dev server and the seeded Postgres
* database (see e2e/global-setup.ts / prisma/seed.ts). Journeys that only
* drives real forms against the real dev server and the seeded MySQL
* database (migrated from Postgres in Phase 7 — see e2e/global-setup.ts /
* prisma/seed.ts). Journeys that only
* read data reuse the seed's fixed fixtures (today's appointments across
* every status, Sam Osei sitting at the loyalty threshold, Leo's time off);
* journeys that mutate state book a fresh appointment first so they don't
@@ -29,11 +31,10 @@ test.describe.serial("barber operations journeys", () => {
// safety net removes them directly regardless of how the tests above
// exited, on top of (not instead of) each test's own UI-driven cleanup.
test.afterAll(async () => {
const client = new Client({ connectionString: process.env.DATABASE_URL });
await client.connect();
await client.query(`DELETE FROM "TimeOff" WHERE reason = 'E2E conflict test'`);
await client.query(`DELETE FROM "Break" WHERE label = 'Afternoon tea'`);
await client.end();
const pool = createPool(buildMysqlPoolConfig(process.env.DATABASE_URL));
await pool.query("DELETE FROM `TimeOff` WHERE reason = 'E2E conflict test'");
await pool.query("DELETE FROM `Break` WHERE label = 'Afternoon tea'");
await pool.end();
});
test("1. barber signs in and sees today's schedule", async ({ page }) => {
@@ -227,4 +228,20 @@ test.describe.serial("barber operations journeys", () => {
await editSheet.getByRole("button", { name: "Remove Time Off", exact: true }).click();
await expect(page.getByText("E2E conflict test")).toHaveCount(0);
});
test("10. barber receives a new-booking notification", async ({ page }) => {
// Journey 3 (this file runs serially) already booked Marcus a fresh appointment for Jordan
// Blake — see NotificationService/booking-notifications.ts, notifyBookingCreated, which
// queues STAFF_NEW_APPOINTMENT for the assigned barber on every booking.
await signIn(page, SEEDED.owner.email, "password123");
await page.goto("/staff");
const bell = page.getByRole("link", { name: /Notifications, \d+ unread/ });
await expect(bell).toBeVisible();
await bell.click();
await expect(page).toHaveURL(/\/staff\/notifications/);
await expect(page.getByText("New appointment").first()).toBeVisible();
await expect(page.getByText(/Jordan Blake/).first()).toBeVisible();
});
});