UNPKG

auto-translatr

Version:
434 lines (433 loc) 18.7 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const settingsReader_1 = require("../settingsReader"); const utils_1 = require("../utils"); // Mock console methods const originalConsoleLog = console.log; const originalConsoleWarn = console.warn; const originalConsoleError = console.error; beforeEach(() => { console.log = jest.fn(); console.warn = jest.fn(); console.error = jest.fn(); // Clear all mocks before each test jest.clearAllMocks(); jest.restoreAllMocks(); }); afterEach(() => { console.log = originalConsoleLog; console.warn = originalConsoleWarn; console.error = originalConsoleError; // Restore all mocks after each test jest.restoreAllMocks(); }); describe('settingsReader', () => { const testDir = path.join(__dirname, 'test-settings'); const settingsFileName = 'auto-translate.settings.json'; const settingsFilePath = path.join(testDir, settingsFileName); const originalEnv = process.env.OPENAI_API_KEY; beforeEach(() => { // Create test directory if (fs.existsSync(testDir)) { try { fs.rmSync(testDir, { recursive: true, force: true }); } catch (error) { // Ignore cleanup errors } } fs.mkdirSync(testDir, { recursive: true }); // Clean environment delete process.env.OPENAI_API_KEY; }); afterEach(() => { // Clean up test directory with retry logic let retries = 3; while (retries > 0) { try { if (fs.existsSync(testDir)) { fs.rmSync(testDir, { recursive: true, force: true }); } break; } catch (error) { retries--; if (retries === 0) { console.warn('Could not clean up test directory:', error); } } } // Clean up any settings files in current directory try { const currentDirSettingsFile = path.join(process.cwd(), settingsFileName); if (fs.existsSync(currentDirSettingsFile)) { fs.rmSync(currentDirSettingsFile); } } catch (error) { // Ignore cleanup errors } // Restore environment if (originalEnv) { process.env.OPENAI_API_KEY = originalEnv; } else { delete process.env.OPENAI_API_KEY; } }); describe('getDefaultSettings', () => { it('should return default settings without environment variable', () => { const settings = (0, settingsReader_1.getDefaultSettings)(); expect(settings).toEqual({ default: 'en', supported: ['en', 'fr', 'de'], openai: { model: 'gpt-4o-mini', apiKey: '' } }); }); it('should include environment variable for API key when available', () => { process.env.OPENAI_API_KEY = 'test-api-key'; const settings = (0, settingsReader_1.getDefaultSettings)(); expect(settings).toEqual({ default: 'en', supported: ['en', 'fr', 'de'], openai: { model: 'gpt-4o-mini', apiKey: 'test-api-key' } }); }); }); describe('readSettingsFile', () => { const originalCwd = process.cwd(); afterEach(() => { process.chdir(originalCwd); }); it('should return Left when settings file does not exist', () => { process.chdir(testDir); const result = (0, settingsReader_1.readSettingsFile)(); expect((0, utils_1.isLeft)(result)).toBe(true); if ((0, utils_1.isLeft)(result)) { expect(result.value.message).toBe('Settings file auto-translate.settings.json not found'); } }); it('should return Right with settings when file exists and is valid', () => { const validSettings = { default: 'es', supported: ['es', 'en', 'pt'], openai: { model: 'gpt-4', apiKey: 'file-api-key' } }; process.chdir(testDir); fs.writeFileSync(settingsFilePath, JSON.stringify(validSettings, null, 2)); const result = (0, settingsReader_1.readSettingsFile)(); expect((0, utils_1.isRight)(result)).toBe(true); if ((0, utils_1.isRight)(result)) { expect(result.value).toEqual(validSettings); } }); it('should automatically add default language to supported array when missing', () => { const settingsWithMissingDefault = { default: 'ja', supported: ['en', 'fr'], openai: { model: 'gpt-4', apiKey: 'test-key' } }; process.chdir(testDir); fs.writeFileSync(settingsFilePath, JSON.stringify(settingsWithMissingDefault, null, 2)); const result = (0, settingsReader_1.readSettingsFile)(); expect((0, utils_1.isRight)(result)).toBe(true); if ((0, utils_1.isRight)(result)) { expect(result.value.supported).toEqual(['ja', 'en', 'fr']); expect(result.value.default).toBe('ja'); } // Should log a warning expect(console.warn).toHaveBeenCalledWith("⚠️ Default language 'ja' not found in supported languages. Adding it automatically."); }); it('should merge environment API key when file has empty API key', () => { process.env.OPENAI_API_KEY = 'env-api-key'; const settingsWithoutApiKey = { default: 'fr', supported: ['fr', 'en'], openai: { model: 'gpt-3.5-turbo', apiKey: '' } }; process.chdir(testDir); fs.writeFileSync(settingsFilePath, JSON.stringify(settingsWithoutApiKey, null, 2)); const result = (0, settingsReader_1.readSettingsFile)(); expect((0, utils_1.isRight)(result)).toBe(true); if ((0, utils_1.isRight)(result)) { expect(result.value.openai.apiKey).toBe('env-api-key'); } }); it('should prefer file API key over environment when file has non-empty API key', () => { process.env.OPENAI_API_KEY = 'env-api-key'; const settingsWithApiKey = { default: 'de', supported: ['de', 'en'], openai: { model: 'gpt-4', apiKey: 'file-api-key' } }; process.chdir(testDir); fs.writeFileSync(settingsFilePath, JSON.stringify(settingsWithApiKey, null, 2)); const result = (0, settingsReader_1.readSettingsFile)(); expect((0, utils_1.isRight)(result)).toBe(true); if ((0, utils_1.isRight)(result)) { expect(result.value.openai.apiKey).toBe('file-api-key'); } }); it('should return Left when settings file has invalid JSON', () => { process.chdir(testDir); fs.writeFileSync(settingsFilePath, '{ invalid json }'); const result = (0, settingsReader_1.readSettingsFile)(); expect((0, utils_1.isLeft)(result)).toBe(true); if ((0, utils_1.isLeft)(result)) { expect(result.value).toBeInstanceOf(Error); } }); it('should return Left when default field is missing', () => { const settingsWithoutDefault = { supported: ['en', 'fr'], openai: { model: 'gpt-4', apiKey: 'test-key' } }; process.chdir(testDir); fs.writeFileSync(settingsFilePath, JSON.stringify(settingsWithoutDefault, null, 2)); const result = (0, settingsReader_1.readSettingsFile)(); expect((0, utils_1.isLeft)(result)).toBe(true); if ((0, utils_1.isLeft)(result)) { expect(result.value.message).toBe('Settings file is missing required field: default'); } }); it('should return Left when supported field is missing', () => { const settingsWithoutSupported = { default: 'en', openai: { model: 'gpt-4', apiKey: 'test-key' } }; process.chdir(testDir); fs.writeFileSync(settingsFilePath, JSON.stringify(settingsWithoutSupported, null, 2)); const result = (0, settingsReader_1.readSettingsFile)(); expect((0, utils_1.isLeft)(result)).toBe(true); if ((0, utils_1.isLeft)(result)) { expect(result.value.message).toBe('Settings file is missing required field: supported (must be a non-empty array)'); } }); it('should return Left when supported field is empty array', () => { const settingsWithEmptySupported = { default: 'en', supported: [], openai: { model: 'gpt-4', apiKey: 'test-key' } }; process.chdir(testDir); fs.writeFileSync(settingsFilePath, JSON.stringify(settingsWithEmptySupported, null, 2)); const result = (0, settingsReader_1.readSettingsFile)(); expect((0, utils_1.isLeft)(result)).toBe(true); if ((0, utils_1.isLeft)(result)) { expect(result.value.message).toBe('Settings file is missing required field: supported (must be a non-empty array)'); } }); it('should return Left when openai.model field is missing', () => { const settingsWithoutModel = { default: 'en', supported: ['en', 'fr'], openai: { apiKey: 'test-key' } }; process.chdir(testDir); fs.writeFileSync(settingsFilePath, JSON.stringify(settingsWithoutModel, null, 2)); const result = (0, settingsReader_1.readSettingsFile)(); expect((0, utils_1.isLeft)(result)).toBe(true); if ((0, utils_1.isLeft)(result)) { expect(result.value.message).toBe('Settings file is missing required field: openai.model'); } }); }); describe('createDefaultSettingsFile', () => { const originalCwd = process.cwd(); afterEach(() => { process.chdir(originalCwd); }); it('should create settings file with default values', () => { process.chdir(testDir); const result = (0, settingsReader_1.createDefaultSettingsFile)(); expect((0, utils_1.isRight)(result)).toBe(true); expect(fs.existsSync(settingsFilePath)).toBe(true); const fileContent = JSON.parse(fs.readFileSync(settingsFilePath, 'utf-8')); expect(fileContent).toEqual({ default: 'en', supported: ['en', 'fr', 'de'], openai: { model: 'gpt-4o-mini', apiKey: '' // Should be empty in file for security } }); if ((0, utils_1.isRight)(result)) { // But should return settings with environment API key if available expect(result.value.openai.apiKey).toBe(''); } }); it('should create settings file and return settings with environment API key', () => { process.env.OPENAI_API_KEY = 'test-env-key'; process.chdir(testDir); const result = (0, settingsReader_1.createDefaultSettingsFile)(); expect((0, utils_1.isRight)(result)).toBe(true); // File should still have empty API key for security const fileContent = JSON.parse(fs.readFileSync(settingsFilePath, 'utf-8')); expect(fileContent.openai.apiKey).toBe(''); // But returned settings should have environment API key if ((0, utils_1.isRight)(result)) { expect(result.value.openai.apiKey).toBe('test-env-key'); } }); it('should log creation messages', () => { process.chdir(testDir); (0, settingsReader_1.createDefaultSettingsFile)(); expect(console.log).toHaveBeenCalledWith('📄 Created auto-translate.settings.json with default settings'); expect(console.log).toHaveBeenCalledWith('💡 Please set your OpenAI API key in the file or as OPENAI_API_KEY environment variable'); }); }); describe('loadSettings', () => { const originalCwd = process.cwd(); afterEach(() => { process.chdir(originalCwd); }); it('should return existing settings when file exists', () => { const existingSettings = { default: 'ja', supported: ['ja', 'en', 'ko'], openai: { model: 'gpt-4-turbo', apiKey: 'existing-key' } }; process.chdir(testDir); fs.writeFileSync(settingsFilePath, JSON.stringify(existingSettings, null, 2)); const result = (0, settingsReader_1.loadSettings)(); expect((0, utils_1.isRight)(result)).toBe(true); if ((0, utils_1.isRight)(result)) { expect(result.value).toEqual(existingSettings); } expect(console.log).toHaveBeenCalledWith('⚙️ Loaded settings from auto-translate.settings.json'); }); it('should create default settings when file does not exist', () => { process.chdir(testDir); const result = (0, settingsReader_1.loadSettings)(); expect((0, utils_1.isRight)(result)).toBe(true); expect(fs.existsSync(settingsFilePath)).toBe(true); if ((0, utils_1.isRight)(result)) { expect(result.value).toEqual({ default: 'en', supported: ['en', 'fr', 'de'], openai: { model: 'gpt-4o-mini', apiKey: '' } }); } expect(console.log).toHaveBeenCalledWith('⚙️ Settings file auto-translate.settings.json not found, creating default settings...'); }); it('should auto-fix settings when default language is missing from supported array', () => { const settingsWithMissingDefault = { default: 'pt', supported: ['en', 'fr'], openai: { model: 'gpt-4', apiKey: 'test-key' } }; process.chdir(testDir); fs.writeFileSync(settingsFilePath, JSON.stringify(settingsWithMissingDefault, null, 2)); const result = (0, settingsReader_1.loadSettings)(); expect((0, utils_1.isRight)(result)).toBe(true); if ((0, utils_1.isRight)(result)) { expect(result.value.supported).toEqual(['pt', 'en', 'fr']); expect(result.value.default).toBe('pt'); } expect(console.warn).toHaveBeenCalledWith("⚠️ Default language 'pt' not found in supported languages. Adding it automatically."); }); }); describe('Settings type validation', () => { it('should handle settings with all required fields', () => { const validSettings = { default: 'pt', supported: ['pt', 'es', 'en'], openai: { model: 'gpt-4', apiKey: 'test-key' } }; const originalCwd = process.cwd(); process.chdir(testDir); try { fs.writeFileSync(settingsFilePath, JSON.stringify(validSettings, null, 2)); const result = (0, settingsReader_1.readSettingsFile)(); expect((0, utils_1.isRight)(result)).toBe(true); if ((0, utils_1.isRight)(result)) { expect(result.value.default).toBe('pt'); expect(result.value.supported).toContain('pt'); expect(result.value.supported).toContain('es'); expect(result.value.supported).toContain('en'); expect(result.value.openai.model).toBe('gpt-4'); expect(result.value.openai.apiKey).toBe('test-key'); } } finally { process.chdir(originalCwd); } }); }); });