107 lines
4.9 KiB
TypeScript
107 lines
4.9 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
import Database from 'better-sqlite3';
|
|
import { mkdtemp, writeFile, mkdir, rm } from 'node:fs/promises';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { runMigrations } from '@main/db/migrations/index.js';
|
|
import { NoteRepository } from '@main/repository/NoteRepository.js';
|
|
import { ImportService } from '@main/services/ImportService.js';
|
|
import { MediaStore } from '@main/services/MediaStore.js';
|
|
|
|
describe('ImportService.applySyncFromDir', () => {
|
|
let db: Database.Database;
|
|
let repo: NoteRepository;
|
|
let svc: ImportService;
|
|
let workDir: string;
|
|
|
|
beforeEach(async () => {
|
|
db = new Database(':memory:');
|
|
db.pragma('foreign_keys = ON');
|
|
runMigrations(db);
|
|
repo = new NoteRepository(db);
|
|
workDir = await mkdtemp(join(tmpdir(), 'inkling-sync-'));
|
|
const mediaStore = new MediaStore(workDir);
|
|
svc = new ImportService(repo, mediaStore);
|
|
});
|
|
|
|
afterEach(async () => {
|
|
db.close();
|
|
await rm(workDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it('inserts new notes and reports changedCount', async () => {
|
|
const notesDir = join(workDir, 'notes');
|
|
await mkdir(notesDir, { recursive: true });
|
|
await writeFile(
|
|
join(notesDir, 'a.md'),
|
|
`---\nid: 00000000-0000-0000-0000-000000000001\ncreated_at: 2026-05-09T00:00:00Z\nupdated_at: 2026-05-10T00:00:00Z\ntitle: title\ntitle_source: ai\nsummary: summary\nsummary_source: ai\nstatus: active\ninkling_export_version: 1\n---\n\n# title\n\n> summary\n\nbody\n`
|
|
);
|
|
const r = await svc.applySyncFromDir(workDir);
|
|
expect(r.changedCount).toBe(1);
|
|
const note = repo.findById('00000000-0000-0000-0000-000000000001');
|
|
expect(note?.rawText).toBe('body');
|
|
});
|
|
|
|
it('skips unchanged notes (no changedCount increment)', async () => {
|
|
const created = repo.create({ rawText: 'body' });
|
|
db.prepare(`UPDATE notes SET updated_at=? WHERE id=?`).run('2026-05-15T00:00:00Z', created.id);
|
|
const notesDir = join(workDir, 'notes');
|
|
await mkdir(notesDir, { recursive: true });
|
|
await writeFile(
|
|
join(notesDir, 'a.md'),
|
|
`---\nid: ${created.id}\ncreated_at: 2026-05-09T00:00:00Z\nupdated_at: 2026-05-10T00:00:00Z\ntitle: t\ntitle_source: ai\nsummary: s\nsummary_source: ai\nstatus: active\ninkling_export_version: 1\n---\n\n# t\n\n> s\n\nbody\n`
|
|
);
|
|
const r = await svc.applySyncFromDir(workDir);
|
|
expect(r.changedCount).toBe(0);
|
|
});
|
|
|
|
it('returns changedCount=0 for an empty notes directory', async () => {
|
|
const notesDir = join(workDir, 'notes');
|
|
await mkdir(notesDir, { recursive: true });
|
|
const r = await svc.applySyncFromDir(workDir);
|
|
expect(r.changedCount).toBe(0);
|
|
});
|
|
|
|
it('updates a note when source updatedAt is newer', async () => {
|
|
const created = repo.create({ rawText: 'old body' });
|
|
db.prepare(`UPDATE notes SET updated_at=? WHERE id=?`).run('2026-05-01T00:00:00Z', created.id);
|
|
const notesDir = join(workDir, 'notes');
|
|
await mkdir(notesDir, { recursive: true });
|
|
await writeFile(
|
|
join(notesDir, 'a.md'),
|
|
`---\nid: ${created.id}\ncreated_at: 2026-05-09T00:00:00Z\nupdated_at: 2026-05-10T00:00:00Z\ntitle: t\ntitle_source: ai\nsummary: s\nsummary_source: ai\nstatus: active\ninkling_export_version: 1\n---\n\n# t\n\n> s\n\nnew body\n`
|
|
);
|
|
const r = await svc.applySyncFromDir(workDir);
|
|
expect(r.changedCount).toBe(1);
|
|
const note = repo.findById(created.id);
|
|
expect(note?.rawText).toBe('new body');
|
|
});
|
|
|
|
it('preserves status field from frontmatter', async () => {
|
|
const notesDir = join(workDir, 'notes');
|
|
await mkdir(notesDir, { recursive: true });
|
|
await writeFile(
|
|
join(notesDir, 'a.md'),
|
|
`---\nid: 00000000-0000-0000-0000-000000000002\ncreated_at: 2026-05-09T00:00:00Z\nupdated_at: 2026-05-10T00:00:00Z\ntitle: t\ntitle_source: ai\nsummary: s\nsummary_source: ai\nstatus: archived\nstatus_changed_at: 2026-05-08T00:00:00Z\nmove_reason: done\ninkling_export_version: 1\n---\n\n# t\n\n> s\n\nbody\n`
|
|
);
|
|
await svc.applySyncFromDir(workDir);
|
|
const note = repo.findById('00000000-0000-0000-0000-000000000002');
|
|
expect(note?.status).toBe('archived');
|
|
expect(note?.statusChangedAt).toBe('2026-05-08T00:00:00Z');
|
|
expect(note?.moveReason).toBe('done');
|
|
});
|
|
|
|
it('preserves dueDate from frontmatter', async () => {
|
|
const notesDir = join(workDir, 'notes');
|
|
await mkdir(notesDir, { recursive: true });
|
|
await writeFile(
|
|
join(notesDir, 'a.md'),
|
|
`---\nid: 00000000-0000-0000-0000-000000000003\ncreated_at: 2026-05-09T00:00:00Z\nupdated_at: 2026-05-10T00:00:00Z\ntitle: t\ntitle_source: ai\nsummary: s\nsummary_source: ai\nstatus: active\ndue_date: 2026-06-01\ndue_date_source: user\ninkling_export_version: 1\n---\n\n# t\n\n> s\n\nbody\n`
|
|
);
|
|
await svc.applySyncFromDir(workDir);
|
|
const note = repo.findById('00000000-0000-0000-0000-000000000003');
|
|
expect(note?.dueDate).toBe('2026-06-01');
|
|
expect(note?.dueDateEditedByUser).toBe(true);
|
|
});
|
|
});
|