Files
basket_utils/server/config.test.js
T

70 lines
3.4 KiB
JavaScript

import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { afterEach, describe, expect, it } from 'vitest';
import { loadConfig } from './config.js';
const temporaryRoots = [];
function validConfig(overrides = {}) {
return {
mongodb: { uri: 'mongodb://172.16.0.7:27017', db: 'basket_utils' },
server: { host: '0.0.0.0', port: 3000, mode: 'development', allowedOrigins: ['http://localhost:5173'], secureCookie: false },
bootstrap: { password: '' },
qa: { db: 'basket_utils_qa', password: '' },
...overrides,
};
}
async function writeConfig(source) {
const root = await mkdtemp(path.join(os.tmpdir(), 'basket-utils-config-')); temporaryRoots.push(root);
await writeFile(path.join(root, '.config.json'), source); return root;
}
afterEach(async () => {
await Promise.all(temporaryRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
});
describe('JSON configuration', () => {
it('loads relative to the project root and accepts a UTF-8 BOM', async () => {
const root = await writeConfig(`\uFEFF${JSON.stringify(validConfig())}`);
const config = await loadConfig({ projectRoot: root });
expect(config.mongodb.db).toBe('basket_utils');
expect(config.server.port).toBe(3000);
});
it('reports missing and malformed files without exposing source values', async () => {
const missingRoot = await mkdtemp(path.join(os.tmpdir(), 'basket-utils-config-')); temporaryRoots.push(missingRoot);
await expect(loadConfig({ projectRoot: missingRoot })).rejects.toThrow(/not found.*\.config\.json\.sample/i);
const secret = 'config-only-secret'; const malformedRoot = await writeConfig(`{"bootstrap":{"password":"${secret}"},`);
await expect(loadConfig({ projectRoot: malformedRoot })).rejects.toThrow(/Invalid JSON.*check its JSON syntax/i);
await expect(loadConfig({ projectRoot: malformedRoot })).rejects.not.toThrow(secret);
});
it('rejects invalid port types with a field-specific message', async () => {
const root = await writeConfig(JSON.stringify(validConfig({ server: { ...validConfig().server, port: '3000' } })));
await expect(loadConfig({ projectRoot: root })).rejects.toThrow(/server\.port.*integer/i);
});
it('forces secure cookies and removes private HTTP origins in production', async () => {
const root = await writeConfig(JSON.stringify(validConfig({ server: {
...validConfig().server,
mode: 'production',
secureCookie: false,
allowedOrigins: ['http://localhost:5173', 'http://192.168.5.10:5173', 'https://coach.example.com'],
} })));
const config = await loadConfig({ projectRoot: root });
expect(config.server.secureCookie).toBe(true);
expect(config.server.allowedOrigins).toEqual(['https://coach.example.com']);
});
it('keeps the sample schema and empty sample passwords', async () => {
const sample = JSON.parse(await readFile(path.resolve(import.meta.dirname, '..', '.config.json.sample'), 'utf8'));
expect(sample.mongodb).toEqual({ uri: 'mongodb://172.16.0.7:27017', db: 'basket_utils' });
expect(sample.server).toMatchObject({ host: '0.0.0.0', port: 3000, mode: 'development', secureCookie: false });
expect(sample.server.allowedOrigins).toEqual(['http://localhost:5173', 'http://127.0.0.1:5173', 'http://192.168.5.10:5173']);
expect(sample.bootstrap.password).toBe('');
expect(sample.qa).toEqual({ db: 'basket_utils_qa', password: '' });
});
});