import { mkdtempSync, readFileSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, describe, expect, it } from 'vitest' import { loadConfig } from '../src/server/config.js' const secret = 'test-secret-that-is-at-least-thirty-two-characters' const directories: string[] = [] afterEach(() => { for (const directory of directories.splice(0)) { rmSync(directory, { recursive: true, force: true }) } }) describe('loadConfig', () => { it('normalizes a valid production origin', () => { expect( loadConfig({ NODE_ENV: 'production', APP_SECRET: secret, PUBLIC_ORIGIN: 'https://feedback.example.com/' }) ).toMatchObject({ nodeEnv: 'production', publicOrigin: 'https://feedback.example.com' }) }) it('requires a production HTTPS origin without paths or credentials', () => { expect(() => loadConfig({ NODE_ENV: 'production', APP_SECRET: secret }) ).toThrow() expect(() => loadConfig({ NODE_ENV: 'production', APP_SECRET: secret, PUBLIC_ORIGIN: 'http://feedback.example.com' }) ).toThrow() expect(() => loadConfig({ NODE_ENV: 'production', APP_SECRET: secret, PUBLIC_ORIGIN: 'https://feedback.example.com/admin' }) ).toThrow() }) it('accepts an explicitly configured secret without a length restriction', () => { expect(loadConfig({ APP_SECRET: 'short' }).appSecret).toBe('short') }) it('generates and reuses a secret when APP_SECRET is omitted', () => { const directory = mkdtempSync(join(tmpdir(), 'product-issue-config-')) directories.push(directory) const first = loadConfig({ DATA_DIRECTORY: directory }) const second = loadConfig({ DATA_DIRECTORY: directory }) expect(first.appSecret).toHaveLength(43) expect(second.appSecret).toBe(first.appSecret) expect(readFileSync(join(directory, '.app-secret'), 'utf8').trim()).toBe( first.appSecret ) }) it('parses initial administrator configuration', () => { expect( loadConfig({ APP_SECRET: secret, INITIAL_ADMIN_EMAIL: 'admin@example.com', INITIAL_ADMIN_PASSWORD: 'a local admin password' }).initialAdmin ).toEqual({ email: 'admin@example.com', displayName: 'Administrator', password: 'a local admin password' }) }) it('requires initial administrator email and password together', () => { expect(() => loadConfig({ APP_SECRET: secret, INITIAL_ADMIN_EMAIL: 'admin@example.com' }) ).toThrow( 'INITIAL_ADMIN_EMAIL and INITIAL_ADMIN_PASSWORD must be configured together' ) }) })