import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { apiLogger } from "../../lib/frontend-logger.js"; // The formatting helpers (status/performance icons, URL sanitization) are // private, so we exercise them through the public request* methods and assert // on what gets written to the console. let logSpy: ReturnType; let errorSpy: ReturnType; let groupSpy: ReturnType; beforeEach(() => { logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); errorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); groupSpy = vi.spyOn(console, "group").mockImplementation(() => {}); vi.spyOn(console, "groupEnd").mockImplementation(() => {}); }); afterEach(() => { vi.restoreAllMocks(); }); function allLoggedText(): string { return logSpy.mock.calls .concat(errorSpy.mock.calls) .concat(groupSpy.mock.calls) .map((args) => args.join(" ")) .join("\n"); } describe("frontend logger request success", () => { it("includes the success status icon and a fast-performance icon", () => { apiLogger.requestSuccess("get", "https://x.test/api", 200, 50); const text = allLoggedText(); expect(text).toContain("✅"); // 2xx status icon expect(text).toContain("⚡"); // <100ms performance icon expect(text).toContain("200"); }); it("uses the slow-performance icon for long requests", () => { apiLogger.requestSuccess("get", "https://x.test/api", 200, 4000); expect(allLoggedText()).toContain("🐌"); }); }); describe("frontend logger error mapping", () => { it("uses a client-error icon for 4xx responses", () => { apiLogger.requestError("get", "https://x.test/api", 404, "Not Found", 30); expect(allLoggedText()).toContain("⚠️"); }); it("uses a server-error icon for 5xx responses", () => { apiLogger.requestError("get", "https://x.test/api", 500, "Boom", 30); expect(allLoggedText()).toContain("❌"); }); }); describe("frontend logger URL sanitization", () => { it("strips password/token query params from logged URLs", () => { apiLogger.requestStart("get", "https://x.test/login?password=hunter2"); const text = allLoggedText(); expect(text).not.toContain("hunter2"); }); it("keeps a normal URL intact", () => { apiLogger.requestStart("get", "https://x.test/api/hosts"); expect(allLoggedText()).toContain("x.test/api/hosts"); }); });