Files
2026-09-09 11:50:00 +02:00

62 lines
2.7 KiB
JavaScript

const {test} = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const source = fs.readFileSync('src/main/frontend/push-worker.js', 'utf8');
const modulePromise = import('data:text/javascript;base64,' + Buffer.from(source).toString('base64'));
const scope = 'https://werkjournal.example/';
function fixture(install) {
const events = {}, shown = [], opened = [];
const worker = {
registration: {scope, async showNotification(...args) { shown.push(args); }},
clients: {async matchAll() { return []; }, async openWindow(url) { opened.push(url); }},
addEventListener(name, handler) { events[name] = handler; }
};
install(worker);
return {worker, events, shown, opened};
}
async function fire(handler, event) {
let pending;
handler({...event, waitUntil(promise) { pending = promise; }});
await pending;
}
test('push shows the dated reminder with the journal icon and a stable daily tag', async () => {
const {installPushHandlers} = await modulePromise;
const f = fixture(installPushHandlers);
await fire(f.events.push, {data: {json: () => ({title:'ignored', body:'Record work', url:'/work?date=2026-09-09&new=true'})}});
assert.equal(f.shown.length, 1);
assert.equal(f.shown[0][0], 'Werkjournal');
assert.equal(f.shown[0][1].icon, scope + 'icons/journal.png');
assert.equal(f.shown[0][1].tag, 'work-2026-09-09');
await fire(f.events.push, {data: {json: () => { throw Error('malformed'); }}});
assert.equal(f.shown.length, 1);
});
test('unsafe or invalid destinations are rejected', async () => {
const {reminderUrl} = await modulePromise;
for (const url of ['https://evil.example/work?date=2026-09-09&new=true', '/settings',
'/work?date=2026-02-30&new=true', 'javascript:alert(1)', '/work?date=2026-09-09&new=true#other']) {
assert.equal(reminderUrl(url, scope), null);
}
assert.equal(reminderUrl('work?date=2026-09-09&new=true', scope + 'app/'), scope + 'app/work?date=2026-09-09&new=true');
});
test('notification click opens the dated form and reuses an existing app window', async () => {
const {installPushHandlers} = await modulePromise;
const f = fixture(installPushHandlers);
const url = scope + 'work?date=2026-09-09&new=true';
let closed = 0, focused = 0, navigated;
const notification = {data: {url}, close() { closed++; }};
await fire(f.events.notificationclick, {notification});
assert.deepEqual(f.opened, [url]);
f.worker.clients.matchAll = async () => [{url: scope + 'reports', async navigate(target) {
navigated = target; return {async focus() { focused++; }};
}}];
await fire(f.events.notificationclick, {notification});
assert.equal(navigated, url);
assert.equal(focused, 1);
assert.equal(closed, 2);
assert.equal(f.opened.length, 1);
});