import { fireEvent, screen, waitFor } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { VendorDialog } from "@/app/(protected)/workorders/_components/list/table/cells/vendor-dialog"; import type { Vendor } from "@/domain/vendors/types/vendor"; import type { VendorDropdownItem } from "@/domain/work-orders/types/work-order"; import { renderWithProviders } from "@/test/test-utils"; const mutateAsync = vi.fn(); vi.mock("@/domain/vendors/use-cases/use-create-vendor", () => ({ useCreateVendor: () => ({ mutateAsync, isPending: false, }), })); const existingVendor: VendorDropdownItem = { id: 10, companyName: "Gateway Plumbing", contactName: "Jordan Lee", tradeSpecialties: "Plumbing", address: "1 Main St", distanceMiles: 4.2, email: "dispatch@gateway.test", }; const createdVendor: Vendor = { id: 99, companyId: 10, companyName: "Gateway Plumbing", contactName: "Jordan Lee", email: "dispatch@gateway.test", phone: "(314) 555-9999", companyPhone: "", googleMapsUrl: "", notes: "", totalJobs: 0, address: "1 Main St", city: "", state: "", zip: "", tradeSpecialties: "Plumbing", isActive: true, preferredContact: "Phone", }; describe("VendorDialog stable technician identity", () => { beforeEach(() => { mutateAsync.mockReset(); mutateAsync.mockResolvedValue(createdVendor); }); it("keeps draft identity on same-name collision and posts live phone on save", async () => { const onSave = vi.fn(); const onOpenChange = vi.fn(); renderWithProviders( , ); fireEvent.click(screen.getByRole("button", { name: /\+ add technician/i })); fireEvent.change(screen.getByPlaceholderText("Full name"), { target: { value: "Jordan Lee" }, }); fireEvent.change(screen.getByPlaceholderText("(000) 000-0000"), { target: { value: "3145550199" }, }); fireEvent.click(screen.getByRole("button", { name: /^add$/i })); // Draft stays staged: add form collapses and select still shows the colliding name. expect(screen.getByRole("button", { name: /\+ add technician/i })).toBeTruthy(); expect(screen.getByRole("button", { name: "Jordan Lee" })).toBeTruthy(); fireEvent.change(screen.getByDisplayValue("3145550199"), { target: { value: "(314) 555-9999" }, }); fireEvent.click(screen.getByRole("button", { name: /^save$/i })); await waitFor(() => { expect(mutateAsync).toHaveBeenCalledTimes(1); }); expect(mutateAsync).toHaveBeenCalledWith( expect.objectContaining({ contactName: "Jordan Lee", companyName: "Gateway Plumbing", phone: "(314) 555-9999", }), ); await waitFor(() => { expect(onSave).toHaveBeenCalledWith( expect.objectContaining({ vendorId: "99", tech: "Jordan Lee", company: "Gateway Plumbing", techPhone: "(314) 555-9999", }), ); }); // Must not persist the pre-existing colliding vendor id. expect(onSave.mock.calls[0]?.[0].vendorId).not.toBe("10"); }); it("does not clear staged draft when technicianOptions rebuild after add", async () => { const onSave = vi.fn(); mutateAsync.mockResolvedValue({ ...createdVendor, id: 88, contactName: "Casey New", phone: "3145550188", }); renderWithProviders( , ); fireEvent.click(screen.getByRole("button", { name: /\+ add technician/i })); fireEvent.change(screen.getByPlaceholderText("Full name"), { target: { value: "Casey New" }, }); fireEvent.change(screen.getByPlaceholderText("(000) 000-0000"), { target: { value: "3145550188" }, }); fireEvent.click(screen.getByRole("button", { name: /^add$/i })); expect(screen.getByRole("button", { name: "Casey New" })).toBeTruthy(); fireEvent.click(screen.getByRole("button", { name: /^save$/i })); await waitFor(() => { expect(mutateAsync).toHaveBeenCalledTimes(1); }); expect(mutateAsync).toHaveBeenCalledWith( expect.objectContaining({ contactName: "Casey New", phone: "3145550188", }), ); await waitFor(() => { expect(onSave).toHaveBeenCalledWith( expect.objectContaining({ vendorId: "88", tech: "Casey New", }), ); }); }); it("keeps a staged draft when the same company is picked again", async () => { const onSave = vi.fn(); mutateAsync.mockResolvedValue({ ...createdVendor, id: 88, contactName: "Casey New", phone: "3145550188", }); renderWithProviders( , ); fireEvent.click(screen.getByRole("button", { name: /\+ add technician/i })); fireEvent.change(screen.getByPlaceholderText("Full name"), { target: { value: "Casey New" }, }); fireEvent.change(screen.getByPlaceholderText("(000) 000-0000"), { target: { value: "3145550188" }, }); fireEvent.click(screen.getByRole("button", { name: /^add$/i })); fireEvent.click(screen.getByRole("button", { name: "Gateway Plumbing" })); const companyButtons = await screen.findAllByRole("button", { name: "Gateway Plumbing" }); fireEvent.click(companyButtons[companyButtons.length - 1]!); fireEvent.click(screen.getByRole("button", { name: /^save$/i })); await waitFor(() => { expect(mutateAsync).toHaveBeenCalledWith( expect.objectContaining({ contactName: "Casey New", phone: "3145550188", }), ); }); expect(onSave).toHaveBeenCalledWith( expect.objectContaining({ vendorId: "88", tech: "Casey New", }), ); }); });