Initial commit: courtlab tactical board with team management and MP4 export
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
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: '' });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user