Files
chimera-Public/test/server/notification-service.test.js

54 lines
3.2 KiB
JavaScript

'use strict';
const assert = require('node:assert/strict');
const test = require('node:test');
const { createNotificationService } = require('../../src/services/notification-service');
test('generic notifications are HTTPS-only, redact bearer state and send bounded JSON', async () => {
const values = new Map(); const secretsMap = new Map(); let request;
const settings = { get: (key, fallback) => values.has(key) ? values.get(key) : fallback, set: (key, value) => values.set(key, value) };
const secrets = { has: key => secretsMap.has(key), get: key => secretsMap.get(key) || '', set: (key, value) => value ? secretsMap.set(key, value) : secretsMap.delete(key) };
const service = createNotificationService({ settings, secrets, fetchImpl: async (url, options) => { request = { url, options }; return { ok: true }; } });
assert.throws(() => service.save({ enabled: true, endpoint: 'http://notify.local' }), /HTTPS/);
const status = service.save({ enabled: true, endpoint: 'https://notify.example.test/chimera', bearerToken: 'secret-token' });
assert.equal(status.bearerConfigured, true);
assert.equal(Object.prototype.hasOwnProperty.call(status, 'bearerToken'), false);
await service.test();
assert.equal(request.options.headers.Authorization, 'Bearer secret-token');
assert.equal(JSON.parse(request.options.body).schema, 1);
});
test('invalid notification changes are atomic and reject loopback variants', () => {
const values = new Map();
const service = createNotificationService({
settings: { get: (key, fallback) => values.has(key) ? values.get(key) : fallback, set: (key, value) => values.set(key, value) },
secrets: { has: () => false, get: () => '', set: () => {} },
});
assert.throws(() => service.save({ enabled: true }), /Configureer/);
assert.equal(values.has('notifications.generic'), false);
assert.throws(() => service.save({ endpoint: 'https://[::1]/hook' }), /loopbackhost/);
});
test('event notification rules are opt-in, deduplicated and previewable', async () => {
const values = new Map(); const secretsMap = new Map(); let calls = 0;
const settings = { get: (key, fallback) => values.has(key) ? values.get(key) : fallback, set: (key, value) => values.set(key, value) };
const secrets = { has: key => secretsMap.has(key), get: key => secretsMap.get(key) || '', set: (key, value) => value ? secretsMap.set(key, value) : secretsMap.delete(key) };
const service = createNotificationService({
settings,
secrets,
fetchImpl: async () => { calls += 1; return { ok: true }; },
});
service.save({
enabled: true,
endpoint: 'https://notify.example.test/chimera',
rules: ['game-update-available'],
cooldownMinutes: 60,
});
assert.equal((await service.emit('task-failure', { title: 'ignored' })).reason, 'rule-disabled');
assert.equal((await service.emit('game-update-available', { title: 'Update found', message: 'CUSA00001' })).sent, true);
assert.equal((await service.emit('game-update-available', { title: 'Update found', message: 'CUSA00001' })).reason, 'cooldown');
assert.equal(calls, 1);
assert.equal(service.preview('game-update-available').dryRun, true);
assert.throws(() => service.preview('not-a-rule'), /Onbekende/);
});