import { describe, it, expect, beforeEach } from 'vitest'; import type Database from 'better-sqlite3'; import { createDb } from '../src/lib/db'; import { contentSeed } from '../src/data/content-seed'; import { makeContentStore, syncSeed, resolveContent } from '../src/lib/content'; let db: Database.Database; beforeEach(() => { db = createDb(':memory:'); }); describe('seed', () => { it('tag univoci, validi e valori non vuoti', () => { const tags = contentSeed.map((e) => e.tag); expect(new Set(tags).size).toBe(tags.length); for (const e of contentSeed) { expect(e.tag).toMatch(/^[a-z0-9-]+(\.[a-z0-9-]+)+$/); if (e.type !== 'image') expect(e.value.length).toBeGreaterThan(0); } }); it('createDb sincronizza il seed senza sovrascrivere modifiche', () => { const n = (db.prepare('SELECT COUNT(*) AS n FROM content_blocks').get() as { n: number }).n; expect(n).toBe(contentSeed.length); db.prepare(`UPDATE content_blocks SET value = 'MODIFICATO' WHERE tag = ?`).run(contentSeed[0].tag); // ri-sync (come a un nuovo avvio) non deve toccare la modifica syncSeed(db); const v = db.prepare('SELECT value FROM content_blocks WHERE tag = ?').get(contentSeed[0].tag) as { value: string }; expect(v.value).toBe('MODIFICATO'); }); }); describe('content store', () => { it('legge dal DB con classi preset e cache invalidabile', () => { const store = makeContentStore(() => db); const tag = contentSeed[0].tag; db.prepare(`UPDATE content_blocks SET value = 'Nuovo', styles = '{"size":"l"}' WHERE tag = ?`).run(tag); store.invalidate(); const r = store.resolve(tag); expect(r.value).toBe('Nuovo'); expect(r.classes).toBe('cs-size-l'); // senza invalidate la cache resta db.prepare(`UPDATE content_blocks SET value = 'Altro' WHERE tag = ?`).run(tag); expect(store.resolve(tag).value).toBe('Nuovo'); store.invalidate(); expect(store.resolve(tag).value).toBe('Altro'); }); it('fallback: tag assente nel DB usa il seed, sconosciuto stringa vuota', () => { const store = makeContentStore(() => db); db.prepare('DELETE FROM content_blocks WHERE tag = ?').run(contentSeed[0].tag); store.invalidate(); expect(store.resolve(contentSeed[0].tag).value).toBe(contentSeed[0].value); expect(store.resolve('tag.inesistente').value).toBe(''); }); it('styles corrotto nel DB viene ignorato', () => { const store = makeContentStore(() => db); db.prepare(`UPDATE content_blocks SET styles = 'non-json' WHERE tag = ?`).run(contentSeed[0].tag); store.invalidate(); expect(store.resolve(contentSeed[0].tag).classes).toBe(''); }); it('resolveContent restituisce il guid dal DB', () => { const r = resolveContent('home.hero.cta'); expect(typeof r.guid).toBe('string'); expect(r.guid.length).toBeGreaterThan(10); }); });