import React from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { AllocationPopover } from "./AllocationPopover.js"; const mockUseQuery = vi.fn(); const mockUseMutation = vi.fn(() => ({ mutate: vi.fn() })); const mockUseUtils = vi.fn(() => ({ allocation: { getAssignmentById: { invalidate: vi.fn() }, listView: { invalidate: vi.fn() }, }, })); vi.mock("~/lib/trpc/client.js", () => ({ trpc: { useUtils: () => mockUseUtils(), allocation: { getAssignmentById: { useQuery: (...args: unknown[]) => mockUseQuery(...args), }, }, timeline: { updateAllocationInline: { useMutation: () => mockUseMutation(), }, carveAllocationRange: { useMutation: () => mockUseMutation(), }, }, }, })); vi.mock("~/hooks/useInvalidatePlanningViews.js", () => ({ useInvalidateTimeline: () => vi.fn(), })); vi.mock("~/hooks/useViewportPopover.js", () => ({ useViewportPopover: () => ({ ref: { current: null }, style: {}, }), })); vi.mock("~/components/ui/DateInput.js", () => ({ DateInput: () => null, })); vi.mock("~/components/ui/ProjectCombobox.js", () => ({ ProjectCombobox: () => null, })); describe("AllocationPopover", () => { beforeEach(() => { mockUseQuery.mockReset(); mockUseMutation.mockClear(); mockUseUtils.mockClear(); }); it("renders an error state when the allocation lookup fails", () => { mockUseQuery.mockReturnValue({ data: undefined, isLoading: false, error: new Error("Assignment not found"), }); const html = renderToStaticMarkup( {}} onOpenPanel={() => {}} />, ); expect(html).toContain("data-testid=\"timeline-allocation-popover-error\""); expect(html).toContain("The selected booking could not be loaded right now."); expect(html).toContain("Assignment not found"); }); it("renders an unavailable state when the lookup returns no allocation", () => { mockUseQuery.mockReturnValue({ data: undefined, isLoading: false, error: null, }); const html = renderToStaticMarkup( {}} onOpenPanel={() => {}} />, ); expect(html).toContain("data-testid=\"timeline-allocation-popover-unavailable\""); expect(html).toContain("The selected booking could not be resolved from the current timeline data."); }); it("renders a loading skeleton when the allocation is being fetched", () => { mockUseQuery.mockReturnValue({ data: undefined, isLoading: true, error: null, }); const html = renderToStaticMarkup( {}} onOpenPanel={() => {}} />, ); expect(html).toContain("data-testid=\"timeline-allocation-popover-loading\""); }); it("renders allocation data when provided as initialAllocation", () => { // useQuery is always called (with enabled: false), so we need a baseline return value mockUseQuery.mockReturnValue({ data: undefined, isLoading: false, error: null, }); const allocation = { id: "assignment_1", entityId: "assignment_1", projectId: "project_1", resourceId: "resource_1", startDate: new Date("2026-01-01"), endDate: new Date("2026-01-31"), hoursPerDay: 8, role: "Developer", metadata: null, resource: { displayName: "Alice Smith", eid: "alice.smith", lcrCents: 0, }, }; const html = renderToStaticMarkup( {}} onOpenPanel={() => {}} />, ); expect(html).not.toContain("data-testid=\"timeline-allocation-popover-error\""); expect(html).not.toContain("data-testid=\"timeline-allocation-popover-unavailable\""); expect(html).not.toContain("data-testid=\"timeline-allocation-popover-loading\""); }); });