feat(w3): ship v1.4.0 export matrix, cockpit tasks, and focus ambient
Add ExportMatrixService for txt/md/docx/pdf, extend ExportModal, cockpit outline tasks, focus ambient sound, and E2E-PDF-01 with 134 passing unit tests. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { buildTxtExport, htmlToPlainParagraphs } from '../../src/main/lib/export-content'
|
||||
|
||||
describe('export-content', () => {
|
||||
it('htmlToPlainParagraphs splits paragraph tags', () => {
|
||||
const html = '<p>第一段。</p><p>第二段。</p>'
|
||||
expect(htmlToPlainParagraphs(html)).toEqual(['第一段。', '第二段。'])
|
||||
})
|
||||
|
||||
it('buildTxtExport includes chapter title and AI marker', () => {
|
||||
const txt = buildTxtExport([
|
||||
{
|
||||
id: '1',
|
||||
title: '第一章',
|
||||
volumeName: '卷一',
|
||||
paragraphs: ['正文内容。'],
|
||||
annotations: [],
|
||||
hasAiContent: true
|
||||
}
|
||||
])
|
||||
expect(txt).toContain('# 第一章')
|
||||
expect(txt).toContain('[AI生成内容]')
|
||||
expect(txt).toContain('正文内容。')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,58 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
||||
import { mkdtempSync, rmSync, existsSync, readFileSync } from 'fs'
|
||||
import { join } from 'path'
|
||||
import { tmpdir } from 'os'
|
||||
import { BookRegistryService } from '../../src/main/services/book-registry'
|
||||
import { GlobalSettingsService } from '../../src/main/services/global-settings'
|
||||
import { ExportMatrixService } from '../../src/main/services/export-matrix.service'
|
||||
import { closeAllBookDbs } from '../../src/main/db/connection'
|
||||
|
||||
describe('ExportMatrixService', () => {
|
||||
let userData: string
|
||||
let registry: BookRegistryService
|
||||
let settings: GlobalSettingsService
|
||||
let matrix: ExportMatrixService
|
||||
|
||||
beforeEach(() => {
|
||||
userData = mkdtempSync(join(tmpdir(), 'bilin-export-matrix-'))
|
||||
registry = new BookRegistryService(userData)
|
||||
settings = new GlobalSettingsService(userData)
|
||||
matrix = new ExportMatrixService(registry, settings)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
closeAllBookDbs()
|
||||
rmSync(userData, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
it('exports chapter as txt', async () => {
|
||||
const book = registry.create({ name: '导出矩阵书', category: '玄幻', createSampleChapter: true })
|
||||
registry.open(book.id)
|
||||
const chapter = registry.getChapterRepo(book.id).list()[0]
|
||||
registry.getChapterRepo(book.id).update(chapter.id, {
|
||||
content: '<p>矩阵导出测试正文。</p>'
|
||||
})
|
||||
|
||||
const dest = join(userData, 'chapter.txt')
|
||||
await matrix.exportToPath(
|
||||
{ bookId: book.id, scope: 'chapter', scopeId: chapter.id, format: 'txt' },
|
||||
dest
|
||||
)
|
||||
const text = readFileSync(dest, 'utf8')
|
||||
expect(text).toContain('矩阵导出测试正文')
|
||||
expect(existsSync(dest)).toBe(true)
|
||||
})
|
||||
|
||||
it('IT-DOCX-01: exports volume docx with table of contents marker', async () => {
|
||||
const book = registry.create({ name: 'Docx书', category: '玄幻', createSampleChapter: true })
|
||||
registry.open(book.id)
|
||||
const chapterRepo = registry.getChapterRepo(book.id)
|
||||
const ch = chapterRepo.list()[0]
|
||||
chapterRepo.update(ch.id, { title: '开篇', content: '<p>Docx正文。</p>' })
|
||||
|
||||
const dest = join(userData, 'book.docx')
|
||||
await matrix.exportToPath({ bookId: book.id, scope: 'book', format: 'docx' }, dest)
|
||||
expect(existsSync(dest)).toBe(true)
|
||||
expect(readFileSync(dest).length).toBeGreaterThan(1000)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user