import { describe, it, expect, beforeEach, afterEach } from 'vitest' import { DatabaseSync } from 'node:sqlite' import { migrate } from '../../src/main/db/migrate' import { ChapterRepository } from '../../src/main/db/repositories/chapter.repo' import { SettingRepository } from '../../src/main/db/repositories/setting.repo' import { VolumeRepository } from '../../src/main/db/repositories/volume.repo' import { TimelineService } from '../../src/main/services/timeline.service' import type { SqliteDb } from '../../src/main/db/types' describe('TimelineService', () => { let db: SqliteDb let timeline: TimelineService beforeEach(() => { db = new DatabaseSync(':memory:') migrate(db) timeline = new TimelineService(db) }) afterEach(() => { db.close() }) it('UT-TL-01: lists chapter entries sorted by story time', () => { const vol = new VolumeRepository(db).create('第一卷', 0) const chapters = new ChapterRepository(db) const ch1 = chapters.create(vol.id, '第一章', 0) chapters.update(ch1.id, { storyTime: '730' }) const ch2 = chapters.create(vol.id, '第二章', 1) chapters.update(ch2.id, { storyTime: '750' }) const list = timeline.list() expect(list.filter((e) => e.kind === 'chapter')).toHaveLength(2) expect(list[0]?.title).toBe('第一章') expect(list[1]?.title).toBe('第二章') }) it('UT-TL-02: detects age regression conflict', () => { const vol = new VolumeRepository(db).create('第一卷', 0) const chapters = new ChapterRepository(db) const settings = new SettingRepository(db) const hero = settings.create('character', '林远') settings.update(hero.id, { properties: { birthDate: '700' } }) const ch1 = chapters.create(vol.id, '第一章', 0) chapters.update(ch1.id, { storyTime: '730' }) const ch2 = chapters.create(vol.id, '第二章', 1) chapters.update(ch2.id, { storyTime: '720' }) const conflicts = timeline.detectConflicts() expect(conflicts).toHaveLength(1) expect(conflicts[0]?.chapterTitle).toBe('第二章') expect(conflicts[0]?.message).toContain('林远') }) it('UT-TL-03: upserts manual timeline event', () => { const entry = timeline.upsertManual({ title: '大战', storyTime: '800' }) expect(entry.kind).toBe('manual') expect(entry.title).toBe('大战') const list = timeline.list() expect(list.some((e) => e.id === entry.id)).toBe(true) }) })