diff --git a/src/cli.ts b/src/cli.ts index 716a9ed..dbaf521 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -56,7 +56,7 @@ export const buildCmd = (): Command => { try { console.log("🚀 Initializing configuration...\n"); - const existingConfig = await loadConfig(); + const existingConfig = await loadConfig(options.force); if (existingConfig.apiKey && !options.force) { console.log("⚠️ Configuration already exists."); @@ -259,7 +259,7 @@ export const buildCmd = (): Command => { .option( "-l, --host-network", "Use host network (default: false). If set you can use localhost directly", - false, + false ) .action(startPrivateLocationWorker); @@ -316,10 +316,10 @@ export const buildCmd = (): Command => { .addOption(testTargetIdOption) .action(async (options, command) => { const resolvedTestTargetId = await resolveTestTargetId( - options.testTargetId, + options.testTargetId ); command.setOptionValue("testTargetId", resolvedTestTargetId); - void listTestCases({...options, status: "ENABLED"}); + void listTestCases({ ...options, status: "ENABLED" }); }); return program; diff --git a/src/config.ts b/src/config.ts index cace405..46703bc 100644 --- a/src/config.ts +++ b/src/config.ts @@ -12,14 +12,20 @@ export function getConfigPath(): string { return path.join(process.cwd(), OCTOMIND_CONFIG_FILE); } -export async function loadConfig(): Promise { +export async function loadConfig(force?: boolean): Promise { try { const configPath = getConfigPath(); const data = await fs.readFile(configPath, "utf8"); return JSON.parse(data); } catch (error) { - console.error("❌ Error parsing configuration:", (error as Error).message); - + // only exit on overwrite attempt + if (force) { + console.error( + "❌ Error parsing configuration:", + (error as Error).message + ); + process.exit(1); + } return {}; } } diff --git a/tests/cli.spec.ts b/tests/cli.spec.ts index ada8648..9d7ba32 100644 --- a/tests/cli.spec.ts +++ b/tests/cli.spec.ts @@ -11,6 +11,9 @@ jest.mock("../src/config", () => ({ loadConfig: jest.fn(), })); +const originalConsoleLog = console.log; +const originalConsoleError = console.error; + beforeAll(() => { buildCmd(); program.exitOverride((err) => { @@ -18,6 +21,16 @@ beforeAll(() => { }); }); +beforeEach(() => { + console.log = jest.fn(); + console.error = jest.fn(); +}); + +afterEach(() => { + console.log = originalConsoleLog; + console.error = originalConsoleError; +}); + describe("CLI Commands parsing options", () => { const stdArgs = [ "node", diff --git a/tests/config.spec.ts b/tests/config.spec.ts index 3e221e2..33a793a 100644 --- a/tests/config.spec.ts +++ b/tests/config.spec.ts @@ -34,7 +34,7 @@ describe("Config", () => { ); }); - it("should error when config file does not exist", async () => { + it("should return empty config when config file does not exist", async () => { const fileNotFoundError = new Error( "ENOENT: no such file or directory", ) as Error & { code?: string }; @@ -42,9 +42,34 @@ describe("Config", () => { mockedFs.readFile.mockRejectedValue(fileNotFoundError); - await loadConfig(); + const result = await loadConfig(); + + expect(result).toEqual({}); + expect(console.error).not.toHaveBeenCalled(); + }); + it("should error and exit when config file does not exist and force is true", async () => { + const fileNotFoundError = new Error( + "ENOENT: no such file or directory", + ) as Error & { code?: string }; + fileNotFoundError.code = "ENOENT"; + + mockedFs.readFile.mockRejectedValue(fileNotFoundError); + + const mockExit = jest + .spyOn(process, "exit") + .mockImplementation((code?: string | number | null | undefined) => { + throw new Error(`Process exit with code: ${code}`); + }); + + const MOCK_FORCE_OPTION = true; + await expect(loadConfig(MOCK_FORCE_OPTION)).rejects.toThrow( + "Process exit with code: 1", + ); expect(console.error).toHaveBeenCalled(); + expect(mockExit).toHaveBeenCalledWith(1); + + mockExit.mockRestore(); }); }); });