Files
inkling/tests/unit/m006-migration.test.ts
2026-05-09 20:32:32 +09:00

96 lines
3.6 KiB
TypeScript

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);
});
});