69 lines
3.1 KiB
JavaScript
69 lines
3.1 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const { collectContentReferences, replaceContentReferences } = require('../src/data/content-references');
|
|
|
|
test('content reference extraction indexes typed sources, media paths, and fonts by owner region', () => {
|
|
const references = collectContentReferences('template', 42, {
|
|
brand: {
|
|
type: 'html',
|
|
value: '<img src="https://signage.example/media/uploads/brand.png"><span style="font-family: \'Acme Display\', sans-serif">Brand</span>',
|
|
font_family: 'Acme Display'
|
|
},
|
|
agenda: { type: 'timetable', timetable_group_id: 7 },
|
|
feed: { type: 'rss', feed_id: '8' },
|
|
forecast: { type: 'weather', weather_location_id: 9, weather_icon_set_id: 'night' },
|
|
api: { type: 'api', source_id: 10 }
|
|
});
|
|
const values = references.map(reference => [reference.owner_key, reference.reference_type, reference.reference_value]);
|
|
|
|
assert.deepEqual(values, [
|
|
['brand', 'media', '/media/uploads/brand.png'],
|
|
['brand', 'font-family', 'acme display'],
|
|
['agenda', 'timetable-group', '7'],
|
|
['feed', 'rss-feed', '8'],
|
|
['forecast', 'weather-location', '9'],
|
|
['forecast', 'weather-icon-set', 'night'],
|
|
['api', 'api-request', '10']
|
|
]);
|
|
assert.ok(references.every(reference => reference.owner_type === 'template' && reference.owner_id === 42 && Buffer.isBuffer(reference.reference_hash)));
|
|
});
|
|
|
|
test('content reference extraction deduplicates repeated references within a region', () => {
|
|
const references = collectContentReferences('slide', 12, {
|
|
hero: { value: '/media/uploads/a.png', secondary: '/media/uploads/a.png', source_id: 4, copy: { source_id: 4 } }
|
|
});
|
|
assert.deepEqual(references.map(reference => [reference.reference_type, reference.reference_value]), [
|
|
['media', '/media/uploads/a.png'],
|
|
['api-request', '4']
|
|
]);
|
|
});
|
|
|
|
test('content reference replacement preserves unchanged rows and only deletes or inserts the delta', async () => {
|
|
const calls = [];
|
|
const connection = {
|
|
async query(sql, params) {
|
|
calls.push([sql, params]);
|
|
if (sql.startsWith('SELECT id, owner_key')) {
|
|
return [[
|
|
{ id: 101, owner_key: 'hero', reference_type: 'media', reference_value: '/media/uploads/keep.png' },
|
|
{ id: 102, owner_key: 'api', reference_type: 'api-request', reference_value: '4' },
|
|
{ id: 103, owner_key: 'old', reference_type: 'font-family', reference_value: 'arial' }
|
|
]];
|
|
}
|
|
return [{}];
|
|
}
|
|
};
|
|
|
|
await replaceContentReferences(connection, 'slide', 22, {
|
|
hero: { value: '/media/uploads/keep.png' },
|
|
api: { source_id: 5 },
|
|
feed: { feed_id: 8 }
|
|
});
|
|
|
|
const deletion = calls.find(([sql]) => sql.startsWith('DELETE FROM c_content_references'));
|
|
assert.deepEqual(deletion[1], ['slide', 22, [102, 103]]);
|
|
const insertion = calls.find(([sql]) => sql.startsWith('INSERT IGNORE INTO c_content_references'));
|
|
assert.equal(insertion[1][0].length, 2);
|
|
assert.deepEqual(insertion[1][0].map(row => [row[3], row[4]]), [['api-request', '5'], ['rss-feed', '8']]);
|
|
assert.ok(!calls.some(([sql]) => sql === 'DELETE FROM c_content_references WHERE owner_type = ? AND owner_id = ?'));
|
|
}); |