import { describe, it, expect, beforeEach, afterEach } from 'vitest' import { DatabaseSync } from 'node:sqlite' import { migrate } from '../../src/main/db/migrate' import { VolumeRepository } from '../../src/main/db/repositories/volume.repo' import { AiSessionRepository } from '../../src/main/db/repositories/ai-session.repo' import { InteractiveRepository } from '../../src/main/db/repositories/interactive.repo' import { SnapshotRepository } from '../../src/main/db/repositories/snapshot.repo' import { ChapterRepository } from '../../src/main/db/repositories/chapter.repo' import { ChapterFinishService } from '../../src/main/services/chapter-finish.service' import { AutoWritingService } from '../../src/main/services/auto-writing.service' import { handoffToInteractive } from '../../src/main/services/writing-flow-handoff.service' import type { SqliteDb } from '../../src/main/db/types' describe('ChapterFinishService', () => { let db: SqliteDb let volId: string let flowId: string beforeEach(() => { db = new DatabaseSync(':memory:') migrate(db) volId = new VolumeRepository(db).create('卷一', 0).id const session = new AiSessionRepository(db).create('t', 'm') flowId = new InteractiveRepository(db).create(session.id).id new InteractiveRepository(db).addScene(flowId, '

场景

', 'A') }) afterEach(() => db.close()) it('IT-FIN-02: creates ai snapshot on interactive finish', () => { const service = new ChapterFinishService(db) const { chapterId } = service.finishFromFlow(flowId, volId, '交互初稿', 'interactive', '交互写作成章') const snaps = new SnapshotRepository(db).list(chapterId) expect(snaps.some((s) => s.type === 'ai' && s.name.includes('交互'))).toBe(true) }) it('IT-FIN-01: auto origin and snapshot label', () => { const service = new ChapterFinishService(db) const { chapterId } = service.finishFromFlow(flowId, volId, '自动初稿', 'auto', '自动写作成章') const ch = new ChapterRepository(db).get(chapterId)! expect(ch.origin).toBe('auto') const snaps = new SnapshotRepository(db).list(chapterId) expect(snaps.some((s) => s.name.includes('自动'))).toBe(true) }) }) describe('auto handoff', () => { it('IT-AUTO-04: handoff sets flow_mode interactive', () => { const db = new DatabaseSync(':memory:') migrate(db) const session = new AiSessionRepository(db).create('t', 'm') const repo = new InteractiveRepository(db) const flow = repo.create(session.id, 'auto', 'auto_generate') repo.addScene(flow.id, '

已生成

', '场景1') const result = handoffToInteractive(repo, flow.id) expect(result.flowMode).toBe('interactive') expect(result.step).toBe('plot_suggest') db.close() }) }) describe('AutoWritingService.setGoal', () => { it('advances to scene_plan', () => { const db = new DatabaseSync(':memory:') migrate(db) const session = new AiSessionRepository(db).create('t', 'm') const service = new AutoWritingService(db, { chat: async () => '' } as never) const flow = service.start(session.id) const updated = service.setGoal(flow.id, { chapterGoal: '林远通过入门考核', wordMin: 2000, wordMax: 4000 }) expect(updated.step).toBe('scene_plan') db.close() }) })