const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const vm = require('node:vm'); const { render } = require('../src/web/public/js/shared/slide-preview-renderer'); const { buildThumbnailPreviewPayload } = require('../src/web/lib/media/slide-thumbnails'); const placeholderUtils = require('../src/web/public/js/shared/placeholder-utils'); function loadEditorTimeDateModule() { const source = fs.readFileSync(require.resolve('../src/web/public/js/regions/type/time-date.js'), 'utf8'); const modules = new Map(); const sandbox = { window: { pulseRegionTypes: { register(type, definition) { modules.set(type, definition); } }, pulseRegionUtils: { escapeHtml(value) { return String(value).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, '''); }, sanitizePreviewHtml(value) { return String(value); } }, placeholderUtils: placeholderUtils } }; vm.runInNewContext(source, sandbox, { filename: 'time-date.js' }); return modules.get('time-date'); } test('thumbnail payload passes saved region geometry and content to the popup renderer', () => { const payload = buildThumbnailPreviewPayload({ template: { canvas_size_width: 1280, canvas_size_height: 720, regions: [{ id: 14, region_key: 'clock', region_type: 'time-date', x: 20, y: 30, width: 400, height: 90, z_index: 3 }] }, content: { clock: { value: '{{hh}}:{{mm}}', timezone: 'Europe/London' } } }); assert.equal(payload.regions[0].x, 20); assert.equal(payload.regions[0].width, 400); assert.equal(payload.regions[0].content.value, '{{hh}}:{{mm}}'); assert.equal(payload.existingContent.clock.timezone, 'Europe/London'); }); test('thumbnail regions use shared region renderers and their source context', () => { const calls = []; const registry = { get(type) { return { renderPreview(...args) { calls.push({ type, args }); return '' + type + ''; } }; } }; const apiSources = [{ id: 8, responseJson: [{ name: 'Ada' }] }]; const payload = { regions: [ { id: 1, region_key: 'clock', region_type: 'time-date', x: 20, y: 12, width: 200, height: 80, z_index: 4, content: { value: '{{hh}}:{{mm}}', timezone: 'UTC' } }, { id: 2, region_key: 'donations', region_type: 'api', x: 220, y: 12, width: 300, height: 80, z_index: 2, content: { source_id: 8, value: '{{name}}' } } ], apiSources: apiSources, rssFeeds: [], weatherLocations: [], timetableGroups: [] }; const html = render(payload, registry); assert.match(html, /data-region-key="clock"[^>]*>time-date<\/span>/); assert.match(html, /data-region-key="donations"[^>]*>api<\/span>/); assert.equal(calls[0].args[3], 1); assert.equal(calls[1].args[2].sources, apiSources); }); test('thumbnail time/date uses the editor renderer to expand current-time tokens', () => { const registry = { get(type) { return type === 'time-date' ? loadEditorTimeDateModule() : null; } }; const html = render({ regions: [{ id: 4, region_key: 'clock', region_type: 'time-date', x: 0, y: 0, width: 320, height: 80, content: { value: '{{hh}}:{{mm}}', timezone: 'UTC' } }] }, registry); assert.match(html, /
]*>\d{2}:\d{2}<\/div>/); });