import { describe, it, expect, beforeEach } from 'vitest'; import { mkdtempSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import Database from 'better-sqlite3'; import { runMigrations } from '@main/db/migrations/index.js'; import { NoteRepository } from '@main/repository/NoteRepository.js'; import { MediaStore } from '@main/services/MediaStore.js'; import { CaptureService } from '@main/services/CaptureService.js'; describe('CaptureService', () => { let db: Database.Database; let repo: NoteRepository; let store: MediaStore; let tmp: string; let enqueued: string[]; let celebrated: string[]; let svc: CaptureService; beforeEach(() => { db = new Database(':memory:'); runMigrations(db); repo = new NoteRepository(db); tmp = mkdtempSync(join(tmpdir(), 'inkling-capture-')); store = new MediaStore(tmp); enqueued = []; celebrated = []; svc = new CaptureService(repo, store, { enqueue: async (id) => { enqueued.push(id); }, celebrate: (id) => { celebrated.push(id); } }); }); it('persists text-only and triggers enqueue + celebrate', async () => { const { noteId } = await svc.submit({ text: '안녕', images: [] }); expect(repo.findById(noteId)?.rawText).toBe('안녕'); expect(enqueued).toEqual([noteId]); expect(celebrated).toEqual([noteId]); }); it('saves images under media/{noteId}/', async () => { const img = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]).buffer; const { noteId } = await svc.submit({ text: 'x', images: [img] }); const note = repo.findById(noteId)!; expect(note.media).toHaveLength(1); expect(note.media[0]!.relPath.startsWith(`media/${noteId}/`)).toBe(true); }); it('rejects empty submit', async () => { await expect(svc.submit({ text: ' ', images: [] })).rejects.toThrow(/empty/i); expect(celebrated).toHaveLength(0); }); it('deleteNote removes db row + media dir', async () => { const img = new Uint8Array([0, 1, 2, 3]).buffer; const { noteId } = await svc.submit({ text: 't', images: [img] }); await svc.deleteNote(noteId); expect(repo.findById(noteId)).toBeNull(); }); });