From 0987dcc33a627a25c2fc92a4d2e56ea137f1a756 Mon Sep 17 00:00:00 2001 From: DEls Date: Sat, 10 Oct 2026 00:14:41 +0200 Subject: [PATCH] test(workforce): update the missing-rate overview for this-month figures The overview test asserted the previous all-time sub-line wording and that employee_rates was read with a site filter, both of which the cost workforce commits changed on purpose. Pins the clock so "this month" is a fixed window, and gives the unpriced worker an October entry so the new month-scoped warning is actually exercised rather than skipped. Added a case asserting rate history is read unfiltered, which is what lets a worker who moved sites keep the rate he was paid at. Co-Authored-By: Claude Opus 5.5 --- .../workforce/missing-rate-overview.test.tsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/app/dashboard/workforce/missing-rate-overview.test.tsx b/src/app/dashboard/workforce/missing-rate-overview.test.tsx index 31a6e7c..6f21995 100644 --- a/src/app/dashboard/workforce/missing-rate-overview.test.tsx +++ b/src/app/dashboard/workforce/missing-rate-overview.test.tsx @@ -1,5 +1,5 @@ import { renderToStaticMarkup } from "react-dom/server"; -import { beforeEach, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, expect, it, vi } from "vitest"; const mocks = vi.hoisted(() => ({ list: vi.fn(), scope: vi.fn() })); vi.mock("next/navigation", () => ({ useRouter: () => ({ refresh: vi.fn() }) })); vi.mock("@/lib/pb", () => ({ pbAdmin: async () => ({ collection: (name: string) => ({ getFullList: (options: unknown) => mocks.list(name, options) }) }) })); @@ -12,6 +12,10 @@ vi.mock("./workforce-charts", () => ({ WorkforceHoursChart: () => null, TopWorke import WorkforceLanding from "./page"; beforeEach(() => { + // Pinned so "this month" is a fixed window: the unpriced-hours warning + // is now scoped to the current month, not to all history. + vi.useFakeTimers(); + vi.setSystemTime(new Date("2026-10-04T10:00:00Z")); mocks.scope.mockResolvedValue({ active: [{ id: "site1" }], allowed: [{ id: "site1", name: "Head Office" }], mode: "single", unrestricted: false }); mocks.list.mockImplementation(async (name: string) => { if (name === "employees") return [ @@ -22,21 +26,30 @@ beforeEach(() => { { employee: "paid", date_logged: "2026-09-30", hours_worked: 8 }, { employee: "paid", date_logged: "2026-10-01", hours_worked: 8 }, { employee: "missing", date_logged: "2026-09-15", hours_worked: 5 }, + { employee: "missing", date_logged: "2026-10-02", hours_worked: 5 }, ]; if (name === "employee_rates") return [{ employee: "paid", effective_from: "2026-10-01", rate_per_hour: 60 }]; if (name === "sites") return [{ id: "site1", name: "Head Office" }]; return []; }); }); +afterEach(() => vi.useRealTimers()); it("shows a missing-rate action and an incomplete cost total using dated payroll", async () => { const html = renderToStaticMarkup(await WorkforceLanding({ searchParams: Promise.resolve({}) })); expect(html).toContain("Needs attention"); expect(html).toContain("Missing Worker"); expect(html).toContain("Add rate for Missing Worker"); - expect(html).toContain("5 hrs still need rates"); + // Only the 5 October hours are unpriced this month; the 5 September + // ones are history and no longer reported on the tile. + expect(html).toContain("5 hrs this month still need rates"); expect(html).toContain("Paid Worker: 880"); - expect(mocks.list).toHaveBeenCalledWith("employee_rates", { filter: 'employee.site="site1"' }); +}); + +it("does not filter rate history by site, so a worker priced elsewhere is still priced", async () => { + await WorkforceLanding({ searchParams: Promise.resolve({}) }); + const rateCall = mocks.list.mock.calls.find(([name]) => name === "employee_rates"); + expect(rateCall?.[1]).toBeUndefined(); }); it("hides inactive workers from rate alerts but preserves their recorded costs", async () => {