141 lines
4.5 KiB
TypeScript
141 lines
4.5 KiB
TypeScript
import { describe, expect, it, vi, beforeEach } from "vitest";
|
|
|
|
import {
|
|
isCopilotCliInstalled,
|
|
readCopilotAuthStatus,
|
|
readCopilotAuthStatusCached,
|
|
resetCopilotCredentialCacheForTest,
|
|
} from "./copilot-credentials.js";
|
|
|
|
describe("copilot-credentials", () => {
|
|
beforeEach(() => {
|
|
resetCopilotCredentialCacheForTest();
|
|
});
|
|
|
|
describe("isCopilotCliInstalled", () => {
|
|
it("returns true when copilot --version succeeds", () => {
|
|
const execSync = vi.fn().mockReturnValue("0.0.1");
|
|
const result = isCopilotCliInstalled({ execSync });
|
|
expect(result).toBe(true);
|
|
expect(execSync).toHaveBeenCalledWith("copilot --version", expect.any(Object));
|
|
});
|
|
|
|
it("returns false when copilot --version fails", () => {
|
|
const execSync = vi.fn().mockImplementation(() => {
|
|
throw new Error("ENOENT: not found");
|
|
});
|
|
const result = isCopilotCliInstalled({ execSync });
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it("uses custom cliPath when provided", () => {
|
|
const execSync = vi.fn().mockReturnValue("0.0.1");
|
|
isCopilotCliInstalled({ cliPath: "/usr/local/bin/copilot", execSync });
|
|
expect(execSync).toHaveBeenCalledWith("/usr/local/bin/copilot --version", expect.any(Object));
|
|
});
|
|
});
|
|
|
|
describe("readCopilotAuthStatus", () => {
|
|
it("returns authenticated status when CLI reports authenticated", () => {
|
|
const execSync = vi.fn().mockReturnValue(
|
|
JSON.stringify({
|
|
isAuthenticated: true,
|
|
user: {
|
|
login: "testuser",
|
|
avatarUrl: "https://example.com/avatar.png",
|
|
},
|
|
}),
|
|
);
|
|
const result = readCopilotAuthStatus({ execSync });
|
|
expect(result).toEqual({
|
|
authenticated: true,
|
|
login: "testuser",
|
|
avatarUrl: "https://example.com/avatar.png",
|
|
});
|
|
});
|
|
|
|
it("returns not authenticated when CLI reports not authenticated", () => {
|
|
const execSync = vi.fn().mockReturnValue(
|
|
JSON.stringify({
|
|
isAuthenticated: false,
|
|
}),
|
|
);
|
|
const result = readCopilotAuthStatus({ execSync });
|
|
expect(result).toEqual({ authenticated: false });
|
|
});
|
|
|
|
it("returns null when CLI is not installed", () => {
|
|
const execSync = vi.fn().mockImplementation(() => {
|
|
const error = new Error("ENOENT: not found");
|
|
throw error;
|
|
});
|
|
const result = readCopilotAuthStatus({ execSync });
|
|
expect(result).toBe(null);
|
|
});
|
|
|
|
it("returns not authenticated on stderr indicating not logged in", () => {
|
|
const execSync = vi.fn().mockImplementation(() => {
|
|
const error = new Error("Command failed") as Error & { stderr: string };
|
|
error.stderr = "You are not logged in";
|
|
throw error;
|
|
});
|
|
const result = readCopilotAuthStatus({ execSync });
|
|
expect(result).toEqual({ authenticated: false });
|
|
});
|
|
});
|
|
|
|
describe("readCopilotAuthStatusCached", () => {
|
|
it("returns cached value within TTL", () => {
|
|
const execSync = vi.fn().mockReturnValue(
|
|
JSON.stringify({
|
|
isAuthenticated: true,
|
|
user: { login: "testuser" },
|
|
}),
|
|
);
|
|
|
|
// First call populates cache
|
|
const result1 = readCopilotAuthStatusCached({ execSync, ttlMs: 60000 });
|
|
expect(result1?.authenticated).toBe(true);
|
|
expect(execSync).toHaveBeenCalledTimes(1);
|
|
|
|
// Second call should use cache
|
|
const result2 = readCopilotAuthStatusCached({ execSync, ttlMs: 60000 });
|
|
expect(result2?.authenticated).toBe(true);
|
|
expect(execSync).toHaveBeenCalledTimes(1); // Not called again
|
|
});
|
|
|
|
it("refreshes cache after TTL expires", async () => {
|
|
const execSync = vi.fn().mockReturnValue(
|
|
JSON.stringify({
|
|
isAuthenticated: true,
|
|
user: { login: "testuser" },
|
|
}),
|
|
);
|
|
|
|
// First call with very short TTL
|
|
readCopilotAuthStatusCached({ execSync, ttlMs: 1 });
|
|
expect(execSync).toHaveBeenCalledTimes(1);
|
|
|
|
// Wait for TTL to expire
|
|
await new Promise((r) => setTimeout(r, 5));
|
|
|
|
// Second call should refresh
|
|
readCopilotAuthStatusCached({ execSync, ttlMs: 1 });
|
|
expect(execSync).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it("does not cache when ttlMs is 0", () => {
|
|
const execSync = vi.fn().mockReturnValue(
|
|
JSON.stringify({
|
|
isAuthenticated: true,
|
|
user: { login: "testuser" },
|
|
}),
|
|
);
|
|
|
|
readCopilotAuthStatusCached({ execSync, ttlMs: 0 });
|
|
readCopilotAuthStatusCached({ execSync, ttlMs: 0 });
|
|
expect(execSync).toHaveBeenCalledTimes(2);
|
|
});
|
|
});
|
|
});
|