import { describe, it, expect, vi, beforeEach } from "vitest"; import { GotifyNotificationService } from "./gotify"; describe("GotifyNotificationService", () => { const mockConfig = { url: "https://gotify.test", token: "test-token", enabled: true, }; const mockLogger = { error: vi.fn(), }; beforeEach(() => { vi.clearAllMocks(); global.fetch = vi.fn(); }); it("should not notify if disabled", async () => { const service = new GotifyNotificationService({ ...mockConfig, enabled: false, }); await service.notify({ title: "test", message: "test" }); expect(global.fetch).not.toHaveBeenCalled(); }); it("should send correct payload to Gotify", async () => { const service = new GotifyNotificationService(mockConfig, mockLogger); (global.fetch as any).mockResolvedValue({ ok: true }); await service.notify({ title: "Alert", message: "Critical issue", priority: 8, }); expect(global.fetch).toHaveBeenCalledWith( "https://gotify.test/message?token=test-token", expect.objectContaining({ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ title: "Alert", message: "Critical issue", priority: 8, }), }), ); }); it("should handle missing trailing slash in URL", async () => { const service = new GotifyNotificationService({ ...mockConfig, url: "https://gotify.test", }); (global.fetch as any).mockResolvedValue({ ok: true }); await service.notify({ title: "test", message: "test" }); expect((global.fetch as any).mock.calls[0][0]).toBe( "https://gotify.test/message?token=test-token", ); }); it("should log error if notify fails", async () => { const service = new GotifyNotificationService(mockConfig, mockLogger); (global.fetch as any).mockResolvedValue({ ok: false, status: 401, text: () => Promise.resolve("Unauthorized"), }); await service.notify({ title: "test", message: "test" }); expect(mockLogger.error).toHaveBeenCalledWith( "Gotify notification failed", expect.objectContaining({ status: 401 }), ); }); });