import { beforeEach, describe, expect, it, vi } from "vitest"; const { fetchMock, invoke, rpc } = vi.hoisted(() => ({ fetchMock: vi.fn(), invoke: vi.fn(), rpc: vi.fn(), })); vi.mock("../supabaseClient", () => ({ hasSupabaseConfig: true, supabaseAnonKey: "anon-key", supabaseUrl: "https://supa.example.test", supabase: { rpc, functions: { invoke, }, }, })); import { buildShowcaseInvitation, confirmDeliveryChoice, fetchDeliveryInvitation, __resetLocalDeliveryInvitationCache, reportDeliveryResult, requestDeliveryLink, transferDeliveryToLogistics, } from "./deliveryInvitationApi"; describe("deliveryInvitationApi", () => { beforeEach(() => { fetchMock.mockReset(); invoke.mockReset(); rpc.mockReset(); vi.stubGlobal("fetch", fetchMock); __resetLocalDeliveryInvitationCache(); const storage = new Map(); vi.stubGlobal("localStorage", { getItem: (key) => storage.get(key) ?? null, setItem: (key, value) => { storage.set(key, String(value)); }, removeItem: (key) => { storage.delete(key); }, clear: () => { storage.clear(); }, }); }); it("loads a delivery invitation by token", async () => { rpc.mockResolvedValueOnce({ data: { ok: true, invitation: { orderId: "order-1", token: "token-1", }, }, error: null, }); await expect(fetchDeliveryInvitation("token-1")).resolves.toEqual({ orderId: "order-1", token: "token-1", }); expect(rpc).toHaveBeenCalledWith("get_delivery_invitation_by_token", { p_token: "token-1", }); expect(fetchMock).not.toHaveBeenCalled(); expect(invoke).not.toHaveBeenCalled(); }); it("throws a readable error when loading invitation fails", async () => { rpc.mockResolvedValueOnce({ data: null, error: new Error("Invitation not found"), }); await expect(fetchDeliveryInvitation("token-1")).rejects.toThrow("Invitation not found"); }); it("returns a local showcase invitation for the preview token", async () => { await expect(fetchDeliveryInvitation("showcase")).resolves.toMatchObject({ token: "showcase", orderNumber: "CD-CLIENT-001", customerName: "Мария Волкова", state: "awaiting_choice", }); expect(invoke).toHaveBeenCalledWith("get-delivery-invitation", { body: { token: "showcase", }, }); }); it("falls back to a local client invitation when the edge function fails", async () => { invoke.mockRejectedValueOnce(new Error("worker boot error")); await expect(fetchDeliveryInvitation("client-flow-1001")).resolves.toMatchObject({ token: "client-flow-1001", orderNumber: "CD-240031", customerName: "Мария Волкова", state: "awaiting_choice", orderItems: [ { name: "Кухонный гарнитур", quantity: "1 комплект" }, { name: "Фурнитура Blum", quantity: "12 шт" }, { name: "Монтажный комплект", quantity: "1 набор" }, ], availableSlots: expect.arrayContaining([ expect.stringMatching(/, До обеда$/), expect.stringMatching(/, После обеда$/), ]), }); expect(invoke).toHaveBeenCalledWith("get-delivery-invitation", { body: { token: "client-flow-1001", }, }); }); it("builds showcase slots for tomorrow and the following day", () => { const invitation = buildShowcaseInvitation("showcase", new Date("2026-04-14T09:00:00Z")); expect(invitation.availableSlots).toEqual([ "2026-04-15, До обеда", "2026-04-15, После обеда", "2026-04-16, До обеда", "2026-04-16, После обеда", ]); }); it("includes readable order items in the showcase invitation", () => { const invitation = buildShowcaseInvitation("showcase", new Date("2026-04-14T09:00:00Z")); expect(invitation.orderItems).toEqual([ { name: "Кухонный гарнитур", quantity: "1 комплект" }, { name: "Фурнитура Blum", quantity: "12 шт" }, { name: "Монтажный комплект", quantity: "1 набор" }, ]); }); it("confirms a delivery choice with the chosen slot", async () => { rpc.mockResolvedValueOnce({ data: { ok: true, orderId: "order-1", }, error: null, }); await expect( confirmDeliveryChoice({ token: "token-1", deliveryDate: "2026-04-01", deliveryTime: "Первая половина дня", }), ).resolves.toEqual({ ok: true, orderId: "order-1", }); expect(rpc).toHaveBeenCalledWith("confirm_delivery_choice_by_token", { p_token: "token-1", p_delivery_date: "2026-04-01", p_delivery_time: "Первая половина дня", }); expect(invoke).not.toHaveBeenCalled(); }); it("updates the local client invitation when confirmation falls back to cache", async () => { invoke.mockRejectedValueOnce(new Error("worker boot error")); await fetchDeliveryInvitation("client-flow-1001"); invoke.mockRejectedValueOnce(new Error("worker boot error")); await expect( confirmDeliveryChoice({ token: "client-flow-1001", deliveryDate: "2026-04-16", deliveryTime: "После обеда", }), ).resolves.toMatchObject({ ok: true, invitation: { token: "client-flow-1001", deliveryDate: "2026-04-16", deliveryTime: "После обеда", state: "confirmed", }, }); await expect(fetchDeliveryInvitation("client-flow-1001")).resolves.toMatchObject({ token: "client-flow-1001", deliveryDate: "2026-04-16", deliveryTime: "После обеда", state: "confirmed", }); }); it("restores the saved local client invitation after cache reset", async () => { invoke.mockRejectedValueOnce(new Error("worker boot error")); await fetchDeliveryInvitation("client-flow-1001"); invoke.mockRejectedValueOnce(new Error("worker boot error")); await confirmDeliveryChoice({ token: "client-flow-1001", deliveryDate: "2026-04-16", deliveryTime: "После обеда", }); __resetLocalDeliveryInvitationCache(); await expect(fetchDeliveryInvitation("client-flow-1001")).resolves.toMatchObject({ token: "client-flow-1001", deliveryDate: "2026-04-16", deliveryTime: "После обеда", state: "confirmed", }); }); it("creates a delivery invitation from order data", async () => { invoke.mockResolvedValueOnce({ data: { ok: true, invitation: { orderId: "order-1", }, }, error: null, }); await expect( requestDeliveryLink({ orderId: "order-1", orderNumber: "CD-240031", customerName: "Мария Волкова", availableSlots: ["Первая половина дня"], }), ).resolves.toEqual({ ok: true, invitation: { orderId: "order-1", }, }); expect(invoke).toHaveBeenCalledWith("create-delivery-invitation", { body: { orderId: "order-1", orderNumber: "CD-240031", customerName: "Мария Волкова", availableSlots: ["Первая половина дня"], }, }); }); it("transfers the order to logistics", async () => { invoke.mockResolvedValueOnce({ data: { ok: true }, error: null, }); await expect( transferDeliveryToLogistics({ orderId: "order-1", reason: "no_response", }), ).resolves.toEqual({ ok: true }); expect(invoke).toHaveBeenCalledWith("transfer-to-logistics", { body: { orderId: "order-1", reason: "no_response", }, }); }); it("reports delivery result", async () => { invoke.mockResolvedValueOnce({ data: { ok: true }, error: null, }); await expect( reportDeliveryResult({ orderId: "order-1", result: "delivered", note: "Передано клиенту", }), ).resolves.toEqual({ ok: true }); expect(invoke).toHaveBeenCalledWith("report-delivery-result", { body: { orderId: "order-1", result: "delivered", note: "Передано клиенту", }, }); }); });