Release v2.15.4
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 1m50s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 34s

This commit is contained in:
lzstealth committed 2026-10-17 16:01:00 +01:00
1 parent 64aeb1b47e
commit 05c9341b08
25 files changed
+595 -31

No files matched your search

+85
View File
@@ -83,6 +83,91 @@ function loadScheduleModule(overrides) {
return registry.get('timetable');
}
test('timetable date ranges agree in preview and player, before limiting items', () => {
const previewModule = loadScheduleModule();
const groups = [{ id: 1, entries: [
{ id: 1, title: 'Early', start_datetime: '2099-08-20T09:00:00Z' },
{ id: 2, title: 'Middle', start_datetime: '2099-08-20T10:00:00Z' },
{ id: 3, title: 'Late', start_datetime: '2099-08-20T11:00:00Z' }
] }];
let playerModule;
const sandbox = {
window: {
pulsePlayerRegionTypes: { register(type, module) { playerModule = module; } },
placeholderUtils: {
resolvePlaceholderExpression(entry, expression) { return entry[expression]; },
formatPlaceholderValue(value) { return value; }
}
},
initialData: { timetableGroups: groups },
escapeHtml: String,
sanitizeRichText: String
};
vm.runInNewContext(fs.readFileSync(require.resolve('../src/player/regions/timetable.js'), 'utf8'), sandbox);
const cases = [
[{}, ['Early', 'Middle', 'Late']],
[{ date_filter: 'all', date_from: '2099-08-20T10:00:00Z' }, ['Early', 'Middle', 'Late']],
[{ date_filter: 'between', date_from: '2099-08-20T10:00:00Z' }, ['Middle', 'Late']],
[{ date_filter: 'between', date_to: '2099-08-20T10:00:00Z' }, ['Early', 'Middle']],
[{ date_filter: 'between', date_from: '2099-08-20T12:00:00+02:00', date_to: '2099-08-20T10:00:00Z' }, ['Middle']],
[{ date_filter: 'between', date_from: '2099-08-20T10:00:00Z', max_items: 1 }, ['Middle']],
[{ date_filter: 'between', date_from: '2099-08-21T00:00:00Z' }, []],
[{ date_filter: 'after', date_from: '2099-08-20T10:00:00Z', date_to: '2099-08-20T09:00:00Z' }, ['Middle', 'Late']],
[{ date_filter: 'before', date_to: '2099-08-20T10:00:00Z', date_from: '2099-08-20T11:00:00Z' }, ['Early', 'Middle']]
];
for (const [range, titles] of cases) {
const config = { value: '{{title}}', timetable_group_id: 1, display_mode: 'both', max_items: 5, ...range };
const region = { id: 47, baseStyle: '' };
const preview = previewModule.renderPreview(region, config, { timetableGroups: groups });
const player = playerModule.renderRegion(region, config);
for (const title of ['Early', 'Middle', 'Late']) {
assert.equal(preview.includes(title), titles.includes(title), 'preview ' + JSON.stringify(range));
assert.equal(player.includes(title), titles.includes(title), 'player ' + JSON.stringify(range));
}
}
groups[0].entries = [{ id: 4, title: 'Live', start_datetime: new Date(Date.now() - 60000).toISOString(), end_datetime: new Date(Date.now() + 60000).toISOString() }];
const config = { value: '{{title}}', timetable_group_id: 1, display_mode: 'upcoming', date_filter: 'between', date_from: '2099-08-20T00:00:00Z' };
assert.doesNotMatch(previewModule.renderPreview({}, config, { timetableGroups: groups }), /Live/);
assert.doesNotMatch(playerModule.renderRegion({}, config), /Live/);
});
test('timetable date controls default to all and pass unsaved date ranges to preview', () => {
const module = loadScheduleModule();
const region = { id: 47, region_key: 'timetable', label: 'Timetable' };
const html = module.renderEditorCard({ region, current: {}, timetableGroups: [] });
assert.match(html, /<option value="all" selected>All<\/option>/);
assert.match(html, /data-timetable-date-range hidden/);
assert.match(html, /data-timetable-date="date_from"[^>]* disabled/);
const saved = { date_filter: 'between', date_from: '2099-08-20T10:00:00.000Z', date_to: '' };
const enabled = module.renderEditorCard({ region, current: saved, timetableGroups: [] });
assert.match(enabled, /<option value="between" selected>Between Dates<\/option>/);
assert.doesNotMatch(enabled, /data-timetable-date-range hidden/);
assert.doesNotMatch(enabled, /data-timetable-date="date_from"[^>]* disabled/);
const config = module.getCurrentConfig(region, { timetable: saved });
assert.equal(config.date_from, saved.date_from);
const fields = {
'[name="region_date_filter_47"]': { value: 'between' },
'[name="region_date_from_47"]': { value: '' },
'[name="region_date_to_47"]': { value: '2099-08-21T10:00:00.000Z' }
};
const context = module.buildPreviewRenderContext(region, { querySelector(selector) { return fields[selector] || null; } }, { timetable: saved }, []);
assert.equal(context.date_filter, 'between');
assert.equal(context.date_from, '');
assert.equal(context.date_to, fields['[name="region_date_to_47"]'].value);
assert.doesNotMatch(html, /Use the selected group and display mode/);
for (const mode of ['before', 'after']) {
const current = { ...saved, date_filter: mode };
const markup = module.renderEditorCard({ region, current, timetableGroups: [] });
assert.match(markup, new RegExp('<option value="' + mode + '" selected>'));
assert.equal(module.getCurrentConfig(region, { timetable: current }).date_filter, mode);
const activeField = mode === 'after' ? 'date_from' : 'date_to';
const inactiveField = mode === 'after' ? 'date_to' : 'date_from';
assert.doesNotMatch(markup, new RegExp('data-timetable-date="' + activeField + '"[^>]* disabled'));
assert.match(markup, new RegExp('data-timetable-date="' + inactiveField + '"[^>]* disabled'));
}
});
test('timetable region editor lists timezone transforms in helper text', () => {
const module = loadScheduleModule();
const html = module.renderEditorCard({