joplock/tests/settingsService.test.js
2026-05-19 12:57:19 +12:00

143 lines
6.1 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const { createSettingsService, defaultAppSettings, defaultSettings, normalizeAppSettings, normalizeSettings } = require('../app/settingsService');
test('settingsService returns defaults when row is missing', async () => {
const queries = [];
const service = createSettingsService({
query: async (sql, params) => {
queries.push({ sql, params });
if (sql.includes('SELECT')) return { rows: [] };
return { rows: [] };
},
});
const settings = await service.settingsByUserId('user-1');
assert.deepEqual(settings, defaultSettings);
assert.ok(queries[0].sql.includes('CREATE TABLE IF NOT EXISTS joplock_settings'));
});
test('settingsService saves normalized settings as JSON', async () => {
const calls = [];
const service = createSettingsService({
query: async (sql, params) => {
calls.push({ sql, params });
return { rows: [] };
},
});
const saved = await service.saveSettings('user-1', {
noteFontSize: '99',
codeFontSize: '8',
noteMonospace: '1',
resumeLastNote: '1',
lastNoteId: 'note-1',
lastNoteFolderId: '__all_notes__',
dateFormat: 'DD/MM/YYYY',
datetimeFormat: 'DD/MM/YYYY HH:mm',
autoLogout: '1',
autoLogoutMinutes: '30',
});
assert.equal(saved.noteFontSize, 24);
assert.equal(saved.codeFontSize, 10);
assert.equal(saved.noteMonospace, true);
assert.equal(saved.resumeLastNote, true);
assert.equal(saved.lastNoteId, 'note-1');
assert.equal(saved.lastNoteFolderId, '__all_notes__');
assert.equal(saved.dateFormat, 'DD/MM/YYYY');
assert.equal(saved.datetimeFormat, 'DD/MM/YYYY HH:mm');
assert.equal(saved.autoLogout, true);
assert.equal(saved.autoLogoutMinutes, 30);
const insertCall = calls.find(c => c.sql.includes('INSERT INTO joplock_settings'));
assert.ok(insertCall, 'should insert into joplock_settings');
const jsonStr = insertCall.params[1];
const parsed = JSON.parse(jsonStr);
assert.equal(parsed.autoLogout, true);
assert.equal(parsed.autoLogoutMinutes, 30);
});
test('settingsService reads JSON settings from row', async () => {
const stored = { noteFontSize: 18, codeFontSize: 14, noteMonospace: true, dateFormat: 'YYYY-MM-DD', datetimeFormat: 'YYYY-MM-DD HH:mm', autoLogout: true, autoLogoutMinutes: 60 };
const service = createSettingsService({
query: async (sql) => {
if (sql.includes('SELECT')) return { rows: [{ settings: stored }] };
return { rows: [] };
},
});
const settings = await service.settingsByUserId('user-1');
assert.equal(settings.noteFontSize, 18);
assert.equal(settings.autoLogout, true);
assert.equal(settings.autoLogoutMinutes, 60);
});
test('settingsService appSettings returns defaults when row is missing', async () => {
const service = createSettingsService({
query: async (sql) => {
if (sql.includes('SELECT')) return { rows: [] };
return { rows: [] };
},
});
const settings = await service.appSettings();
assert.deepEqual(settings, defaultAppSettings);
});
test('settingsService saves normalized app settings as JSON', async () => {
const calls = [];
const service = createSettingsService({
query: async (sql, params) => {
calls.push({ sql, params });
return { rows: [] };
},
});
const saved = await service.saveAppSettings({ authRateLimitAttempts: '9999' });
assert.equal(saved.authRateLimitAttempts, 1000);
const insertCall = calls.find(c => c.sql.includes('INSERT INTO joplock_settings'));
assert.ok(insertCall, 'should insert app settings into joplock_settings');
assert.equal(insertCall.params[0], '__app__');
assert.equal(JSON.parse(insertCall.params[1]).authRateLimitAttempts, 1000);
});
test('settingsService returns defaults when table creation fails', async () => {
const service = createSettingsService({
query: async () => { throw new Error('permission denied'); },
});
const settings = await service.settingsByUserId('user-1');
assert.deepEqual(settings, defaultSettings);
});
test('normalizeSettings clamps autoLogoutMinutes', () => {
assert.equal(normalizeSettings({ autoLogoutMinutes: 0 }).autoLogoutMinutes, 1);
assert.equal(normalizeSettings({ autoLogoutMinutes: 999 }).autoLogoutMinutes, 480);
assert.equal(normalizeSettings({ autoLogoutMinutes: 'abc' }).autoLogoutMinutes, 15);
assert.equal(normalizeSettings({ autoLogoutMinutes: 120 }).autoLogoutMinutes, 120);
});
test('normalizeSettings coerces autoLogout', () => {
assert.equal(normalizeSettings({ autoLogout: '1' }).autoLogout, true);
assert.equal(normalizeSettings({ autoLogout: true }).autoLogout, true);
assert.equal(normalizeSettings({ autoLogout: 1 }).autoLogout, true);
assert.equal(normalizeSettings({ autoLogout: '0' }).autoLogout, false);
assert.equal(normalizeSettings({ autoLogout: false }).autoLogout, false);
assert.equal(normalizeSettings({ autoLogout: undefined }).autoLogout, false);
});
test('normalizeSettings coerces resumeLastNote and preserves last note state', () => {
const settings = normalizeSettings({ resumeLastNote: '1', lastNoteId: 'n1', lastNoteFolderId: '__all_notes__' });
assert.equal(settings.resumeLastNote, true);
assert.equal(settings.lastNoteId, 'n1');
assert.equal(settings.lastNoteFolderId, '__all_notes__');
assert.equal(normalizeSettings({ resumeLastNote: '0' }).resumeLastNote, false);
});
test('normalizeSettings accepts new matrix theme variants', () => {
assert.equal(normalizeSettings({ theme: 'matrix-blue' }).theme, 'matrix-blue');
assert.equal(normalizeSettings({ theme: 'matrix-purple' }).theme, 'matrix-purple');
assert.equal(normalizeSettings({ theme: 'matrix-amber' }).theme, 'matrix-amber');
assert.equal(normalizeSettings({ theme: 'matrix-orange' }).theme, 'matrix-orange');
assert.equal(normalizeSettings({ theme: 'not-a-theme' }).theme, 'matrix');
});
test('normalizeAppSettings clamps authRateLimitAttempts', () => {
assert.equal(normalizeAppSettings({ authRateLimitAttempts: 0 }).authRateLimitAttempts, 1);
assert.equal(normalizeAppSettings({ authRateLimitAttempts: 2000 }).authRateLimitAttempts, 1000);
assert.equal(normalizeAppSettings({ authRateLimitAttempts: 'abc' }).authRateLimitAttempts, 20);
assert.equal(normalizeAppSettings({ authRateLimitAttempts: 25 }).authRateLimitAttempts, 25);
});