import fs from 'fs'; import { EnvironmentConfig, EnvironmentType } from '../../src/config/environment'; // Mock fs module jest.mock('fs'); describe('EnvironmentConfig', () => { let envConfig: EnvironmentConfig; let originalNodeEnv: string | undefined; let mockFs: jest.Mocked; beforeEach(() => { // Clear all mocks before each test jest.clearAllMocks(); // Store original NODE_ENV originalNodeEnv = process.env['NODE_ENV']; // Get the mocked fs module mockFs = fs as jest.Mocked; }); afterEach(() => { // Restore original NODE_ENV if (originalNodeEnv !== undefined) { process.env['NODE_ENV'] = originalNodeEnv; } else { delete process.env['NODE_ENV']; } }); describe('constructor', () => { it('should create an instance', () => { envConfig = new EnvironmentConfig(); expect(envConfig).toBeInstanceOf(EnvironmentConfig); }); }); describe('detectEnvironment - NODE_ENV based detection', () => { it('should return PRODUCTION when NODE_ENV is production', () => { process.env['NODE_ENV'] = 'production'; envConfig = new EnvironmentConfig(); expect(envConfig.getEnvironment()).toBe(EnvironmentType.PRODUCTION); expect(envConfig.isProduction()).toBe(true); expect(envConfig.isDevelopment()).toBe(false); }); it('should return PRODUCTION when NODE_ENV is PRODUCTION (uppercase)', () => { process.env['NODE_ENV'] = 'PRODUCTION'; envConfig = new EnvironmentConfig(); expect(envConfig.getEnvironment()).toBe(EnvironmentType.PRODUCTION); expect(envConfig.isProduction()).toBe(true); }); it('should return DEVELOPMENT when NODE_ENV is development', () => { process.env['NODE_ENV'] = 'development'; envConfig = new EnvironmentConfig(); expect(envConfig.getEnvironment()).toBe(EnvironmentType.DEVELOPMENT); expect(envConfig.isDevelopment()).toBe(true); expect(envConfig.isProduction()).toBe(false); }); it('should return DEVELOPMENT when NODE_ENV is DEVELOPMENT (uppercase)', () => { process.env['NODE_ENV'] = 'DEVELOPMENT'; envConfig = new EnvironmentConfig(); expect(envConfig.getEnvironment()).toBe(EnvironmentType.DEVELOPMENT); expect(envConfig.isDevelopment()).toBe(true); }); }); describe('detectEnvironment - workspace based detection', () => { beforeEach(() => { // Clear NODE_ENV to test workspace detection delete process.env['NODE_ENV']; }); it('should return DEVELOPMENT when workspaces field exists in package.json', () => { // Mock existsSync to return true for package.json mockFs.existsSync.mockReturnValue(true); // Mock readFileSync to return package.json with workspaces mockFs.readFileSync.mockReturnValue(JSON.stringify({ name: 'test-project', workspaces: ['packages/*'] })); envConfig = new EnvironmentConfig(); expect(envConfig.getEnvironment()).toBe(EnvironmentType.DEVELOPMENT); expect(envConfig.isDevelopment()).toBe(true); }); it('should return PRODUCTION when package.json has no workspaces field', () => { // Mock existsSync to return true for package.json mockFs.existsSync.mockReturnValue(true); // Mock readFileSync to return package.json without workspaces mockFs.readFileSync.mockReturnValue(JSON.stringify({ name: 'test-project', version: '1.0.0' })); envConfig = new EnvironmentConfig(); expect(envConfig.getEnvironment()).toBe(EnvironmentType.PRODUCTION); expect(envConfig.isProduction()).toBe(true); }); it('should return PRODUCTION when package.json is not found', () => { // Mock existsSync to return false (no package.json found) mockFs.existsSync.mockReturnValue(false); envConfig = new EnvironmentConfig(); expect(envConfig.getEnvironment()).toBe(EnvironmentType.PRODUCTION); expect(envConfig.isProduction()).toBe(true); }); it('should return PRODUCTION when package.json is invalid JSON', () => { // Mock existsSync to return true for package.json mockFs.existsSync.mockReturnValue(true); // Mock readFileSync to return invalid JSON mockFs.readFileSync.mockReturnValue('{ invalid json'); envConfig = new EnvironmentConfig(); expect(envConfig.getEnvironment()).toBe(EnvironmentType.PRODUCTION); expect(envConfig.isProduction()).toBe(true); }); it('should return PRODUCTION when file system error occurs', () => { // Mock existsSync to throw an error mockFs.existsSync.mockImplementation(() => { throw new Error('File system error'); }); envConfig = new EnvironmentConfig(); expect(envConfig.getEnvironment()).toBe(EnvironmentType.PRODUCTION); expect(envConfig.isProduction()).toBe(true); }); }); describe('getEnvironment', () => { it('should return the detected environment', () => { process.env['NODE_ENV'] = 'production'; envConfig = new EnvironmentConfig(); expect(envConfig.getEnvironment()).toBe(EnvironmentType.PRODUCTION); }); it('should return the same environment on multiple calls', () => { process.env['NODE_ENV'] = 'development'; envConfig = new EnvironmentConfig(); const env1 = envConfig.getEnvironment(); const env2 = envConfig.getEnvironment(); expect(env1).toBe(env2); expect(env1).toBe(EnvironmentType.DEVELOPMENT); }); }); describe('isDevelopment', () => { it('should return true when in development environment', () => { process.env['NODE_ENV'] = 'development'; envConfig = new EnvironmentConfig(); expect(envConfig.isDevelopment()).toBe(true); }); it('should return false when in production environment', () => { process.env['NODE_ENV'] = 'production'; envConfig = new EnvironmentConfig(); expect(envConfig.isDevelopment()).toBe(false); }); }); describe('isProduction', () => { it('should return true when in production environment', () => { process.env['NODE_ENV'] = 'production'; envConfig = new EnvironmentConfig(); expect(envConfig.isProduction()).toBe(true); }); it('should return false when in development environment', () => { process.env['NODE_ENV'] = 'development'; envConfig = new EnvironmentConfig(); expect(envConfig.isProduction()).toBe(false); }); }); describe('findProjectRoot', () => { it('should traverse up directory tree to find package.json', () => { delete process.env['NODE_ENV']; mockFs.existsSync.mockReturnValue(true); mockFs.readFileSync.mockReturnValue(JSON.stringify({ name: 'test-project', workspaces: ['packages/*'] }) as any); envConfig = new EnvironmentConfig(); expect(envConfig.isDevelopment()).toBe(true); }); it('should stop at filesystem root if package.json not found', () => { delete process.env['NODE_ENV']; // Mock existsSync to always return false mockFs.existsSync.mockReturnValue(false); envConfig = new EnvironmentConfig(); // Should default to production when root is reached expect(envConfig.isProduction()).toBe(true); }); }); describe('edge cases', () => { it('should handle NODE_ENV with mixed case', () => { process.env['NODE_ENV'] = 'PrOdUcTiOn'; envConfig = new EnvironmentConfig(); expect(envConfig.getEnvironment()).toBe(EnvironmentType.PRODUCTION); }); it('should handle empty NODE_ENV', () => { process.env['NODE_ENV'] = ''; // Mock for workspace detection mockFs.existsSync.mockReturnValue(false); envConfig = new EnvironmentConfig(); // Should fall back to workspace detection or default to production expect(envConfig.getEnvironment()).toBeDefined(); }); it('should handle workspaces as empty array', () => { delete process.env['NODE_ENV']; mockFs.existsSync.mockReturnValue(true); mockFs.readFileSync.mockReturnValue(JSON.stringify({ name: 'test-project', workspaces: [] }) as any); envConfig = new EnvironmentConfig(); // Empty workspaces array should still count as workspaces present expect(envConfig.isDevelopment()).toBe(true); }); it('should handle workspaces as object', () => { delete process.env['NODE_ENV']; mockFs.existsSync.mockReturnValue(true); mockFs.readFileSync.mockReturnValue(JSON.stringify({ name: 'test-project', workspaces: { packages: ['packages/*'] } }) as any); envConfig = new EnvironmentConfig(); // Workspaces as object should still be detected as development expect(envConfig.isDevelopment()).toBe(true); }); }); });