import { describe, it, expect } from 'vitest'; import { createDb } from '../src/lib/db'; import { services, getService } from '../src/data/services'; import { trainings, trainingDaMostrare, VISTE_TRAINING } from '../src/data/trainings'; import { contentSeed } from '../src/data/content-seed'; import { site } from '../src/data/site'; import { PAGINE_CON_CALENDARIO, CARD_CON_CALENDARIO } from '../src/data/calendari'; import { rinominaSmallGroup, calcola, applica, TESTI } from '../scripts/testi-17-agosto.mjs'; // Le modifiche chieste dal cliente il 17/08/2026 (MODIFICHE_PER_SITO.pdf). describe('Small Group è diventato Personalized Training Group', () => { it('non resta traccia del vecchio nome nei dati né nel seed', () => { const testi = [ ...services.flatMap((s) => [s.title, s.subtitle, s.excerpt, s.longDescription, ...s.features, ...s.faq.flatMap((f) => [f.q, f.a])]), ...trainings.flatMap((t) => [t.title, t.caption, t.description]), ...site.footerTraining.map((v) => v.label), ...contentSeed.map((e) => e.value), ]; expect(testi.filter((v) => /small group/i.test(v))).toEqual([]); }); // Lo slug resta `small-group`: è l'indirizzo della scheda, e cambiarlo romperebbe i link // già girati su WhatsApp senza che nessuno se ne accorga. it('lo slug della scheda non cambia', () => { expect(getService('small-group')?.title).toBe('Personalized Training Group'); }); it('gli articoli restano corretti, e passarci due volte non cambia niente', () => { const casi: [string, string][] = [ ['Lo Small Group di InsanityLab è un allenamento', 'Il Personalized Training Group di InsanityLab è un allenamento'], ['nuovi format come gli small group e una', 'nuovi format come i Personalized Training Group e una'], ['One to One / Small Group / Rehab', 'One to One / Personalized Training Group / Rehab'], ['Small Groups', 'Personalized Training Group'], ['in formula small group (massimo 4 persone)', 'in formula Personalized Training Group (massimo 4 persone)'], ]; for (const [prima, dopo] of casi) { expect(rinominaSmallGroup(prima)).toBe(dopo); expect(rinominaSmallGroup(dopo)).toBe(dopo); } }); }); describe('lo script porta i testi nuovi in un database già scritto', () => { it('aggiorna le righe vecchie e al secondo giro non ha più niente da fare', () => { const db = createDb(':memory:'); const scrivi = db.prepare('INSERT OR REPLACE INTO content_blocks (tag, type, value) VALUES (?, ?, ?)'); scrivi.run('service.one-to-one.subtitle', 'text', 'One to One / Small Group / Rehab'); scrivi.run('service.profilazione.subtitle', 'text', 'Profilazione e valutazione fisica'); scrivi.run('footer.services.4.label', 'text', 'Profilazione'); const cambi = applica(db); const dopo = (tag: string) => (db.prepare('SELECT value FROM content_blocks WHERE tag = ?').get(tag) as { value: string }).value; expect(dopo('service.one-to-one.subtitle')).toBe('One to One / Personalized Training Group / Rehab'); expect(dopo('service.profilazione.subtitle')).toBe('Base e avanzato'); expect(dopo('footer.services.4.label')).toBe('Check-up'); expect(cambi.length).toBeGreaterThanOrEqual(3); expect(calcola(db)).toEqual([]); }); // Un `--dry-run` che scrivesse renderebbe inutile guardare prima di toccare la produzione. it('con --dry-run non tocca niente', () => { const db = createDb(':memory:'); db.prepare('INSERT OR REPLACE INTO content_blocks (tag, type, value) VALUES (?, ?, ?)') .run('promo.card.2.title', 'text', 'Small Group'); expect(applica(db, { dryRun: true }).length).toBe(1); expect((db.prepare('SELECT value FROM content_blocks WHERE tag = ?').get('promo.card.2.title') as { value: string }).value) .toBe('Small Group'); }); it('i testi riscritti a mano corrispondono a quelli del seed', () => { const seed = new Map(contentSeed.map((e) => [e.tag, e.value])); for (const [tag, valore] of Object.entries(TESTI)) expect(seed.get(tag)).toBe(valore); }); }); describe('viste di /training', () => { it('senza vista si vedono tutti i training', () => { expect(trainingDaMostrare()?.map((t) => t.id)).toEqual(trainings.map((t) => t.id)); }); it('One to One porta a One to One, Personalized Training Group e Rehab', () => { expect(trainingDaMostrare('one-to-one')?.map((t) => t.id)).toEqual(['one-to-one', 'small-groups', 'rehab']); }); it('Class porta a Holistic e Reformer', () => { expect(trainingDaMostrare('class')?.map((t) => t.id)).toEqual(['holistic-class', 'reformer-class']); }); // Un filtro sbagliato che mostra tutto farebbe passare per buono un indirizzo rotto. it('una vista inventata è 404, non l\'elenco intero', () => { expect(trainingDaMostrare('inesistente')).toBeNull(); }); it('ogni vista nomina solo training che esistono', () => { for (const v of Object.values(VISTE_TRAINING)) { for (const id of v.blocchi) expect(trainings.some((t) => t.id === id)).toBe(true); } }); }); describe('instradamento delle card di /services', () => { const href = (slug: string) => { const s = getService(slug)!; return s.href ?? `/services/${s.slug}`; }; it('One to One e Class portano alle viste di training', () => { expect(href('one-to-one')).toBe('/training/one-to-one'); expect(href('performance-class')).toBe('/training/class'); }); it('Check-up porta alla propria scheda', () => { expect(href('profilazione')).toBe('/services/profilazione'); }); // La Performance Class non si eroga più: la card resta, la scheda che la spiegava no. it('la Performance Class non ha più una scheda ma resta in griglia', () => { expect(getService('performance-class')?.page).toBe(false); expect(getService('performance-class')?.grid).not.toBe(false); }); it('nessun link del sito manda a una scheda che non esiste', () => { const schede = new Set(services.filter((s) => s.page !== false).map((s) => `/services/${s.slug}`)); const interni = [...site.footerServices, ...site.footerTraining, ...site.navigation] .map((v) => v.href) .filter((h) => h.startsWith('/services/')); for (const h of interni) expect(schede.has(h)).toBe(true); }); }); describe('Check-up', () => { const checkup = getService('profilazione')!; it('il trafiletto della card racconta Base e Avanzato', () => { expect(checkup.title).toBe('Check-up'); expect(checkup.subtitle).toBe('Base e avanzato'); expect(checkup.excerpt).toContain('Check-up Base'); expect(checkup.excerpt).toContain('Check-up Avanzato'); }); it('la scheda porta la sezione avanzata con i suoi cinque punti', () => { expect(checkup.extra?.title).toBe('Check-up Avanzato'); expect(checkup.extra?.body).toContain('Wellness Tower'); expect(checkup.extra?.items).toHaveLength(5); }); it('i testi della sezione avanzata sono modificabili dal pannello', () => { const tags = new Set(contentSeed.map((e) => e.tag)); expect(tags.has('service.profilazione.extra.title')).toBe(true); expect(tags.has('service.profilazione.extra.body')).toBe(true); for (let i = 1; i <= 5; i++) expect(tags.has(`service.profilazione.extra.item.${i}`)).toBe(true); }); }); describe('calendario delle class', () => { // Il calendario si apre da due punti diversi: le schede delle class che si fanno, e la // card «Class» della griglia servizi, che ha slug `performance-class`. it('le schede sono Holistic e Reformer, la Performance Class è fuori', () => { expect(PAGINE_CON_CALENDARIO).toEqual(['holistic-class', 'reformer-class']); }); it('in griglia il bottone sta sulla card Class', () => { expect(CARD_CON_CALENDARIO).toEqual(['performance-class']); }); it('ogni slug nominato esiste davvero', () => { for (const slug of [...PAGINE_CON_CALENDARIO, ...CARD_CON_CALENDARIO]) expect(getService(slug)).toBeDefined(); }); }); describe('promo ed eventi', () => { it('i testi della pagina di scelta e degli eventi sono nel seed', () => { const tags = new Set(contentSeed.map((e) => e.tag)); for (const tag of ['promo-eventi.hero.title', 'promo-eventi.promo.label', 'promo-eventi.eventi.label', 'eventi.hero.title', 'eventi.inaugurazione.title', 'eventi.inaugurazione.body']) { expect(tags.has(tag)).toBe(true); } }); it('l\'inaugurazione dice la data e che il programma manca ancora', () => { const testo = contentSeed.find((e) => e.tag === 'eventi.inaugurazione.body')!.value; expect(contentSeed.find((e) => e.tag === 'eventi.inaugurazione.title')!.value).toContain('19 settembre 2026'); expect(testo).toContain('programma completo'); }); // La voce di menu continua a puntare qui: è l'indirizzo già girato ai clienti. it('il menu punta alla pagina di scelta', () => { expect(site.navigation.some((v) => v.href === '/promo-eventi')).toBe(true); }); });