screentinker/server/test/schedule-eval.test.js
ScreenTinker 2ccf3264a9
Some checks are pending
CI / Unit tests (node --test) (push) Waiting to run
CI / Android unit tests (Kotlin schedule evaluator vectors) (push) Waiting to run
CI / Boot smoke + version check (push) Waiting to run
feat(scheduling): per-item schedule blocks (#74 dayparting, #75 auto-expire)
Each playlist item can carry schedule blocks (active days, start/end
time-of-day, optional start/end dates). An item plays when the screen's
local "now" matches at least one block; an item with no blocks always
plays. #74 covers time-of-day/day-of-week windows including overnight
wrap; #75 covers inclusive date ranges (auto-expiry). Evaluation is
on-device, so dayparting and expiry work offline.

- Shared evaluator contract: shared/schedule-vectors.json (39 vectors —
  DST US+AU, overnight-wrap anchoring, timezone correctness, date
  boundaries). Canonical JS evaluator in server/lib/schedule-eval.js;
  Kotlin and Tizen ports kept in lockstep by drift guards (Tizen byte-diff
  test, Kotlin JUnit reads the shared JSON, new android-test CI job).
- All three players (web, Android, Tizen) filter by schedule against their
  own clock, idle with a "Nothing scheduled" message + 30s re-check when
  everything is filtered, and fail open on any evaluator error.
- Editor: per-item schedule modal + row badge in the playlist editor;
  client validation mirrors the server; editing marks the playlist draft.
- Part B (behaviour change): device/group schedule overrides now evaluate
  in each device's effective timezone instead of server-local time.
- Device detail shows the reported timezone + a clock-skew warning.
- i18n for en/es/fr/de/pt across all new strings (namespaced itemsched.*
  to avoid colliding with the device-schedule calendar's schedule.*).
- CHANGELOG documents the feature, the Part B change, the fail-open
  guarantee, and the scheduled-single-video re-render tradeoff.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 15:46:41 -05:00

24 lines
1.2 KiB
JavaScript

// Drives the canonical evaluator against the shared conformance vectors
// (shared/schedule-vectors.json). The same file is consumed by the Kotlin JUnit
// suite and the Tizen-JS-under-Node test, so all three implementations are held to
// one contract.
const { test } = require('node:test');
const assert = require('node:assert');
const path = require('node:path');
const fs = require('node:fs');
const { isItemActiveNow } = require('../lib/schedule-eval');
const vectorsPath = path.join(__dirname, '..', '..', 'shared', 'schedule-vectors.json');
const data = JSON.parse(fs.readFileSync(vectorsPath, 'utf8'));
test('schedule evaluator conforms to every shared vector', () => {
const failures = [];
for (const v of data.vectors) {
const got = isItemActiveNow(v.blocks, v.utc_now, v.timezone);
if (got !== v.expected) failures.push(` [${v.utc_now} ${v.timezone}] expected ${v.expected} got ${got} :: ${v.description}`);
}
if (failures.length) console.error('\n' + failures.join('\n'));
console.log(`schedule vectors: ${data.vectors.length - failures.length}/${data.vectors.length} passed`);
assert.strictEqual(failures.length, 0, `${failures.length} vector(s) failed`);
});