feat: content store con seed, cache e fallback

This commit is contained in:
2026-07-05 15:43:29 +02:00
parent 6f51aec4c6
commit b22cc40b03
5 changed files with 153 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
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 } 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('');
});
});