import { mkdtemp, rm, stat } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import path from 'node:path'; import { afterAll, describe, expect, it } from 'vitest'; import { openGameDb, persist } from './client'; const dir = await mkdtemp(path.join(tmpdir(), 'sw-db-test-')); const file = path.join(dir, 'test.db'); afterAll(async () => { await rm(dir, { recursive: true, force: true }); }); function metaValue(db: Awaited>, key: string): string | undefined { const rows = db.raw.exec('SELECT value FROM _meta WHERE key = ?', [key]); return rows[0]?.values[0][0] as string | undefined; } describe('db client (sql.js/Drizzle plumbing)', () => { it('creates a valid DB file on disk when opening a fresh path', async () => { const db = await openGameDb(file); expect(db.file).toBe(file); const s = await stat(file); expect(s.size).toBeGreaterThan(0); // persisted at first open, not left in-memory only expect(metaValue(db, 'created_at')).toMatch(/^\d{4}-\d{2}-\d{2}T/); }); it('preserves state across reopen (volume persistence)', async () => { const created = metaValue(await openGameDb(file), 'created_at'); expect(created).toBeDefined(); const db = await openGameDb(file); // second process would see the same file expect(db.raw.exec('PRAGMA integrity_check')[0].values[0][0]).toBe('ok'); expect(metaValue(db, 'created_at')).toBe(created); // not re-stamped on reopen }); it('persist() rewrites the file atomically (tmp + rename)', async () => { const db = await openGameDb(file); await persist(db); const s = await stat(file); expect(s.size).toBeGreaterThan(0); // no leftover tmp file after a clean persist let tmpGone = true; try { await stat(`${file}.tmp`); tmpGone = false; } catch { /* expected */ } expect(tmpGone).toBe(true); }); });