import { afterEach, describe, expect, it, vi } from "vitest"; import { emitAlert, getEmittedAlerts, resetAlertState, } from "@/services/alert/webhook"; import { enableTestModeEnv, disableTestModeEnv } from "@/services/test/test-mode-env"; describe("alert webhook", () => { afterEach(() => { resetAlertState(); delete process.env.ALERT_WEBHOOK_URL; disableTestModeEnv(); vi.unstubAllGlobals(); }); it("records in memory when webhook url empty", async () => { enableTestModeEnv(); const sent = await emitAlert({ key: "imap.consecutive_fail", title: "IMAP 连续拉取失败", severity: "error", fields: { consecutiveFail: 3 }, }); expect(sent).toBe(true); expect(getEmittedAlerts()).toHaveLength(1); expect(getEmittedAlerts()[0].title).toMatch(/IMAP/); }); it("dedups same key within window", async () => { enableTestModeEnv(); await emitAlert({ key: "cc.auth_expired", title: "a", severity: "error" }); const second = await emitAlert({ key: "cc.auth_expired", title: "b", severity: "error", }); expect(second).toBe(false); expect(getEmittedAlerts()).toHaveLength(1); }); it("POSTs JSON when ALERT_WEBHOOK_URL is set", async () => { enableTestModeEnv(); process.env.ALERT_WEBHOOK_URL = "https://example.test/hook"; const { resetEnvCache } = await import("@/lib/env"); resetEnvCache(); const fetchMock = vi.fn().mockResolvedValue({ ok: true }); vi.stubGlobal("fetch", fetchMock); resetAlertState(); await emitAlert({ key: "cc.login_fail", title: "CC 登录失败", severity: "error", fields: { code: 401 }, }); expect(fetchMock).toHaveBeenCalledTimes(1); const [url, init] = fetchMock.mock.calls[0] as [string, RequestInit]; expect(url).toBe("https://example.test/hook"); expect(init.method).toBe("POST"); delete process.env.ALERT_WEBHOOK_URL; resetEnvCache(); }); });