configs/server-dockers/jellyfin-news/index_test.js
server-dockers/jellyfin-news/index_test.jsRaw
1// Run with node --test index_test.js; no browser dependencies are required.
2const { test } = require('node:test');
3const assert = require('node:assert/strict');
4const fs = require('node:fs');
5const vm = require('node:vm');
6
7// Exercise the page's actual handlers against a minimal DOM and fetch stub.
8function page() {
9 const ids = ['period', 'week-controls', 'month-controls', 'week-offset', 'month-offset', 'added', 'watched', 'copy', 'output', 'status'];
10 const elements = Object.fromEntries(ids.map(id => [id, {
11 value: id === 'period' ? 'current-week' : '-1',
12 events: {}, valid: true,
13 addEventListener(event, handler) { this.events[event] = handler; },
14 reportValidity() { return this.valid; },
15 }]));
16 const requests = [];
17 const script = fs.readFileSync(`${__dirname}/index.html`, 'utf8').split('<script>')[1].split('</script>')[0];
18 vm.runInNewContext(script, {
19 URLSearchParams,
20 document: {
21 querySelector: selector => elements[selector.slice(1)],
22 querySelectorAll: selector => selector === 'input'
23 ? [elements['week-offset'], elements['month-offset']] : Object.values(elements),
24 },
25 fetch: async url => { requests.push(url); return { ok: true, text: async () => 'recap' }; },
26 });
27 return { elements, requests };
28}
29
30test('period selection fetches nothing and watched can run first for every period', () => {
31 for (const period of ['current-week', 'week', 'month']) {
32 const { elements, requests } = page();
33 elements.output.value = 'old recap';
34 elements.period.value = period;
35 elements.period.events.change();
36 assert.deepEqual(requests, []);
37 assert.equal(elements.output.value, '');
38 assert.equal(elements['week-controls'].hidden, period !== 'week');
39 assert.equal(elements['month-controls'].hidden, period !== 'month');
40 elements.watched.events.click();
41 const url = new URL(requests[0], 'http://localhost');
42 assert.equal(url.pathname, '/api/watched');
43 assert.equal(url.searchParams.get('period'), period);
44 assert.equal(url.searchParams.get('offset'), period === 'current-week' ? null : '-1');
45 }
46});
47
48test('both report actions use the explicit period and edited offset', () => {
49 for (const period of ['current-week', 'week', 'month']) {
50 for (const action of ['added', 'watched']) {
51 const { elements, requests } = page();
52 elements.period.value = period;
53 elements.period.events.change();
54 if (period !== 'current-week') {
55 elements[`${period}-offset`].value = '-3';
56 elements[`${period}-offset`].events.input();
57 }
58 assert.equal(requests.length, 0);
59 elements[action].events.click();
60 const url = new URL(requests[0], 'http://localhost');
61 assert.equal(url.pathname, action === 'added' ? `/api/${period}` : '/api/watched');
62 assert.equal(url.searchParams.get('offset'), period === 'current-week' ? null : '-3');
63 }
64 }
65});
66
67test('invalid offsets prevent either report, but do not affect current week', () => {
68 for (const action of ['added', 'watched']) {
69 const { elements, requests } = page();
70 elements.period.value = 'week';
71 elements['week-offset'].valid = false;
72 elements[action].events.click();
73 assert.equal(requests.length, 0);
74 elements.period.value = 'current-week';
75 elements[action].events.click();
76 assert.equal(requests.length, 1);
77 }
78});