Versie 0.2.0
This commit is contained in:
commit
e77d8fd373
495 files changed
+81026
No files matched your search
@@ -0,0 +1,169 @@
|
||||
// Generated, do not edit. sha256:72e7504c7f13026263eeeda6dcafb41dafbff8bea070ad9a3fc74a1411bd4d43
|
||||
import { describe, it, beforeEach, mock } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import { mkdtempSync, readFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { createDbHarness } from '../helpers/db-node.mjs';
|
||||
import { PREFERENCES, ENUMS, CONFIG } from '../../shared/config.js';
|
||||
|
||||
process.env.ASSETAPP_DATA_DIR = mkdtempSync(join(tmpdir(), 'assetapp-prefs-'));
|
||||
|
||||
const harness = createDbHarness({ seedPreferences: true });
|
||||
mock.module('../../server/db.js', { namedExports: harness.exports });
|
||||
|
||||
const { getPref, getSettings, setPref, updateSettings } = await import('../../server/data/preferences.js');
|
||||
|
||||
beforeEach(() => harness.recreate());
|
||||
|
||||
const ruweWaarde = (scope, key) => {
|
||||
const r = harness.exports.one(`SELECT value FROM Preference WHERE scope=? AND key=?`, [scope, key]);
|
||||
return r ? r.value : null;
|
||||
};
|
||||
|
||||
describe('setPref: validatie tegen de registry', () => {
|
||||
it('accepteert elke toegestane enum-waarde', async () => {
|
||||
for (const thema of ENUMS.THEME) {
|
||||
await setPref('app', 'theme', thema);
|
||||
assert.equal(getPref('app', 'theme'), thema);
|
||||
}
|
||||
});
|
||||
|
||||
it('weigert een enum-waarde buiten de registry', async () => {
|
||||
await assert.rejects(() => setPref('app', 'theme', 'neon'), /theme/);
|
||||
assert.equal(getPref('app', 'theme'), PREFERENCES.app.theme.initial,
|
||||
'de oude waarde blijft staan');
|
||||
});
|
||||
|
||||
it('maakt van een bool een 0 of 1', async () => {
|
||||
await setPref('app', 'blur', true);
|
||||
assert.equal(getPref('app', 'blur'), 1, 'true wordt 1');
|
||||
await setPref('app', 'blur', 0);
|
||||
assert.equal(getPref('app', 'blur'), 0);
|
||||
});
|
||||
|
||||
it('weigert een bool-waarde die geen 0 of 1 oplevert', async () => {
|
||||
await assert.rejects(() => setPref('app', 'blur', 2), /blur/);
|
||||
await assert.rejects(() => setPref('app', 'blur', 'ja'), /blur/,
|
||||
'niet-numerieke tekst levert NaN op en hoort geweigerd te worden');
|
||||
});
|
||||
|
||||
it('eist bij een int een geheel getal binnen min/max', async () => {
|
||||
const spec = PREFERENCES.app.auto_blur_min;
|
||||
await setPref('app', 'auto_blur_min', spec.min);
|
||||
assert.equal(getPref('app', 'auto_blur_min'), spec.min);
|
||||
|
||||
await assert.rejects(() => setPref('app', 'auto_blur_min', 2.5), (e) => e.key === 'settings.prefWantsInteger');
|
||||
await assert.rejects(() => setPref('app', 'auto_blur_min', spec.min - 1), (e) => e.key === 'settings.prefBelowMin');
|
||||
await assert.rejects(() => setPref('app', 'auto_blur_min', spec.max + 1), (e) => e.key === 'settings.prefAboveMax');
|
||||
});
|
||||
|
||||
it('laat een string ongemoeid', async () => {
|
||||
await setPref('app', 'last_backup_at', '2026-10-27T10:00:00Z');
|
||||
assert.equal(getPref('app', 'last_backup_at'), '2026-10-27T10:00:00Z');
|
||||
});
|
||||
|
||||
it('bewaart een scope zonder registry-regel as-is', async () => {
|
||||
const view = { sort: { key: 'occurredAt', dir: 'desc' }, group: null };
|
||||
await setPref('table.trades', 'view', view);
|
||||
assert.deepEqual(getPref('table.trades', 'view'), view);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPref: terugval en coercie', () => {
|
||||
it('geeft de initiële waarde uit de registry als er geen rij is', () => {
|
||||
harness.exports.run(`DELETE FROM Preference`);
|
||||
assert.equal(getPref('app', 'theme'), PREFERENCES.app.theme.initial);
|
||||
});
|
||||
|
||||
it('geeft de meegegeven fallback bij een onbekende sleutel', () => {
|
||||
assert.equal(getPref('bestaat', 'niet', 'terugval'), 'terugval');
|
||||
assert.equal(getPref('bestaat', 'niet'), undefined, 'zonder fallback: undefined');
|
||||
});
|
||||
|
||||
it('coërceert een opgeslagen enum-waarde die niet meer bestaat', () => {
|
||||
assert.ok(!ENUMS.ACCENT.includes('paars'));
|
||||
harness.exports.run(
|
||||
`INSERT INTO Preference (scope,key,value) VALUES ('app','accent','"paars"')
|
||||
ON CONFLICT(scope,key) DO UPDATE SET value = excluded.value`);
|
||||
assert.equal(getPref('app', 'accent'), PREFERENCES.app.accent.initial);
|
||||
});
|
||||
|
||||
it('laat een geldige enum-waarde ongemoeid', () => {
|
||||
const geldig = ENUMS.ACCENT.at(-1);
|
||||
harness.exports.run(
|
||||
`INSERT INTO Preference (scope,key,value) VALUES ('app','accent',?)
|
||||
ON CONFLICT(scope,key) DO UPDATE SET value = excluded.value`, [JSON.stringify(geldig)]);
|
||||
assert.equal(getPref('app', 'accent'), geldig);
|
||||
});
|
||||
});
|
||||
|
||||
describe('voorkeuren dragen geen geheimen meer', () => {
|
||||
it('heeft nergens in de registry nog een secret-vlag', () => {
|
||||
const metVlag = [];
|
||||
for (const [scope, keys] of Object.entries(PREFERENCES)) {
|
||||
for (const [key, spec] of Object.entries(keys)) {
|
||||
if (spec.secret) metVlag.push(`${scope}.${key}`);
|
||||
}
|
||||
}
|
||||
assert.deepEqual(metVlag, []);
|
||||
});
|
||||
|
||||
it('kent de nwc-scope niet meer', () => {
|
||||
assert.equal(PREFERENCES.nwc, undefined,
|
||||
'de NWC-URI hoort server-side te staan (data/secrets.json, sleutel nwc_<bron-id>)');
|
||||
});
|
||||
|
||||
it('slaat elke waarde op als leesbare JSON, ook onder een onbekende scope', async () => {
|
||||
await setPref('view.demo', 'stand', { sort: 'naam' });
|
||||
assert.deepEqual(JSON.parse(ruweWaarde('view.demo', 'stand')), { sort: 'naam' },
|
||||
'een vrije scope wordt as-is bewaard; er is geen versleutel-pad meer dat dit onderschept');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSettings / updateSettings', () => {
|
||||
it('levert elke app-voorkeur plus de schemaversie', () => {
|
||||
const s = getSettings();
|
||||
for (const key of Object.keys(PREFERENCES.app)) {
|
||||
if (!PREFERENCES.app[key].secret) assert.ok(key in s, `${key} ontbreekt`);
|
||||
}
|
||||
assert.equal(s.version, CONFIG.SCHEMA_VERSION);
|
||||
});
|
||||
|
||||
it('werkt meerdere instellingen in één keer bij', async () => {
|
||||
await updateSettings({ theme: 'light', locale: 'nl' });
|
||||
assert.equal(getPref('app', 'theme'), 'light');
|
||||
assert.equal(getSettings().locale, 'nl');
|
||||
});
|
||||
|
||||
it('bewaart de taal bij de installatie en niet in de portefeuille', async () => {
|
||||
await updateSettings({ locale: 'en' });
|
||||
assert.equal(ruweWaarde('app', 'locale'), null);
|
||||
const bestand = join(process.env.ASSETAPP_DATA_DIR, CONFIG.INSTALLATION.SETTINGS_FILE_NAME);
|
||||
assert.equal(JSON.parse(readFileSync(bestand, 'utf8')).locale, 'en');
|
||||
harness.recreate();
|
||||
assert.equal(getSettings().locale, 'en', 'een andere database verandert de taal niet');
|
||||
});
|
||||
|
||||
it('weigert een taal zonder catalogus', async () => {
|
||||
await updateSettings({ locale: 'nl' });
|
||||
await assert.rejects(() => updateSettings({ locale: 'xx' }), /Unknown locale/);
|
||||
assert.equal(getSettings().locale, 'nl');
|
||||
});
|
||||
|
||||
it('slaat undefined-waarden over', async () => {
|
||||
await updateSettings({ locale: 'nl' });
|
||||
await updateSettings({ theme: 'light', locale: undefined });
|
||||
assert.equal(getSettings().locale, 'nl');
|
||||
});
|
||||
|
||||
it('weigert een onbekende instelling', async () => {
|
||||
await assert.rejects(() => updateSettings({ verzonnen: 1 }), (e) => e.key === 'settings.unknownSetting');
|
||||
});
|
||||
|
||||
it('valideert nog steeds per type', async () => {
|
||||
await assert.rejects(() => updateSettings({ theme: 'neon' }), /theme/);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user