Files
Nodecast/test/t26Frontend.test.js
blomios 63a5946e75 fix(live): prevent analysis crash on large catalogs (#26)
Bound synchronous live channel enrichment and tolerate minimal projection payloads so analysis and listings do not blank the UI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-06 15:13:48 +02:00

70 lines
3.3 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { JSDOM } = require('jsdom');
const root = path.resolve(__dirname, '..');
const projection = require('../public/js/services/liveChannelProjection.js');
const script = relativePath => fs.readFileSync(path.join(root, 'public', relativePath), 'utf8');
test('minimal non-enriched live projection payload maps and renders without an exception', () => {
const mapped = projection.mapResponse({
projection: { stale: false },
filters: { availableLanguages: [null, {}] },
channels: [
{
id: 'logical-news:und', logicalChannelId: 'logical-news', displayName: 'News',
standard: null, language: {}, epg: null, preferredVariant: null,
variants: [{
id: 'news-raw', sourceId: 1, name: 'News Raw', tvgId: 'news.raw',
categoryName: 'News', language: null, isHidden: false
}]
},
{
id: 'logical-sports:und', logicalChannelId: 'logical-sports', displayName: 'Sports',
language: null, variants: null,
preferredVariant: {
id: 'sports-raw', sourceId: 1, name: 'Sports Raw', tvgId: 'sports.raw',
categoryName: 'Sports', isHidden: false
}
},
{
id: 'empty', logicalChannelId: 'empty', displayName: 'Empty',
language: null, variants: null, preferredVariant: null
}
]
}, [{ id: 1, type: 'm3u', name: 'Provider' }]);
assert.equal(mapped.logicalChannels.length, 2);
assert.ok(mapped.logicalChannels.every(channel => channel.language.code === 'und'));
assert.equal(mapped.logicalChannels[0].tvgId, 'news.raw');
assert.deepEqual(mapped.availableLanguages.map(language => language.code), ['und']);
const dom = new JSDOM('<div id="result"></div>', { url: 'http://nodecast.test/', runScripts: 'outside-only' });
const { window } = dom;
window.eval(script('js/icons.js'));
window.eval(script('js/services/channelLanguageDetection.js'));
window.eval(script('js/services/channelLanguageFusion.js'));
window.eval(script('js/services/channelVariantGrouping.js'));
window.eval(`${script('js/components/ChannelList.js')}\nwindow.ChannelList = ChannelList;`);
window.app = { epgGuide: { getCurrentProgram: () => null, loadError: null } };
const channelList = Object.create(window.ChannelList.prototype);
channelList.expandedVariants = new Set();
channelList.sources = [{ id: 1, type: 'm3u', name: 'Provider' }];
channelList.showHidden = false;
channelList.isFavorite = () => false;
channelList.isHidden = () => false;
const result = window.document.getElementById('result');
assert.doesNotThrow(() => {
result.innerHTML = mapped.logicalChannels.map(channel =>
channelList.renderLogicalChannel(channel, 'render-id', 'News')
).join('');
});
assert.equal(result.querySelectorAll('.logical-channel').length, 2);
assert.equal(result.querySelector('.channel-language-badge').getAttribute('aria-label'), 'Unknown language');
assert.match(result.textContent, /No program information/);
dom.window.close();
});