import React from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { describe, expect, it } from "vitest"; import { OrderPathFunnelBlock } from "./OrderPathFunnelBlock"; // Фикстура — блок order_path из admin_comms_funnel (реальные цифры за 30 дней на 29.09.2026). const funnel = { order_path: { stages: [ { key: "created", label: "Групп в работе", value: 396, pct: 100 }, { key: "sms", label: "Первое SMS", value: 340, pct: 85.9 }, { key: "dated", label: "Дата согласована", value: 161, pct: 40.7 }, { key: "done", label: "Выдано по цепочке", value: 134, pct: 33.8 }, ], bypass: { delivered: 199, paid_storage: 3, cancelled: 0, no_confirmation: 42 }, split: { pickup: 235, delivery: 161 }, channels: [ { channel: "manual", count: 135 }, { channel: "sms", count: 20 }, { channel: "call", count: 7 }, ], sources: [ { source: "manual", count: 135 }, { source: "autocall", count: 6 }, { source: "none", count: 20 }, ], }, }; const empty = { order_path: { stages: [], bypass: {}, split: {}, sources: [] } }; describe("OrderPathFunnelBlock", () => { const html = renderToStaticMarkup(); it("подписывает этапы со значениями и процентами", () => { for (const label of ["Групп в работе", "Первое SMS", "Дата согласована", "Выдано по цепочке"]) { expect(html).toContain(label); } expect(html).toContain("396 · 100%"); expect(html).toContain("340 · 85.9%"); expect(html).toContain("134 · 33.8%"); }); it("считает конверсию между ступенями", () => { expect(html).toContain("Групп в работе → Первое SMS"); expect(html).toContain("85.9%"); expect(html).toContain("Первое SMS → Дата согласована"); expect(html).toContain("47.4%"); // 161/340 expect(html).toContain("Дата согласована → Выдано по цепочке"); }); it("честно показывает то, что прошло мимо цепочки", () => { expect(html).toContain("Мимо цепочки (без даты)"); expect(html).toContain("выдано 199"); expect(html).toContain("платное хранение 3"); expect(html).toContain("воронка выше их не считает"); expect(html).toContain("без согласования 42"); }); it("показывает источники даты и разбивку по типу заказа", () => { expect(html).toContain("Менеджер"); expect(html).toContain("Робот-звонок"); expect(html).toContain("В обход (без даты)"); expect(html).toContain("Самовывоз"); expect(html).toContain("235"); expect(html).toContain("Доставка"); }); it("подписывает клиентские источники даты, а не показывает ключи БД", () => { const withClientSources = renderToStaticMarkup( , ); expect(withClientSources).toContain("SMS-ссылка"); expect(withClientSources).toContain("Ссылка (прямой заход)"); expect(withClientSources).toContain("Push"); expect(withClientSources).toContain("Мессенджер"); expect(withClientSources).not.toContain(">client<"); expect(withClientSources).not.toContain(">messenger<"); }); it("на пустом периоде пишет заглушку", () => { const e = renderToStaticMarkup(); expect(e).toContain("За период заказов нет"); expect(e).toContain("Путь заказа"); }); it("показывает заглушку загрузки, пока данных нет", () => { const l = renderToStaticMarkup(); expect(l).toContain("Путь заказа"); expect(l).toContain("Загружаю…"); }); it("показывает, каким каналом согласовали дату", () => { expect(html).toContain("Как согласовали дату"); expect(html).toContain("Логист"); expect(html).toContain("SMS-ссылка"); expect(html).toContain("Звонок робота"); expect(html).toContain("135"); expect(html).toContain("20"); }); });