import { describe, it, expect, vi, beforeEach } from "vitest"; import { handleEventToast, clearToastDedup } from "./toast-rules"; import type { InstanceEventPayload } from "../types/events"; const mockToastInfo = vi.fn(); const mockToastSuccess = vi.fn(); const mockToastWarning = vi.fn(); const mockToastError = vi.fn(); vi.mock("../state/toast", () => ({ toast: { info: (...args: unknown[]) => mockToastInfo(...args), success: (...args: unknown[]) => mockToastSuccess(...args), warning: (...args: unknown[]) => mockToastWarning(...args), error: (...args: unknown[]) => mockToastError(...args), }, })); describe("toast-rules", () => { beforeEach(() => { clearToastDedup(); mockToastInfo.mockClear(); mockToastSuccess.mockClear(); mockToastWarning.mockClear(); mockToastError.mockClear(); }); it("maps instance.started to info toast", () => { const event: InstanceEventPayload = { event: "instance.started", instance_id: "inst-1", status: "starting", message: "Container starting...", metadata: {}, timestamp: "2026-05-28T12:00:00Z", correlation_id: "corr-1", }; handleEventToast(event); expect(mockToastInfo).toHaveBeenCalledWith("Container starting...", { duration: 3000, }); }); it("maps health_changed to running to success toast", () => { const event: InstanceEventPayload = { event: "instance.health_changed", instance_id: "inst-1", status: "running", message: "Container is running", metadata: { previous_status: "starting" }, timestamp: "2026-05-28T12:00:00Z", correlation_id: "corr-1", }; handleEventToast(event); expect(mockToastSuccess).toHaveBeenCalledWith("Container running", { duration: 3000, }); }); it("maps health_changed to unhealthy to warning toast", () => { const event: InstanceEventPayload = { event: "instance.health_changed", instance_id: "inst-1", status: "unhealthy", message: "Container is unhealthy", metadata: { previous_status: "running" }, timestamp: "2026-05-28T12:00:00Z", correlation_id: "corr-1", }; handleEventToast(event); expect(mockToastWarning).toHaveBeenCalledWith("Container unhealthy", { duration: 5000, }); }); it("maps instance.error to error toast with exit code", () => { const event: InstanceEventPayload = { event: "instance.error", instance_id: "inst-1", status: "error", message: "Container crashed", metadata: { exit_code: 137 }, timestamp: "2026-05-28T12:00:00Z", correlation_id: "corr-1", }; handleEventToast(event); expect(mockToastError).toHaveBeenCalledWith( "Container crashed (exit code: 137)", { duration: 10000 }, ); }); it("maps instance.error to error toast without exit code", () => { const event: InstanceEventPayload = { event: "instance.error", instance_id: "inst-1", status: "error", message: "Build failed", metadata: {}, timestamp: "2026-05-28T12:00:00Z", correlation_id: "corr-1", }; handleEventToast(event); expect(mockToastError).toHaveBeenCalledWith("Build failed", { duration: 10000, }); }); it("deduplicates within one second", () => { const event: InstanceEventPayload = { event: "instance.started", instance_id: "inst-1", status: "starting", message: "Container starting...", metadata: {}, timestamp: "2026-05-28T12:00:00Z", correlation_id: "corr-1", }; handleEventToast(event); handleEventToast(event); expect(mockToastInfo).toHaveBeenCalledTimes(1); }); it("allows duplicate after one second", () => { vi.useFakeTimers(); const event: InstanceEventPayload = { event: "instance.started", instance_id: "inst-1", status: "starting", message: "Container starting...", metadata: {}, timestamp: "2026-05-28T12:00:00Z", correlation_id: "corr-1", }; handleEventToast(event); vi.advanceTimersByTime(1100); handleEventToast(event); expect(mockToastInfo).toHaveBeenCalledTimes(2); vi.useRealTimers(); }); });