Files
product-issue/tests/config.test.ts
T
2026-08-24 17:59:49 +08:00

96 lines
2.7 KiB
TypeScript

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'
)
})
})