import 'reflect-metadata'; import { validateEnv } from './env.validation'; describe('validateEnv', () => { const valid = { DATABASE_URL: 'postgresql://user:secret@localhost:5432/db', HIBOUTIK_BASE_URL: 'https://shop.hiboutik.com/api', HIBOUTIK_USERNAME: 'user', HIBOUTIK_PASSWORD: 'secret-password', }; it('accepts a valid configuration and keeps every variable', () => { const env = { ...valid, PORT: '3000', CORS_ORIGINS: 'https://shop.example.com', TRUST_PROXY: '1', OTHER: 'x' }; expect(validateEnv(env)).toBe(env); }); it('rejects a missing required variable, naming it', () => { expect(() => validateEnv({ ...valid, HIBOUTIK_PASSWORD: undefined })).toThrow(/HIBOUTIK_PASSWORD/); }); it('rejects a non-HTTPS Hiboutik URL', () => { expect(() => validateEnv({ ...valid, HIBOUTIK_BASE_URL: 'http://shop.hiboutik.com/api' })).toThrow(/HIBOUTIK_BASE_URL/); }); it('rejects an invalid port', () => { expect(() => validateEnv({ ...valid, PORT: 'abc' })).toThrow(/PORT/); expect(() => validateEnv({ ...valid, PORT: '70000' })).toThrow(/PORT/); }); it('never puts secret values in the error message', () => { expect.assertions(2); try { validateEnv({ ...valid, HIBOUTIK_BASE_URL: 'http://insecure', DATABASE_URL: '' }); } catch (error) { expect((error as Error).message).not.toContain('secret-password'); expect((error as Error).message).not.toContain('secret'); } }); describe('in production', () => { const production = { ...valid, NODE_ENV: 'production' }; it('requires an encrypted database connection', () => { expect(() => validateEnv(production)).toThrow(/DATABASE_URL: sslmode/); expect(() => validateEnv({ ...production, DATABASE_URL: `${valid.DATABASE_URL}?sslmode=disable` })).toThrow(/DATABASE_URL/); }); it.each(['require', 'verify-ca', 'verify-full'])('accepts sslmode=%s', (mode) => { expect(() => validateEnv({ ...production, DATABASE_URL: `${valid.DATABASE_URL}?sslmode=${mode}` })).not.toThrow(); }); it('never puts the connection string in the error message', () => { expect.assertions(2); try { validateEnv(production); } catch (error) { expect((error as Error).message).toContain('DATABASE_URL'); expect((error as Error).message).not.toContain('secret'); } }); }); it('does not require TLS outside production', () => { expect(() => validateEnv({ ...valid, NODE_ENV: 'development' })).not.toThrow(); }); it('rejects an unknown NODE_ENV', () => { expect(() => validateEnv({ ...valid, NODE_ENV: 'prod' })).toThrow(/NODE_ENV/); }); });