import { describe, it, expect, vi, beforeEach } from "vitest"; vi.mock("node:fs", () => ({ existsSync: vi.fn(), readFileSync: vi.fn(), writeFileSync: vi.fn(), mkdirSync: vi.fn(), renameSync: vi.fn(), })); vi.mock("node:os", () => ({ homedir: () => "/home/test", })); import { getConfig, saveConfig, getAuthHeader, ensureAuth } from "./config.js"; import { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync, } from "node:fs"; const mockExistsSync = vi.mocked(existsSync); const mockReadFileSync = vi.mocked(readFileSync); const mockWriteFileSync = vi.mocked(writeFileSync); const mockMkdirSync = vi.mocked(mkdirSync); const mockRenameSync = vi.mocked(renameSync); beforeEach(() => { vi.clearAllMocks(); }); describe("getConfig", () => { it("returns default config when file does not exist", () => { mockExistsSync.mockReturnValue(false); const config = getConfig(); expect(config.apiUrl).toBe("https://api.skills-hub.ai"); }); it("reads and merges config from file", () => { mockExistsSync.mockReturnValue(true); mockReadFileSync.mockReturnValue(JSON.stringify({ apiKey: "sk_test" })); const config = getConfig(); expect(config.apiKey).toBe("sk_test"); expect(config.apiUrl).toBe("https://api.skills-hub.ai"); }); it("returns default on parse error", () => { mockExistsSync.mockReturnValue(true); mockReadFileSync.mockReturnValue("invalid json"); const config = getConfig(); expect(config.apiUrl).toBe("https://api.skills-hub.ai"); }); }); describe("saveConfig", () => { it("creates directory and writes config atomically", () => { mockExistsSync.mockReturnValue(false); saveConfig({ apiKey: "sk_new" }); expect(mockMkdirSync).toHaveBeenCalled(); expect(mockWriteFileSync).toHaveBeenCalled(); expect(mockRenameSync).toHaveBeenCalled(); }); }); describe("getAuthHeader", () => { it("returns ApiKey header when apiKey is set", () => { mockExistsSync.mockReturnValue(true); mockReadFileSync.mockReturnValue(JSON.stringify({ apiKey: "sk_test" })); expect(getAuthHeader()).toEqual({ Authorization: "ApiKey sk_test" }); }); it("returns Bearer header when accessToken is set", () => { mockExistsSync.mockReturnValue(true); mockReadFileSync.mockReturnValue(JSON.stringify({ accessToken: "tok" })); expect(getAuthHeader()).toEqual({ Authorization: "Bearer tok" }); }); it("returns empty object when no auth", () => { mockExistsSync.mockReturnValue(false); expect(getAuthHeader()).toEqual({}); }); }); describe("ensureAuth", () => { it("exits when not authenticated", () => { mockExistsSync.mockReturnValue(false); const exit = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("exit"); }); expect(() => ensureAuth()).toThrow("exit"); exit.mockRestore(); }); it("does not exit when authenticated", () => { mockExistsSync.mockReturnValue(true); mockReadFileSync.mockReturnValue(JSON.stringify({ apiKey: "sk_test" })); expect(() => ensureAuth()).not.toThrow(); }); });