import { describe, it, expect } from 'vitest'; import { parseGuide, kindOf, rewriteAssets } from '../scripts/campus/parse.mjs'; import { sourceDirFor, CHAPTERS, AREAS, CH_COLORS } from '../scripts/campus/structure.mjs'; const body = ` > Sintesi di studio basata sulla trascrizione della lezione del corso. ## In sintesi Testo di prova. ## Concetti chiave - **Il sonno è il pilastro.** Spiegazione. - **Ritmi circadiani.** Altra spiegazione. `; describe('kindOf / sourceDirFor', () => { it('riconosce il tipo dallo slug', () => { expect(kindOf('lezione-01-ottimizzazione-del-sonno')).toBe('lezione'); expect(kindOf('lezione-live-1-2026-02-24')).toBe('live'); expect(kindOf('accelerator-1-2025-11-11')).toBe('accelerator'); expect(kindOf('slide-hrv')).toBe('slide'); expect(kindOf('speaker-resta-marketing')).toBe('speaker'); expect(kindOf('consulenza-2025-02-04-cristina-ruggeri')).toBe('consulenza'); expect(kindOf('masterclass-2025-10-08-luca-ruggeri')).toBe('masterclass'); expect(kindOf('qa-01-tony-04')).toBe('qa'); }); it('mappa lo slug alla cartella sorgente', () => { expect(sourceDirFor('lezione-01-ottimizzazione-del-sonno')).toBe('studio'); expect(sourceDirFor('lezione-live-1-2026-02-24')).toBe('lezioni-live'); expect(sourceDirFor('qa-01-tony-04')).toBe('qa'); expect(sourceDirFor('consulenza-2025-02-04-cristina-ruggeri')).toBe('consulenze'); }); }); describe('parseGuide', () => { it('lezione numerata con parte e relatore', () => { const raw = '# Lezione 2 — Movimento e fitness (Parte 1) (Tony Manfron) — Guida allo studio' + body; const g = parseGuide(raw, 'lezione-02-movimento-fitness-parte1', 1); expect(g).toMatchObject({ kind: 'lezione', num: 2, relatore: 'Tony Manfron', parte: 'Parte 1', titleFull: 'Movimento e fitness (Parte 1)', titleShort: 'Movimento e fitness', label: 'L2 · Parte 1', }); }); it('lezione live e accelerator usano la data come titolo', () => { const live = parseGuide( '# Lezione live 1 — 24 febbraio 2026 (Massimo Filippi) — Guida allo studio' + body, 'lezione-live-1-2026-02-24', 1); expect(live).toMatchObject({ kind: 'live', num: 1, titleFull: 'Lezione live 1 — 24 febbraio 2026', titleShort: 'Lezione live 1', relatore: 'Massimo Filippi · 24 febbraio 2026', label: 'LV1', }); const acc = parseGuide( '# Accelerator 3 — 28 gennaio 2026 (Massimo Filippi) — Guida allo studio' + body, 'accelerator-3-2026-01-28', 3); expect(acc).toMatchObject({ kind: 'accelerator', num: 3, titleShort: 'Accelerator 3', label: 'A3' }); }); it('slide, speaker, consulenza, masterclass e Q&A', () => { expect(parseGuide('# Slide — HRV: Variabilità della frequenza cardiaca — Guida allo studio' + body, 'slide-hrv', 1)) .toMatchObject({ kind: 'slide', num: 1, titleFull: 'HRV: Variabilità della frequenza cardiaca', label: 'SL1' }); expect(parseGuide('# Intervento — Marketing nel BioHacking (Roberto Resta) — Guida allo studio' + body, 'speaker-resta-marketing', 5)) .toMatchObject({ kind: 'speaker', titleFull: 'Marketing nel BioHacking', relatore: 'Roberto Resta', label: 'SP5' }); expect(parseGuide('# Consulenza — Cristina Ruggeri (04/02/2025) — Guida allo studio' + body, 'consulenza-2025-02-04-cristina-ruggeri', 1)) .toMatchObject({ kind: 'consulenza', titleFull: 'Cristina Ruggeri', relatore: '04/02/2025', label: 'C1' }); expect(parseGuide('# Masterclass — Luca Ruggeri (08/10/2025) — Guida allo studio' + body, 'masterclass-2025-10-08-luca-ruggeri', 1)) .toMatchObject({ kind: 'masterclass', titleFull: 'Luca Ruggeri', relatore: '08/10/2025', label: 'MC1' }); expect(parseGuide('# Q&A Tony n°4 — Guida allo studio' + body, 'qa-01-tony-04', 1)) .toMatchObject({ kind: 'qa', titleFull: 'Q&A Tony n°4', label: 'QA1' }); }); it('estrae i concetti chiave in grassetto e rimuove H1 e blockquote', () => { const g = parseGuide('# Lezione 1 — Sonno (Tony Manfron) — Guida allo studio' + body, 'lezione-01-ottimizzazione-del-sonno', 1); expect(g.concetti).toEqual(['Il sonno è il pilastro', 'Ritmi circadiani']); expect(g.html).not.toContain('Guida allo studio'); expect(g.html).not.toContain('Sintesi di studio basata'); expect(g.html).toContain(' { expect(() => parseGuide('# Titolo qualunque\n\ntesto', 'lezione-99-x', 1)).toThrow(/H1 non riconosciuto/); }); }); describe('rewriteAssets', () => { it('riscrive i path relativi delle immagini verso la route protetta', () => { const html = 'x'; expect(rewriteAssets(html)).toBe( 'x'); }); }); describe('struttura del corso', () => { const chapterNums = CHAPTERS.map((c) => c[0] as number); it('ogni capitolo ha un colore e ogni area capitoli esistenti', () => { expect(CH_COLORS.length).toBe(CHAPTERS.length); for (const area of AREAS) for (const n of area[4] as number[]) expect(chapterNums).toContain(n); }); it('nessuno slug duplicato e ogni capitolo è in una sola area', () => { const slugs = CHAPTERS.flatMap((c) => c[3] as string[]); expect(new Set(slugs).size).toBe(slugs.length); const assigned = AREAS.flatMap((a) => a[4] as number[]); expect(new Set(assigned).size).toBe(assigned.length); expect(assigned.sort((a, b) => a - b)).toEqual(chapterNums); }); });