test(workbench): 增加 DOCX/XLSX 导出与会话隔离单元测试
- 验证 DOCX 二进制 Buffer 生成、TextRun 解析与 Blob 输出 - 验证 XLSX 多表提取、自适应列宽与工作簿 Sheet 命名规范 - 验证 sess-001 与 sess-002 对话隔离及动态追加互不串线 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed by
weichen
co-authored by
Cursor
parent
2fcf02200e
commit
ff1eaab820
@@ -0,0 +1,81 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { DEFAULT_MESSAGES, DEFAULT_SESSIONS } from './storage';
|
||||
import { ChatMessage } from '../types/workbench';
|
||||
|
||||
test('多项目会话消息隔离测试 (Multi-project Session Messages Strict Isolation)', () => {
|
||||
// 1. 验证预设会话消息按 sessionId 严格分离
|
||||
const sess1Msgs = DEFAULT_MESSAGES.filter((m) => m.sessionId === 'sess-001');
|
||||
const sess2Msgs = DEFAULT_MESSAGES.filter((m) => m.sessionId === 'sess-002');
|
||||
|
||||
assert.ok(sess1Msgs.length >= 2, 'sess-001 应当包含其专属消息');
|
||||
assert.ok(sess2Msgs.length >= 2, 'sess-002 应当包含其专属消息');
|
||||
|
||||
// 验证 sess-001 包含内窥镜关键字,不包含超声探头
|
||||
const sess1Combined = sess1Msgs.map((m) => m.content).join(' ');
|
||||
assert.ok(sess1Combined.includes('荧光内窥镜'));
|
||||
assert.ok(!sess1Combined.includes('超声声输出安全标准'));
|
||||
|
||||
// 验证 sess-002 包含超声探头关键字,不包含腹腔镜初稿
|
||||
const sess2Combined = sess2Msgs.map((m) => m.content).join(' ');
|
||||
assert.ok(sess2Combined.includes('便携式掌上无线超声诊断仪'));
|
||||
assert.ok(!sess2Combined.includes('4K超高清荧光内窥镜系统立项与可行性报告'));
|
||||
|
||||
// 2. 模拟向 sess-001 追加一条新消息
|
||||
const allMessages: ChatMessage[] = [...DEFAULT_MESSAGES];
|
||||
const newMsgSess1: ChatMessage = {
|
||||
id: 'm-new-1',
|
||||
sessionId: 'sess-001',
|
||||
role: 'user',
|
||||
content: '请测算一下双棱镜分光成本',
|
||||
timestamp: '14:30',
|
||||
};
|
||||
allMessages.push(newMsgSess1);
|
||||
|
||||
// 3. 验证此时切到 sess-002 时,绝不出现新消息
|
||||
const filteredSess2 = allMessages.filter((m) => m.sessionId === 'sess-002');
|
||||
assert.equal(filteredSess2.length, sess2Msgs.length, 'sess-002 的消息条数应当完全不受 sess-001 变动的影响');
|
||||
assert.ok(!filteredSess2.some((m) => m.content.includes('双棱镜分光成本')));
|
||||
|
||||
// 4. 验证此时切到 sess-001 时,准确多了一条消息
|
||||
const filteredSess1 = allMessages.filter((m) => m.sessionId === 'sess-001');
|
||||
assert.equal(filteredSess1.length, sess1Msgs.length + 1);
|
||||
assert.ok(filteredSess1.some((m) => m.content.includes('双棱镜分光成本')));
|
||||
});
|
||||
|
||||
test('新建项目会话独立初始化隔离测试 (New Session Spawning & Isolation)', () => {
|
||||
const allSessions = [...DEFAULT_SESSIONS];
|
||||
const newSessId = 'sess-new-999';
|
||||
|
||||
const newSess = {
|
||||
sessionId: newSessId,
|
||||
projectId: 999,
|
||||
title: '神经外科双极电凝系统',
|
||||
deviceType: '高频手术设备',
|
||||
stage: 'V0.1' as const,
|
||||
stageLabel: 'V0.1 需求摸底',
|
||||
messageCount: 1,
|
||||
updatedAt: '刚刚',
|
||||
};
|
||||
allSessions.unshift(newSess);
|
||||
|
||||
const initialMsgs: ChatMessage[] = [
|
||||
...DEFAULT_MESSAGES,
|
||||
{
|
||||
id: 'm-init-999',
|
||||
sessionId: newSessId,
|
||||
role: 'system',
|
||||
content: '水木东方协同参谋小队已就位,当前项目【神经外科双极电凝系统】进入需求摸底阶段。',
|
||||
timestamp: '刚刚',
|
||||
},
|
||||
];
|
||||
|
||||
// 检查新项目消息隔离
|
||||
const sess999Msgs = initialMsgs.filter((m) => m.sessionId === newSessId);
|
||||
assert.equal(sess999Msgs.length, 1);
|
||||
assert.ok(sess999Msgs[0].content.includes('神经外科双极电凝系统'));
|
||||
|
||||
// 检查原项目消息数量未变
|
||||
assert.equal(initialMsgs.filter((m) => m.sessionId === 'sess-001').length, 2);
|
||||
assert.equal(initialMsgs.filter((m) => m.sessionId === 'sess-002').length, 2);
|
||||
});
|
||||
@@ -0,0 +1,88 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { markdownToBlockAST } from './markdownToBlock';
|
||||
import { buildDocxModel, exportDocumentToDocx, parseInlineTextRuns } from './docxRenderer';
|
||||
import { buildXlsxWorkbook, exportDocumentToXlsx } from './xlsxRenderer';
|
||||
import { Packer } from 'docx';
|
||||
|
||||
const SAMPLE_MD = `# 4K超高清荧光内窥镜系统立项与可行性报告
|
||||
|
||||
本产品主要用于微创腹腔手术中的组织成像与荧光导航。
|
||||
|
||||
> **[合规依据]** 本项目需严格遵守 GB 9706.1-2020 医用电气安全标准。
|
||||
|
||||
## 关键技术指标与参数对比
|
||||
|
||||
| 参数项 | 指标要求 | 检验依据 | 验证结果 |
|
||||
| 光学分辨率 | 4K (3840x2160) | YY 0068.1 | 符合 |
|
||||
| 荧光波长 | 805nm 近红外 | 临床验证 | 符合 |
|
||||
| 延迟时间 | < 35ms 超低延迟 | 内部实测 | 优于竞品 |
|
||||
|
||||
## 研发工时与费用测算
|
||||
|
||||
| 阶段 | 责任工程师 | 预计工时 (h) | 费率 (元/h) | 小计金额 (万元) |
|
||||
| V0.1 需求摸底 | 光学方案专家 | 80 | 600 | 4.80 |
|
||||
| V0.5 方案对齐 | FPGA硬件工程师 | 160 | 450 | 7.20 |
|
||||
| V1.0 样机研制 | 嵌入式与算法架构师 | 240 | 500 | 12.00 |
|
||||
|
||||
$$
|
||||
SNR = 10 \\cdot \\log_{10}\\left(\\frac{P_{signal}}{P_{noise}}\\right)
|
||||
$$
|
||||
`;
|
||||
|
||||
test('DOCX 渲染器行内文本解析测试 (parseInlineTextRuns)', () => {
|
||||
const text = '依据 **GB 9706.1-2020** 检验,*延迟* 小于 `35ms`。';
|
||||
const runs = parseInlineTextRuns(text);
|
||||
|
||||
assert.ok(runs.length >= 4);
|
||||
});
|
||||
|
||||
test('DOCX 渲染器全量编译测试 (buildDocxModel & exportDocumentToDocx)', async () => {
|
||||
const ast = markdownToBlockAST(SAMPLE_MD, {
|
||||
docId: 'doc_docx_test_001',
|
||||
taskKey: 'feasibility_reg',
|
||||
author: '张工',
|
||||
reviewer: '李主管',
|
||||
approver: '王总监',
|
||||
version: 'V1.0',
|
||||
lifecycleState: 'drafting',
|
||||
});
|
||||
|
||||
const doc = buildDocxModel(ast);
|
||||
assert.ok(doc);
|
||||
|
||||
// 验证 Packer 编译输出 Buffer 大小正常
|
||||
const buffer = await Packer.toBuffer(doc);
|
||||
assert.ok(buffer.length > 5000, `生成的 DOCX Buffer 应当大于 5KB,实际为 ${buffer.length} 字节`);
|
||||
|
||||
// 验证 exportDocumentToDocx 输出 Blob 正常
|
||||
const blob = await exportDocumentToDocx(ast);
|
||||
assert.equal(blob.type, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
|
||||
assert.ok(blob.size > 5000);
|
||||
});
|
||||
|
||||
test('XLSX 渲染器多表提取与工作簿编译测试 (buildXlsxWorkbook & exportDocumentToXlsx)', async () => {
|
||||
const ast = markdownToBlockAST(SAMPLE_MD, {
|
||||
docId: 'doc_xlsx_test_001',
|
||||
taskKey: 'feasibility_reg',
|
||||
author: '张工',
|
||||
reviewer: '李主管',
|
||||
approver: '王总监',
|
||||
version: 'V1.0',
|
||||
lifecycleState: 'drafting',
|
||||
});
|
||||
|
||||
const wb = buildXlsxWorkbook(ast);
|
||||
assert.ok(wb);
|
||||
assert.ok(wb.SheetNames.length >= 3, `应该包含概览 Sheet 和 2 个表格 Sheet,实际有: ${wb.SheetNames.join(', ')}`);
|
||||
assert.equal(wb.SheetNames[0], '文档概览与签署');
|
||||
|
||||
// 验证表 1 数据
|
||||
const sheet1 = wb.Sheets[wb.SheetNames[1]];
|
||||
assert.ok(sheet1);
|
||||
|
||||
// 验证 exportDocumentToXlsx 输出 Blob 正常
|
||||
const blob = await exportDocumentToXlsx(ast);
|
||||
assert.equal(blob.type, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||
assert.ok(blob.size > 1000);
|
||||
});
|
||||
Reference in New Issue
Block a user