const test = require('node:test'); const assert = require('node:assert/strict'); const { buildSlidePayload } = require('../src/data/slides'); test('buildSlidePayload normalizes timetable region fields', async () => { const pool = { async query(sql) { if (sql.includes('FROM c_templates st')) { return [[{ id: 9, name: 'Template 9', canvas_size_id: 1, canvas_size_width: 1920, canvas_size_height: 1080 }]]; } if (sql.includes('FROM c_template_regions')) { return [[{ id: 47, template_id: 9, region_key: 'timetable', region_type: 'timetable', label: 'Timetable' }]]; } return [[]]; } }; const payload = await buildSlidePayload(pool, { body: { title: 'Timetable slide', template_id: '9', region_text_47: '

{{title}}

', region_timetable_group_id_47: '1', region_timetable_display_mode_47: 'current', region_timetable_max_items_47: '7', region_date_filter_47: 'between', region_date_from_47: '2099-08-20T12:00:00+02:00', region_date_to_47: '' }, files: [] }, null); const content = JSON.parse(payload.contentJson); assert.equal(content.timetable.type, 'timetable'); assert.equal(content.timetable.text, '

{{title}}

'); assert.equal(content.timetable.value, '

{{title}}

'); assert.equal(content.timetable.timetable_group_id, '1'); assert.equal(content.timetable.display_mode, 'current'); assert.equal(content.timetable.max_items, '7'); assert.equal(content.timetable.date_filter, 'between'); assert.equal(content.timetable.date_from, '2099-08-20T10:00:00.000Z'); assert.equal(content.timetable.date_to, ''); assert.equal(Object.prototype.hasOwnProperty.call(content.timetable, 'timetable_display_mode'), false); assert.equal(Object.prototype.hasOwnProperty.call(content.timetable, 'timetable_max_items'), false); }); test('timetable date settings persist, clear, default to all, and reject invalid ranges', async () => { const pool = { async query(sql) { if (sql.includes('FROM c_templates st')) { return [[{ id: 9, name: 'Template 9' }]]; } if (sql.includes('FROM c_template_regions')) { return [[{ id: 47, region_key: 'timetable', region_type: 'timetable' }]]; } return [[]]; } }; const existing = { content_json: JSON.stringify({ timetable: { type: 'timetable', date_filter: 'between', date_from: '2099-08-20T10:00:00.000Z', date_to: '2099-08-20T11:00:00.000Z' } }) }; async function save(fields, slide) { const payload = await buildSlidePayload(pool, { body: { title: 'Timetable', template_id: '9', ...fields }, files: [] }, slide); return JSON.parse(payload.contentJson).timetable; } assert.equal((await save({})).date_filter, 'all'); assert.equal((await save({}, existing)).date_from, '2099-08-20T10:00:00.000Z'); assert.equal((await save({ region_date_from_47: '' }, existing)).date_from, ''); const all = await save({ region_date_filter_47: 'all' }, existing); assert.equal(all.date_filter, 'all'); assert.equal(all.date_to, '2099-08-20T11:00:00.000Z'); for (const mode of ['before', 'after']) { const saved = await save({ region_date_filter_47: mode }, existing); assert.equal(saved.date_filter, mode); assert.equal(saved.date_from, '2099-08-20T10:00:00.000Z'); assert.equal(saved.date_to, '2099-08-20T11:00:00.000Z'); } assert.equal((await save({ region_date_filter_47: 'after', region_date_to_47: '2099-08-19T00:00:00Z' }, existing)).date_filter, 'after'); assert.equal((await save({ region_date_filter_47: 'before', region_date_from_47: '2099-08-21T00:00:00Z' }, existing)).date_filter, 'before'); await assert.rejects(save({ region_date_filter_47: 'before', region_date_to_47: 'invalid' }), { statusCode: 400 }); await assert.rejects(save({ region_date_filter_47: 'after', region_date_from_47: 'invalid' }), { statusCode: 400 }); await assert.rejects(save({ region_date_filter_47: 'between', region_date_from_47: 'invalid' }), { statusCode: 400 }); await assert.rejects(save({ region_date_from_47: '2099-08-21T00:00:00Z' }, existing), { statusCode: 400 }); }); test('buildSlidePayload preserves safe image markup in text regions', async () => { const pool = { async query(sql) { if (sql.includes('FROM c_templates st')) { return [[{ id: 9, name: 'Template 9', canvas_size_id: 1, canvas_size_width: 1920, canvas_size_height: 1080 }]]; } if (sql.includes('FROM c_template_regions')) { return [[{ id: 47, template_id: 9, region_key: 'body', region_type: 'text', label: 'Body' }]]; } return [[]]; } }; const payload = await buildSlidePayload(pool, { body: { title: 'Text slide', template_id: '9', region_text_47: '

Photo

' }, files: [] }, null); const content = JSON.parse(payload.contentJson); assert.equal(content.body.type, 'text'); assert.equal(content.body.value, '

Photo

'); }); test('buildSlidePayload preserves safe color spans in text regions', async () => { const pool = { async query(sql) { if (sql.includes('FROM c_templates st')) { return [[{ id: 9, name: 'Template 9', canvas_size_id: 1, canvas_size_width: 1920, canvas_size_height: 1080 }]]; } if (sql.includes('FROM c_template_regions')) { return [[{ id: 47, template_id: 9, region_key: 'body', region_type: 'text', label: 'Body' }]]; } return [[]]; } }; const payload = await buildSlidePayload(pool, { body: { title: 'Text slide', template_id: '9', region_text_47: '

Hello

' }, files: [] }, null); const content = JSON.parse(payload.contentJson); assert.equal(content.body.type, 'text'); assert.equal(content.body.value, '

Hello

'); });