114 lines
4.1 KiB
TypeScript
114 lines
4.1 KiB
TypeScript
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();
|
|
});
|
|
});
|
|
|
|
describe('CaptureService telemetry emit', () => {
|
|
let db: Database.Database;
|
|
let repo: NoteRepository;
|
|
let store: MediaStore;
|
|
let tmp: string;
|
|
let events: Array<{ kind: string; payload: { noteId: string; rawTextLength: number; hasMedia: boolean } }>;
|
|
|
|
beforeEach(() => {
|
|
db = new Database(':memory:');
|
|
runMigrations(db);
|
|
repo = new NoteRepository(db);
|
|
tmp = mkdtempSync(join(tmpdir(), 'inkling-capture-'));
|
|
store = new MediaStore(tmp);
|
|
events = [];
|
|
});
|
|
|
|
it('emits capture event with noteId/rawTextLength/hasMedia', async () => {
|
|
const svc = new CaptureService(repo, store, {
|
|
enqueue: async () => {},
|
|
celebrate: () => {},
|
|
telemetry: { emit: async (ev) => { events.push(ev as typeof events[number]); } }
|
|
});
|
|
await svc.submit({ text: '안녕하세요', images: [] });
|
|
expect(events).toHaveLength(1);
|
|
expect(events[0]!.kind).toBe('capture');
|
|
expect(events[0]!.payload.rawTextLength).toBe('안녕하세요'.length);
|
|
expect(events[0]!.payload.hasMedia).toBe(false);
|
|
expect(typeof events[0]!.payload.noteId).toBe('string');
|
|
});
|
|
|
|
it('emits hasMedia=true when images present', async () => {
|
|
const svc = new CaptureService(repo, store, {
|
|
enqueue: async () => {},
|
|
celebrate: () => {},
|
|
telemetry: { emit: async (ev) => { events.push(ev as typeof events[number]); } }
|
|
});
|
|
const img = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]).buffer;
|
|
await svc.submit({ text: '이미지 메모', images: [img] });
|
|
expect(events).toHaveLength(1);
|
|
expect(events[0]!.payload.hasMedia).toBe(true);
|
|
});
|
|
|
|
it('does NOT emit when telemetry dep absent (backward compat)', async () => {
|
|
const svc = new CaptureService(repo, store, {
|
|
enqueue: async () => {},
|
|
celebrate: () => {}
|
|
});
|
|
const result = await svc.submit({ text: 'no telem', images: [] });
|
|
expect(typeof result.noteId).toBe('string');
|
|
expect(events).toHaveLength(0); // events array stays empty since no telemetry was wired
|
|
});
|
|
});
|