返回 oh-my-ppt
workspace.test.ts
根目录 / tests / unit / thinking / workspace.test.ts
1 import fs from 'fs'
2 import os from 'os'
3 import path from 'path'
4 import { afterEach, describe, expect, it } from 'vitest'
5 import {
6 createWorkspace,
7 readWorkspace,
8 replaceThinkingPageOutline,
9 resolveThinkingDir,
10 writeMessagesList
11 } from '../../../src/main/thinking/workspace'
12
13 const tempDirs: string[] = []
14
15 async function makeStorageRoot(): Promise<string> {
16 const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'thinking-workspace-test-'))
17 tempDirs.push(dir)
18 return dir
19 }
20
21 describe('thinking workspace messages', () => {
22 afterEach(async () => {
23 await Promise.all(tempDirs.splice(0).map((dir) => fs.promises.rm(dir, { recursive: true, force: true })))
24 })
25
26 it('persists and restores sanitized chat messages', async () => {
27 const storageRoot = await makeStorageRoot()
28 const workspace = await createWorkspace(storageRoot)
29 const thinkingDir = resolveThinkingDir(storageRoot, workspace.thinkingId)
30
31 await writeMessagesList(thinkingDir, [
32 {
33 role: 'user',
34 content: '2026 ai短剧的发展',
35 timestamp: 1000
36 },
37 {
38 role: 'assistant',
39 content: '"topic": "2026年AI短剧的发展",\n "userIntent": "规划演示"\n}\n\n我已确认主题。',
40 timestamp: 1001
41 },
42 {
43 role: 'assistant',
44 content: 'context.md updated for stage collect.',
45 timestamp: 1002
46 }
47 ])
48
49 const restored = await readWorkspace(storageRoot, workspace.thinkingId)
50
51 expect(restored.messages).toEqual([
52 {
53 role: 'user',
54 content: '2026 ai短剧的发展',
55 timestamp: 1000
56 },
57 {
58 role: 'assistant',
59 content: '我已确认主题。',
60 timestamp: 1001
61 }
62 ])
63 })
64 })
65
66 describe('replaceThinkingPageOutline', () => {
67 it('updates only the selected page and keeps the remaining outline', () => {
68 const original = `# Thinking Brief
69
70 ## Topic
71 Quarterly review
72
73 ## Page 1: Cover
74 - Role: cover
75 - Objective: Introduce the review
76
77 Original summary
78
79 - Original point
80
81 ## Page 2: Results
82 - Role: data
83 - Objective: Present results
84
85 Keep this summary
86
87 - Keep this point
88
89 ## Appendix
90 Keep this section
91 `
92
93 const updated = replaceThinkingPageOutline(original, {
94 pageNumber: 1,
95 title: 'Executive Overview',
96 role: 'cover',
97 objective: 'Set the context for the review',
98 summary: 'Updated summary',
99 keyPoints: ['Updated point', 'Next point']
100 })
101
102 expect(updated).toContain('## Page 1: Executive Overview')
103 expect(updated).toContain('- Objective: Set the context for the review')
104 expect(updated).toContain('Updated summary')
105 expect(updated).toContain('- Updated point')
106 expect(updated).toContain('## Page 2: Results')
107 expect(updated).toContain('Keep this summary')
108 expect(updated).toContain('## Appendix\nKeep this section')
109 expect(updated).not.toContain('Original summary')
110 })
111
112 it('rejects incomplete page outlines', () => {
113 expect(() =>
114 replaceThinkingPageOutline('## Page 1: Cover\n', {
115 pageNumber: 1,
116 title: '',
117 role: 'cover',
118 objective: 'Introduce',
119 summary: 'Summary',
120 keyPoints: ['Point']
121 })
122 ).toThrow('Page outline fields cannot be empty')
123 })
124
125 it('preserves a non-page section after the edited page', () => {
126 const updated = replaceThinkingPageOutline(
127 `## Page 1: Cover
128 - Role: cover
129 - Objective: Introduce
130
131 Summary
132
133 - Point
134
135 ## Appendix
136 Keep this section
137 `,
138 {
139 pageNumber: 1,
140 title: 'New cover',
141 role: 'cover',
142 objective: 'Introduce the topic',
143 summary: 'New summary',
144 keyPoints: ['New point']
145 }
146 )
147
148 expect(updated).toContain('## Appendix\nKeep this section')
149 })
150 })
151
151 lines TYPESCRIPT