supersam/src/services/deliveryInvitationApi.test.js

305 lines
8.4 KiB
JavaScript

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: "Передано клиенту",
},
});
});
});