import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import Database from 'better-sqlite3'; import { up } from '../../src/main/db/migrations/m006_revisions.js'; describe('m006 migration — note_revisions table', () => { let db: Database.Database; beforeEach(() => { db = new Database(':memory:'); db.pragma('foreign_keys = ON'); db.exec(` CREATE TABLE notes ( id TEXT PRIMARY KEY, raw_text TEXT NOT NULL, ai_title TEXT, ai_summary TEXT, ai_status TEXT NOT NULL CHECK (ai_status IN ('pending','done','failed','disabled')), ai_error TEXT, ai_provider TEXT, ai_generated_at TEXT, title_edited_by_user INTEGER NOT NULL DEFAULT 0, summary_edited_by_user INTEGER NOT NULL DEFAULT 0, user_intent TEXT, intent_prompted_at TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, due_date TEXT, due_date_edited_by_user INTEGER NOT NULL DEFAULT 0, deleted_at TEXT, last_recalled_at TEXT, recall_dismissed_at TEXT, status TEXT NOT NULL DEFAULT 'active', status_changed_at TEXT, move_reason TEXT ); INSERT INTO notes (id, raw_text, ai_status, created_at, updated_at) VALUES ('a', 'first text', 'done', '2026-05-01T00:00:00Z', '2026-05-01T00:00:00Z'), ('b', 'second text', 'done', '2026-05-02T00:00:00Z', '2026-05-02T00:00:00Z'); `); }); afterEach(() => { db.close(); }); it('creates note_revisions table with required columns', () => { up(db); const cols = db.prepare(`PRAGMA table_info(note_revisions)`).all() as Array<{ name: string }>; const names = cols.map((c) => c.name); expect(names).toEqual( expect.arrayContaining(['rev_id', 'note_id', 'raw_text', 'edited_at', 'edited_by']) ); }); it('creates idx_note_revisions_note_id index', () => { up(db); const idx = db.prepare(`PRAGMA index_list(note_revisions)`).all() as Array<{ name: string }>; expect(idx.map((i) => i.name)).toContain('idx_note_revisions_note_id'); }); it('cascades on note delete (FK ON DELETE CASCADE)', () => { up(db); db.prepare( `INSERT INTO note_revisions (note_id, raw_text, edited_at, edited_by) VALUES ('a', 'manual rev', '2026-05-03T00:00:00Z', 'user')` ).run(); db.prepare(`DELETE FROM notes WHERE id=?`).run('a'); const rows = db.prepare(`SELECT * FROM note_revisions WHERE note_id=?`).all('a'); expect(rows).toHaveLength(0); }); it("backfills existing notes as edited_by='capture' revisions", () => { up(db); const rows = db .prepare(`SELECT note_id, raw_text, edited_at, edited_by FROM note_revisions ORDER BY note_id`) .all() as Array<{ note_id: string; raw_text: string; edited_at: string; edited_by: string }>; expect(rows).toHaveLength(2); expect(rows[0]).toEqual({ note_id: 'a', raw_text: 'first text', edited_at: '2026-05-01T00:00:00Z', edited_by: 'capture' }); expect(rows[1]).toEqual({ note_id: 'b', raw_text: 'second text', edited_at: '2026-05-02T00:00:00Z', edited_by: 'capture' }); }); it('exports version=6', async () => { const mod = await import('../../src/main/db/migrations/m006_revisions.js'); expect(mod.version).toBe(6); }); });