// Tests of static/js/podcast-article.js under Node: node --test tools/tests/ // No network, no LLM: fetch and DioraAI are stubbed. import test from 'node:test'; import assert from 'node:assert/strict'; import * as pa from '../../static/js/podcast-article.js'; test('transcriptToText groups 30 seconds and splits on speaker change', () => { const segs = [ {start: 0, end: 5, speaker: '', text: 'Hallo zusammen.'}, {start: 20, end: 29, speaker: '', text: 'Heute geht es um X.'}, {start: 31, end: 40, speaker: '', text: 'Zweite Gruppe.'}, {start: 3725, end: 3730, speaker: '', text: 'Spät.'}, {start: 3726, end: 3730, speaker: '', text: ' '}, ]; assert.equal(pa.transcriptToText(segs), '[00:00] Hallo zusammen. Heute geht es um X.\n[00:31] Zweite Gruppe.\n[62:05] Spät.'); const sp = [ {start: 0, speaker: 'Anna', text: 'Eins.'}, {start: 4, speaker: 'Anna', text: 'Zwei.'}, {start: 8, speaker: 'Bernd', text: 'Drei.'}, ]; assert.equal(pa.transcriptToText(sp), '[00:00] Anna: Eins. Zwei.\n[00:08] Bernd: Drei.'); assert.equal(pa.transcriptToText([]), ''); }); test('clock and mmss', () => { assert.equal(pa.mmss(754), '12:34'); assert.equal(pa.clock(754), '12:34'); assert.equal(pa.clock(3725), '1:02:05'); }); test('token estimate and the limit message', () => { assert.equal(pa.estimateTokens('a'.repeat(400)), 100); const big = {segments: Array.from({length: 20000}, (_, i) => ({start: i * 31, speaker: '', text: 'x'.repeat(30)}))}; assert.throws(() => pa.buildPrompt({title: 'T'}, big), e => e.diora && /zu lang/.test(e.message)); const ok = pa.buildPrompt({title: 'T', feed: {title: 'P'}, description: '
Notes & mehr
', duration_seconds: 3725, chapters: [{start: 60, title: 'Kap 1'}]}, {segments: [{start: 0, text: 'Hallo'}]}); assert.match(ok, /Podcast: P\nFolge: T\nDauer: 1:02:05\nShownotes:\nNotes & mehr\nKapitel:\n\[01:00\] Kap 1\n\nTranskript:\n\[00:00\] Hallo$/); assert.throws(() => pa.buildPrompt({title: 'T'}, {segments: []}), /leer/); }); test('system prompt is the one of the contract', async () => { const fs = await import('node:fs'); const doc = fs.readFileSync(new URL('../../docs/transcription.md', import.meta.url), 'utf8').split('\r\n').join('\n'); assert.ok(doc.includes(pa.SYSTEM)); assert.deepEqual(pa.SCHEMA.required, ['title', 'summary', 'kind', 'speakers', 'sections']); }); test('markdownToHtml: paragraphs, emphasis, lists, quotes, escaping', () => { assert.equal(pa.markdownToHtml('Eins *kursiv* und **fett**.\nWeiter.\n\nZwei.'), 'Eins kursiv und fett. Weiter.
\nZwei.
'); assert.equal(pa.markdownToHtml('- a\n- b'), ''); const evil = pa.markdownToHtml(' **„Zitat“ mehr