Files
inkling/tests/unit/NotebookRepository.test.ts
th-kim0823 7aef46dc1a feat(ai): AiWorker — notebook_match 매치 시 자동 moveNote
- NotebookRepository.findByName(name) 추가 — COLLATE NOCASE case-insensitive 조회
- AiWorkerOptions.notebookRepo 옵션 추가 (optional Pick<NotebookRepository, ...>)
- processJob: generate 전 notebookRepo.list() → notebooks 배열 GenerateInput 에 주입
- processJob: updateAiResult 후 res.notebookMatch valid 이름이면 findByName + moveNote 호출
- main/index.ts: AiWorker 생성 시 notebookRepo 전달
- NotebookRepository.test.ts: findByName 3개 테스트 추가
- AiWorker.test.ts: notebook 매칭 describe 4개 테스트 추가 (총 45 테스트 통과)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 10:36:59 +09:00

116 lines
3.9 KiB
TypeScript

import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import Database from 'better-sqlite3';
import { runMigrations } from '../../src/main/db/migrations/index.js';
import { NotebookRepository } from '../../src/main/repository/NotebookRepository.js';
describe('NotebookRepository', () => {
let db: Database.Database;
let repo: NotebookRepository;
beforeEach(() => {
db = new Database(':memory:');
db.pragma('foreign_keys = ON');
runMigrations(db);
repo = new NotebookRepository(db);
});
afterEach(() => { db.close(); });
it('list: 기본 notebook 1개 + noteCount 0', () => {
const all = repo.list();
expect(all).toHaveLength(1);
expect(all[0]!.name).toBe('기본');
expect(all[0]!.noteCount).toBe(0);
});
it('create: 새 notebook 추가', () => {
const nb = repo.create({ name: '회사', color: '#0a4b80' });
expect(nb.name).toBe('회사');
expect(nb.color).toBe('#0a4b80');
expect(repo.list()).toHaveLength(2);
});
it('create: 같은 이름 두 번이면 throw', () => {
repo.create({ name: '회사' });
expect(() => repo.create({ name: '회사' })).toThrow();
});
it('rename: 이름 변경', () => {
const nb = repo.create({ name: '회사' });
repo.rename(nb.id, '워크');
const after = repo.findById(nb.id);
expect(after?.name).toBe('워크');
});
it('delete: 메모 없으면 OK', () => {
const nb = repo.create({ name: '회사' });
const r = repo.delete(nb.id);
expect(r.ok).toBe(true);
expect(repo.findById(nb.id)).toBeNull();
});
it('delete: 메모 있으면 RESTRICT — ok:false', () => {
const nb = repo.create({ name: '회사' });
const ts = '2026-05-14T00:00:00Z';
db.prepare(
`INSERT INTO notes(id, raw_text, ai_status, created_at, updated_at, status, notebook_id)
VALUES('n1','t','pending',?,?,'active',?)`
).run(ts, ts, nb.id);
const r = repo.delete(nb.id);
expect(r.ok).toBe(false);
if (!r.ok) expect(r.reason).toBe('has_notes');
});
it('noteCount: status="active" 만 카운트 (completed/trashed 제외)', () => {
const nb = repo.create({ name: '회사' });
const ts = '2026-05-14T00:00:00Z';
const insert = db.prepare(
`INSERT INTO notes(id, raw_text, ai_status, created_at, updated_at, status, notebook_id)
VALUES(?,?,?,?,?,?,?)`
);
insert.run('n1','t','done',ts,ts,'active',nb.id);
insert.run('n2','t','done',ts,ts,'completed',nb.id);
insert.run('n3','t','done',ts,ts,'trashed',nb.id);
const found = repo.findById(nb.id);
expect(found?.noteCount).toBe(1);
});
it('moveNote: notebook_id 갱신', () => {
const nb = repo.create({ name: '회사' });
const ts = '2026-05-14T00:00:00Z';
const defaultId = repo.list().find((n) => n.name === '기본')!.id;
db.prepare(
`INSERT INTO notes(id, raw_text, ai_status, created_at, updated_at, status, notebook_id)
VALUES('n1','t','pending',?,?,'active',?)`
).run(ts, ts, defaultId);
repo.moveNote('n1', nb.id);
const r = db.prepare(`SELECT notebook_id FROM notes WHERE id='n1'`).get() as { notebook_id: string };
expect(r.notebook_id).toBe(nb.id);
});
it('setColor: 색 변경', () => {
const nb = repo.create({ name: '회사', color: '#000' });
repo.setColor(nb.id, '#fff');
expect(repo.findById(nb.id)?.color).toBe('#fff');
});
it('delete: 존재하지 않는 id → ok:false reason="not_found"', () => {
const r = repo.delete('does-not-exist');
expect(r.ok).toBe(false);
if (!r.ok) expect(r.reason).toBe('not_found');
});
it('findByName: 이름으로 조회', () => {
const nb = repo.create({ name: '회사' });
const found = repo.findByName('회사');
expect(found?.id).toBe(nb.id);
});
it('findByName: case-insensitive', () => {
repo.create({ name: 'Work' });
expect(repo.findByName('work')?.name).toBe('Work');
});
it('findByName: 없으면 null', () => {
expect(repo.findByName('없음')).toBeNull();
});
});