import { describe, it, expect, vi, beforeEach } from "vitest"; vi.mock("../lib/config.js", () => ({ getConfig: vi.fn(() => ({ apiUrl: "https://api.skills-hub.ai" })), getAuthHeader: vi.fn(() => ({ Authorization: "Bearer test" })), ensureAuth: vi.fn(), saveConfig: vi.fn(), })); vi.mock("../lib/api-client.js", () => ({ apiRequest: vi.fn(), })); import { orgSyncCommand } from "./org-sync.js"; import { apiRequest } from "../lib/api-client.js"; const mockApiRequest = vi.mocked(apiRequest); beforeEach(() => { vi.clearAllMocks(); // Reset Commander's stored githubOrg to prevent state leaking between tests orgSyncCommand.setOptionValue("githubOrg", undefined); }); describe("org sync", () => { it("connects GitHub org when --github-org provided", async () => { mockApiRequest.mockResolvedValue({ connected: true, membersAdded: 5 }); await orgSyncCommand.parseAsync( ["node", "sync", "acme", "--github-org", "acme-inc"], { from: "node" }, ); expect(mockApiRequest).toHaveBeenCalledWith( "/api/v1/orgs/acme/github", expect.objectContaining({ method: "POST", body: expect.stringContaining('"githubOrgSlug":"acme-inc"'), }), ); }); it("performs manual sync without --github-org", async () => { mockApiRequest.mockResolvedValue({ synced: 3, added: 1 }); await orgSyncCommand.parseAsync(["node", "sync", "acme"], { from: "node" }); expect(mockApiRequest).toHaveBeenCalledWith( "/api/v1/orgs/acme/github/sync", expect.objectContaining({ method: "POST" }), ); }); it("handles API error on connect", async () => { mockApiRequest.mockRejectedValue(new Error("Not an admin")); const exit = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("exit"); }); await expect( orgSyncCommand.parseAsync( ["node", "sync", "acme", "--github-org", "bad"], { from: "node" }, ), ).rejects.toThrow("exit"); exit.mockRestore(); }); it("handles API error on sync", async () => { mockApiRequest.mockRejectedValue(new Error("Not connected to GitHub")); const exit = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("exit"); }); await expect( orgSyncCommand.parseAsync(["node", "sync", "acme"], { from: "node" }), ).rejects.toThrow("exit"); exit.mockRestore(); }); });