import { fireEvent, screen, waitFor, within } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import type { StallCard, StallMine } from "../../api/stall"; import { DEPARTMENTS, makeMe, renderApp } from "../../test/auth"; import { mockFetch } from "../../test/fetchMock"; import { makeCard } from "../../test/packets"; import { memoryStorage } from "../supervisor/memoryStorage"; import { NONE_ASSIGNED } from "./StallHome"; const ANDY = makeMe({ roles: ["shop:03:worker"], screens: ["stall"], user: { sam_account: "weld.andy", display_name: "Andy Welder" } }); function stallCard(id: number, over: Partial = {}): StallCard { const { open_cos: _ignored, ...base } = makeCard({ id, unit: { id: 100 + id, number: `L66200${id}` }, holder: "Stall 1" }); return { ...base, open_cos: [], station_id: null, station_name: null, ...over }; } const MINE: StallMine = { mine: [ stallCard(1, { status: "in_progress", station: null, station_id: 1, station_name: "Stall 1", clock: { elapsed_ms: 3_600_000, running: false }, target_hrs: 4.5 }), stallCard(3, { status: "assigned", station: null, station_id: 7, station_name: "Bay 2", dept: { code: "14", name: "Electrical" } }), ], submitted: [stallCard(2, { status: "review", station: { id: 1, name: "Stall 1" }, station_id: 1, station_name: "Stall 1" })], }; function base(mine: StallMine = MINE) { return { "/api/auth/me": { body: ANDY }, "/api/departments": { body: DEPARTMENTS }, "/api/stall/mine": { body: mine }, }; } const column = (title: string) => screen.getByRole("heading", { name: new RegExp(`^${title}`) }).closest("section") as HTMLElement; beforeEach(() => { vi.stubGlobal("localStorage", memoryStorage()); }); describe("StallHome", () => { it("lists my packets across stations, each with its station, and has no station picker", async () => { const fetch = mockFetch(base()); renderApp("/stall"); const mine = await waitFor(() => column("My packets")); const one = within(mine).getByRole("link", { name: /^L662001/ }); expect(one).toHaveTextContent("01:00:00 paused · target 4.5 h"); expect(one).toHaveTextContent("Stall 1"); expect(within(mine).getByRole("link", { name: /^L662003/ })).toHaveTextContent("Bay 2"); expect(within(column("Submitted, waiting on supervisor")).getByRole("link", { name: /^L662002/ })).toBeInTheDocument(); expect(screen.queryByRole("combobox", { name: "Station" })).not.toBeInTheDocument(); expect(screen.getByText("Weld stall · Andy Welder")).toHaveClass("eyebrow"); const urls = fetch.mock.calls.map(([u]) => String(u)); expect(urls.some((u) => u.startsWith("/api/stall/mine"))).toBe(true); expect(urls.some((u) => u.includes("station_id") || u.startsWith("/api/shop/stations") || u.startsWith("/api/shop/stall"))).toBe(false); }); it("says the supervisor assigns packets when none are assigned", async () => { mockFetch(base({ mine: [], submitted: [] })); renderApp("/stall"); expect(await screen.findByText(NONE_ASSIGNED)).toBeInTheDocument(); expect(screen.queryByRole("heading", { name: /^My packets/ })).not.toBeInTheDocument(); }); it("keeps the board when only submitted packets are left", async () => { mockFetch(base({ mine: [], submitted: MINE.submitted })); renderApp("/stall"); const mine = await waitFor(() => column("My packets")); expect(mine).toHaveTextContent(`Nothing to work on right now. ${NONE_ASSIGNED}`); }); it("sends the find box to the server without a station", async () => { const fetch = mockFetch(base()); renderApp("/stall"); await waitFor(() => column("My packets")); fireEvent.change(screen.getByRole("searchbox"), { target: { value: "L662003" } }); await waitFor(() => expect(fetch.mock.calls.some(([u]) => String(u) === "/api/stall/mine?q=L662003")).toBe(true)); }); });