arnaucube
arnaucube/configsPublic Self-hosted repository
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});