import { describe, it, expect, vi, beforeEach } from "vitest"; import { UmamiAnalyticsService } from "./umami"; describe("UmamiAnalyticsService", () => { const mockConfig = { websiteId: "test-website-id", apiEndpoint: "https://analytics.test", enabled: true, }; const mockLogger = { debug: vi.fn(), warn: vi.fn(), error: vi.fn(), trace: vi.fn(), }; beforeEach(() => { vi.clearAllMocks(); global.fetch = vi.fn(); }); it("should not send payload if disabled", async () => { const service = new UmamiAnalyticsService({ ...mockConfig, enabled: false, }); service.track("test-event"); expect(global.fetch).not.toHaveBeenCalled(); }); it("should send payload with correct data for track", async () => { const service = new UmamiAnalyticsService(mockConfig, mockLogger); (global.fetch as any).mockResolvedValue({ ok: true }); service.track("test-event", { foo: "bar" }); // Wait for async sendPayload await new Promise((resolve) => setTimeout(resolve, 0)); expect(global.fetch).toHaveBeenCalledWith( "https://analytics.test/api/send", expect.objectContaining({ method: "POST", body: expect.stringContaining('"type":"event"'), }), ); const callBody = JSON.parse((global.fetch as any).mock.calls[0][1].body); expect(callBody.payload.name).toBe("test-event"); expect(callBody.payload.data.foo).toBe("bar"); expect(callBody.payload.website).toBe("test-website-id"); }); it("should log warning if send fails", async () => { const service = new UmamiAnalyticsService(mockConfig, mockLogger); (global.fetch as any).mockResolvedValue({ ok: false, status: 500, text: () => Promise.resolve("Internal error"), }); service.track("test-event"); await new Promise((resolve) => setTimeout(resolve, 10)); expect(mockLogger.warn).toHaveBeenCalledWith( "Umami API responded with error", expect.objectContaining({ status: 500 }), ); }); });