Add showcase tests for PPT management, review, knowledge base replies, and service contracts
- Implemented `ppt-management-briefing-edit.showcase.test.ts` to test editing PPTs with AI assistance. - Created `ppt-management-briefing-review.showcase.test.ts` for reviewing PPTs generated by AI. - Added `xinghe-kb-reply.showcase.test.ts` to validate knowledge base replies against local documents. - Developed `xinghe-service-contract.showcase.test.ts` to test AI responses based on PDF contract queries. - Introduced shared utility functions in `shared.ts` for handling file operations and cost calculations. - Updated Vitest configuration to include new test paths for showcase cases.
This commit is contained in:
1 parent
203f8ab180
commit
d7e84edda9
18 files changed
+79
-195
No files matched your search
@@ -25,7 +25,6 @@
|
||||
- `doc/test-plan/ai-test.md`:涉及 AI 回归测试范围、live case 设计或 suite 覆盖维护时阅读。
|
||||
- `doc/test-plan/settings-test.md`:涉及 Settings 测试范围或测试边界时阅读。
|
||||
- `doc/test-plan/workbench-test.md`:涉及 Workbench 回归测试范围、真实 e2e case 设计、发送前置条件验证或 suite 覆盖维护时阅读。
|
||||
- `doc/test-plan/showcase-test.md`:涉及官网样例采集任务、采集 case 或 Showcase 命令时阅读。
|
||||
- `doc/test.md`:涉及测试体系、UI E2E 回归规则、runner 或回归测试流程时阅读。
|
||||
- `doc/tidy.md`:需要按周期整理文档、PRD、测试计划、测试用例或清理代码整洁度(死代码、兼容残留、无用代码、简洁性)时,先按其中流程审计并等待决策。
|
||||
|
||||
@@ -59,7 +58,6 @@
|
||||
│ ├── test-plan/ # 专项测试计划
|
||||
│ │ ├── ai-test.md # AI 回归测试计划
|
||||
│ │ ├── settings-test.md # Settings 测试计划
|
||||
│ │ ├── showcase-test.md # 官网样例采集计划
|
||||
│ │ └── workbench-test.md # Workbench 测试计划
|
||||
│ └── tidy.md # 周期性文档、测试与代码整理流程
|
||||
├── src/ # 应用源码
|
||||
@@ -75,10 +73,10 @@
|
||||
├── tests/ # 自动化测试
|
||||
│ ├── case/ # 测试用例
|
||||
│ │ ├── ai/ # AI 测试用例
|
||||
│ │ ├── showcase/ # 独立官网样例采集
|
||||
│ │ ├── settings/ # Settings 测试用例
|
||||
│ │ ├── unit/ # backend 单元测试
|
||||
│ │ └── workbench/ # Workbench 测试用例
|
||||
│ ├── showcase/ # 官网样例采集任务
|
||||
│ ├── fixtures/ # 长期复用测试输入
|
||||
│ │ ├── workspace/ # 工作区语义测试共享输入目录
|
||||
│ │ └── sqlite/ # SQLite 升级与版本门禁 fixture
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
# Showcase 样例采集计划
|
||||
|
||||
## 1. 定位
|
||||
|
||||
Showcase 是官网样例采集任务,不是产品回归、E2E 回归或发布门禁。它只通过 `pnpm test:showcase` 显式执行,不被 `pnpm test:e2e:*`、Workbench 回归命令或发布命令发现。
|
||||
|
||||
采集使用真实 Electron UI、真实 AI 和真实文件处理链路,目的是产出可审核的截图、样例文件和用量记录;采集失败不改变产品回归范围。
|
||||
|
||||
## 2. 目录与命令
|
||||
|
||||
采集文件位于:
|
||||
|
||||
```text
|
||||
tests/showcase/
|
||||
<case>.showcase.test.ts
|
||||
createSeeds.ts
|
||||
shared.ts
|
||||
```
|
||||
|
||||
运行全部采集任务:
|
||||
|
||||
```bash
|
||||
pnpm test:showcase
|
||||
```
|
||||
|
||||
只运行指定任务:
|
||||
|
||||
```bash
|
||||
pnpm test:showcase -- --case <caseId>
|
||||
```
|
||||
|
||||
运行日志写入 `tests/logs/showcase/collection/<caseId>/`,官网导出文件写入 `tests/logs/showcase/export/<caseId>/`。
|
||||
|
||||
## 3. 共同约束
|
||||
|
||||
- 每个任务必须创建隔离临时工作区,结束后清理。
|
||||
- 必须通过真实 Settings / Workbench UI 配置模型、创建伙伴和发送请求;不使用 fake AI、fake 工具结果或直接写入产品状态。
|
||||
- 新建样例可以把结果复制为 fixture;编辑样例必须复用已有过关 fixture,不能临时新建文件凑截图。
|
||||
- 每个任务记录截图、样例文件、模型、耗时和实际用量。
|
||||
- Showcase 不参与日常 E2E、正式包 E2E 或发布回归的默认发现;需要正式回归的产品能力必须另有 `tests/case/**` 回归 case。
|
||||
|
||||
## 4. 采集任务
|
||||
|
||||
### `docx-weekly-report`
|
||||
|
||||
- What:根据站会纪要、客户风险和财务草稿生成管理层 Word 周报。
|
||||
- How:真实 AI 写入 `云枢智服-9月第2周经营周报.docx`,截审核态和预览态。
|
||||
- Oracle:Word 可解析并包含进展、风险、下周计划;至少有一张审核图和一张预览图,并记录用量。
|
||||
|
||||
### `docx-weekly-report-edit`
|
||||
|
||||
- What:修改已有周报,采集审核态绿增红删。
|
||||
- How:必须使用过关 Word fixture,发送风险排序和负责人补充请求,截 `.docx-content`。
|
||||
- Oracle:产生真实 Word 修改记录和非零修改;至少有一张审核图,并记录用量。
|
||||
|
||||
### `excel-budget`
|
||||
|
||||
- What:从空工作区生成部门明细和汇总表组成的 9 月费用预算。
|
||||
- How:真实 AI 写入 `云枢智服-9月费用预算.xlsx`,按工作表截审核态和预览态。
|
||||
- Oracle:xlsx 可解析且至少两张表;至少有一张审核图和一张预览图,并记录用量。
|
||||
|
||||
### `excel-budget-edit`
|
||||
|
||||
- What:修改已有费用预算,采集审核态红绿框。
|
||||
- How:必须使用过关 Excel fixture,压低品牌推广金额并补充已发生列,截数据区域。
|
||||
- Oracle:文件包含已发生列和目标金额,存在非零修改,并记录用量。
|
||||
|
||||
### `ppt-management-briefing-review`
|
||||
|
||||
- What:从空工作区生成管理层经营简报,采集新增页面审核态。
|
||||
- How:真实 AI 创建 16:9 PPT,按缩略图截 `pptDiffAfter`。
|
||||
- Oracle:PPTX 写回且至少有一张审核图,并记录用量。
|
||||
|
||||
### `ppt-management-briefing-edit`
|
||||
|
||||
- What:修改已有经营复盘,采集修改前后对照。
|
||||
- How:必须使用过关 PPT fixture,修改封面和未达标 KPI,截审核态整块 diff。
|
||||
- Oracle:出现修改前后画布和至少一张审核图,并记录用量。
|
||||
|
||||
### `xinghe-service-contract`
|
||||
|
||||
- What:引用星河服务合同 PDF,回答尾款支付时间,采集原文页和回答。
|
||||
- How:只读引用 PDF,不改原件;渲染合同页并截最终回答。
|
||||
- Oracle:回答包含终验/验收后十个工作日;原件 bytes 不变;至少有两张原文图和一张回答图。
|
||||
|
||||
### `xinghe-kb-reply`
|
||||
|
||||
- What:根据本地星河资料回复交付承诺和验收口径。
|
||||
- How:准备星河资料和清和干扰资料,完成真实索引后不使用 `@` 文件名直接提问;截资料页和最终回答。
|
||||
- Oracle:使用本地知识库工具,不调用浏览器或网页搜索;回答包含 95% 承诺及验收 / P1 / 7 天依据。
|
||||
|
||||
### `court-typical-cases`
|
||||
|
||||
- What:用内置浏览器检索最高人民法院建设工程典型案例。
|
||||
- How:真实 AI 驱动内置浏览器,采集空白检索、已填词、结果三帧及最终回答。
|
||||
- Oracle:调用 `browser_use`;三类浏览器帧完整;回答涉及工程款、结算、违约或典型案例。
|
||||
|
||||
### `chailv-tax-deduction`
|
||||
|
||||
- What:搜索企业员工国内差旅住宿和交通税前扣除口径。
|
||||
- How:不指定网站,真实 AI 使用网页搜索,截带来源的最终回答。
|
||||
- Oracle:调用 `web_search`;回答包含住宿或交通、税前扣除和来源依据。
|
||||
@@ -2,29 +2,27 @@
|
||||
|
||||
## 1. 总体目标
|
||||
|
||||
- 本计划定义 Workbench 用户可见交互的回归范围,并对齐 [workbench.md](../prd/workbench.md) 的 `WB-*` 需求和验收编号。
|
||||
- 本计划定义 Workbench 用户可见交互的测试范围,并对齐 [workbench.md](../prd/workbench.md) 的 `WB-*` 需求和验收编号。
|
||||
- 通用测试、runner、raw logs、UI E2E 和 live 断言规则遵循 `doc/test.md`。
|
||||
- Workbench UI E2E 回归测试必须通过真实 Electron UI 配模型、创建伙伴、发送消息、选择 `@` 资料、预览、回退和操作右侧面板。设置页可另加文件地址,但发送不再要求绑定工作空间目录。
|
||||
- 涉及 AI 的 Workbench UI E2E 回归测试必须使用真实模型调用;live 配置只读内置服务商 Key 池与选中目标:`AI_LIVE_KEY_<PROVIDER>`(`DEEPSEEK` / `DASHSCOPE` / `MIMO` / `ZHIPU`)、可选 `AI_LIVE_PROVIDER`(默认 `dashscope`)、可选 `AI_LIVE_MODEL`(默认该服务商测试默认模型,通义为 `qwen3.8-flash`)。`baseUrl` / `providerKind` 由产品 registry 推导。日常 case 通过 Settings「推荐」类型写入当前目标服务商;全服务商冒烟见 `live-preset-provider-smoke`。
|
||||
- `provider-matrix` 与 `wps-office` 都是正式 E2E 回归范围内的 Workbench case;发布时按版本影响范围选择,影响面广时随正式 E2E 全量执行。Showcase 已独立为单独采集任务。
|
||||
- 发版回归按版本改动影响范围选择正式包 E2E;影响范围较广或无法可靠收敛时执行全部正式 E2E,包含 `provider-matrix` 和 `wps-office`。Showcase 不属于正式 E2E。
|
||||
- Workbench UI E2E 测试必须通过真实 Electron UI 配模型、创建伙伴、发送消息、选择 `@` 资料、预览、回退和操作右侧面板。设置页可另加文件地址,但发送不再要求绑定工作空间目录。
|
||||
- 涉及 AI 的 Workbench UI E2E 测试必须使用真实模型调用;live 配置只读内置服务商 Key 池与选中目标:`AI_LIVE_KEY_<PROVIDER>`(`DEEPSEEK` / `DASHSCOPE` / `MIMO` / `ZHIPU`)、可选 `AI_LIVE_PROVIDER`(默认 `dashscope`)、可选 `AI_LIVE_MODEL`(默认该服务商测试默认模型,通义为 `qwen3.8-flash`)。`baseUrl` / `providerKind` 由产品 registry 推导。日常 case 通过 Settings「推荐」类型写入当前目标服务商;全服务商冒烟见 `live-preset-provider-smoke`。
|
||||
- case 因生产行为缺口失败时,不在测试中硬改业务行为,统一记录为产品或生产实现待决项。
|
||||
|
||||
## 2. 测试边界
|
||||
|
||||
- Workbench UI E2E 回归测试通过脚本在 case 运行时把 `tests/fixtures/workspace` 复制到临时目录;需要文件资料时通过 Settings UI 添加文件地址、检查更新和更新索引。前置始终是创建伙伴;不断言工作区选择器、`.ncurator` 或 `__draft__`。
|
||||
- Workbench UI E2E 测试通过脚本在 case 运行时把 `tests/fixtures/workspace` 复制到临时目录;需要文件资料时通过 Settings UI 添加文件地址、检查更新和更新索引。前置始终是创建伙伴;不断言工作区选择器、`.ncurator` 或 `__draft__`。
|
||||
- Workbench 正式 e2e 不允许直接调用 `workspacePrepare`、直接写模型配置、fake model、fake search、fake docx、fake AI event、fake attachment pick 或固定 document id。
|
||||
- Workbench e2e 的 workspace 文件索引允许在测试环境通过 `NCURATOR_WORKSPACE_KNOWLEDGE_CACHE=1` 启用真实 split / vector 缓存;缓存只按文件内容 hash、扩展名、splitter 参数和 embedding model 复用计算结果,不替代 workspace 文件记录、document id、搜索结果或 UI 状态。Source E2E 直接共享内容缓存并按 case 隔离统计;Source 与正式包 E2E 在多 case 时都先执行 `warmup` 预热共享 fixture,正式包 E2E 再把缓存种子复制给隔离 case。
|
||||
- Workbench 模型选择 helper 优先按预设 option 的稳定调用名 `data-testid`(`AI_LIVE_MODEL`)点选;未命中再按展示名;仍未命中则进入「自定义模型」按名称搜索。
|
||||
- Workbench UI E2E 回归测试需要真实索引完成信号和 UI 可见状态作为等待条件;IPC observer 和 job 查询只能作为辅助证据,不能用来造业务状态。
|
||||
- `file-preview-actions` 当前按生产真实索引能力覆盖 `pdf/docx/md/txt/xlsx/xlsm/xltx/xltm`:连续打开的文件要分别保留为资源 Tab,并能切回旧 Tab;Excel 普通预览还要覆盖只读、切 Sheet 和拖列宽后预览仍可用。`workspace-file-explorer-open-refresh` 覆盖工作区文件列表在打开时重新读取磁盘最新目录(含外部新建文件)。`file-preview-external-change-auto-refresh` 另行覆盖所有实时预览的统一磁盘监听:以普通文本、DOCX、PPTX、XLSX 为代表验证,文件地址内的文件和 `userData/partners/{id}/runtime/assets` 中的真实附件复用同一预览刷新链路;审核 Diff 快照不监听;仅文件内容变化才提示“已自动刷新”,打开外部应用或仅元数据变化不提示。WPS 刷新分两条:正式回归由 `wps-sync-dispatch-on-write-and-revert` 覆盖馆长对 docx / xlsx / pptx 的 `/status` dispatch,不打开 WPS;真窗口刷新 `wps-office-reload-on-write-and-revert` 在路径 `result/wps-office/`,属于正式 E2E,支持 `pnpm test:workbench:wps-office` 单独执行,因本机授权弹窗可能卡住自动化。正式 E2E 启动时跳过覆盖拷加载项文件,但会启动回环 `/addon`;`publish.xml` 与授权 path 固定 `http://127.0.0.1:18723/addon/`,端口文件记录实际监听端口。若 `18723` 上已是本馆长 `/status` 通道,后启动实例不得把 `publish.xml` / 授权 path 改到临时端口。安装器与 `publish.xml` / `authaddin` 合并由 unit 覆盖。
|
||||
- Workbench UI E2E 测试需要真实索引完成信号和 UI 可见状态作为等待条件;IPC observer 和 job 查询只能作为辅助证据,不能用来造业务状态。
|
||||
- `file-preview-actions` 当前按生产真实索引能力覆盖 `pdf/docx/md/txt/xlsx/xlsm/xltx/xltm`:连续打开的文件要分别保留为资源 Tab,并能切回旧 Tab;Excel 普通预览还要覆盖只读、切 Sheet 和拖列宽后预览仍可用。`workspace-file-explorer-open-refresh` 覆盖工作区文件列表在打开时重新读取磁盘最新目录(含外部新建文件)。`file-preview-external-change-auto-refresh` 另行覆盖所有实时预览的统一磁盘监听:以普通文本、DOCX、PPTX、XLSX 为代表验证,文件地址内的文件和 `userData/partners/{id}/runtime/assets` 中的真实附件复用同一预览刷新链路;审核 Diff 快照不监听;仅文件内容变化才提示“已自动刷新”,打开外部应用或仅元数据变化不提示。WPS 刷新分两条:正式测试由 `wps-sync-dispatch-on-write-and-revert` 覆盖馆长对 docx / xlsx / pptx 的 `/status` dispatch,不打开 WPS;真窗口刷新 `wps-office-reload-on-write-and-revert` 在路径 `result/wps-office/`,属于正式 E2E,支持 `pnpm test:workbench:wps-office` 单独执行,因本机授权弹窗可能卡住自动化。正式 E2E 启动时跳过覆盖拷加载项文件,但会启动回环 `/addon`;`publish.xml` 与授权 path 固定 `http://127.0.0.1:18723/addon/`,端口文件记录实际监听端口。若 `18723` 上已是本馆长 `/status` 通道,后启动实例不得把 `publish.xml` / 授权 path 改到临时端口。安装器与 `publish.xml` / `authaddin` 合并由 unit 覆盖。
|
||||
- docx apply case 需要真实 docx 输入、真实 AI 编辑、真实写回记录、真实预览和真实回退。
|
||||
- text-file apply case 需要真实 Markdown 或代码文件、真实 `text_file_edit`、真实结构化 diff、独立 `TextFileDiffViewer` 和按原始 bytes 回退。
|
||||
- image generation apply case 需要真实模型先学习外置 `image-generation` 技能、真实调用 `image_generate`、生成可解码图片、展示修改入口和图片预览,并完成新建图片回退。
|
||||
- `browser-use-task-panel` 需要真实 AI run 触发 `browser_use` 并驱动内置浏览器完成本地内容输入与 hover-退出网页任务(observe→actionId act,支持 text 注入);必须在无进程级远程调试口下完成。同时验证多个浏览器 Tab 独立历史、共享持久站点数据、切换文件后网页状态不销毁,以及同 URL 标签不会让 Stagehand 串页,不能用 fake browser 替代。
|
||||
- `web_search` 单独覆盖:搜索 case 验证 type=search 后 type=fetch 读取网页正文;直接 URL case 验证 type=fetch 读取网页正文后再回答。两类 case 均不得因 `web_search` 自动展开右侧搜索列表(该列表面板已不存在),对齐 `WB-CORE-007-AC4`。Composer 搜索模式与右侧搜索列表面板已删除,废弃 `WB-COMPOSER-004`、`WB-PANEL-002`。
|
||||
- Workbench 附件链路不限文件扩展名,任何可被文件选择器选中的普通文件都可以添加,不因扩展名拒绝;`+` 和拖放保留源文件绝对路径,粘贴文件保存到 `userData/partners/{id}/runtime/assets/<assetBucketId>/`。`assetBucketId` 为输入草稿 UUID,发送给 AI 时只传附件名称与路径,不再做发送前识图或文件解析;文件是否可被 AI 工具处理由 AI 工具层自行判断。无伙伴时空态 Composer 不接受附件。
|
||||
- Excel / PPT / DOCX / PDF 工具的输入输出、operation、原子失败与 diff artifact 语义由 AI tool 回归承担;Workbench apply case 只验证真实用户流程、预览入口、审核交互与回退,不重复枚举底层操作矩阵。其中 Excel 工具侧覆盖 `WB-EXCEL-001-AC3`、`WB-EXCEL-001-AC4`、`WB-EXCEL-001-AC6`、`WB-EXCEL-001-AC7`、`WB-EXCEL-002-AC2`、`WB-EXCEL-002-AC3`、`WB-EXCEL-002-AC5`、`WB-EXCEL-002-AC6`、`WB-EXCEL-002-AC7`、`WB-EXCEL-002-AC8`(`WB-EXCEL-002-AC3` 记录/baseline **只在 ai-test 硬断言**);Workbench e2e 覆盖 `WB-EXCEL-001-AC5`、`WB-EXCEL-002-AC1`、`WB-EXCEL-002-AC4`、`WB-EXCEL-002-AC9` 用户闭环(UI 可见单入口,不重复硬断言 AC3)。
|
||||
- Excel / PPT / DOCX / PDF 工具的输入输出、operation、原子失败与 diff artifact 语义由 AI tool 测试承担;Workbench apply case 只验证真实用户流程、预览入口、审核交互与回退,不重复枚举底层操作矩阵。其中 Excel 工具侧覆盖 `WB-EXCEL-001-AC3`、`WB-EXCEL-001-AC4`、`WB-EXCEL-001-AC6`、`WB-EXCEL-001-AC7`、`WB-EXCEL-002-AC2`、`WB-EXCEL-002-AC3`、`WB-EXCEL-002-AC5`、`WB-EXCEL-002-AC6`、`WB-EXCEL-002-AC7`、`WB-EXCEL-002-AC8`(`WB-EXCEL-002-AC3` 记录/baseline **只在 ai-test 硬断言**);Workbench e2e 覆盖 `WB-EXCEL-001-AC5`、`WB-EXCEL-002-AC1`、`WB-EXCEL-002-AC4`、`WB-EXCEL-002-AC9` 用户闭环(UI 可见单入口,不重复硬断言 AC3)。
|
||||
- DOCX 读取结果和历史结果按递归 children 树展示,Workbench 必须能显示统一的 `nodeId`、visual kind、`imagePath` 和 story;DOCX 写结果复用统一状态展示,普通写入不展示冗余正文,创建操作只展示 `createdIds`。格式操作按 text、paragraph、table、row、cell、section 展示。图片理解统一由 `agent-control` 内置的 `read_image` 把图片加入主模型请求。
|
||||
- Workbench 历史只展示白名单内的必要 DOCX 字段,不展示 worker、identity 或 replay 内部状态。DOCX 事件以 `nodeId` 定位,PPT 继续使用自己的 `location`,两套协议互不复用。
|
||||
|
||||
@@ -46,16 +44,16 @@ Workbench 顶层 suite 按用户任务闭环划分,不逐一复制 PRD 小节
|
||||
- Workbench 测试全部是 `e2e`,覆盖 Electron、renderer、IPC、真实 AI、右侧面板和文件系统联动。
|
||||
- 涉及 AI 的 case 必须记录模型、耗时、完成度评分和失败归因;Oracle 引用 [workbench.md](../prd/workbench.md) 的需求或验收编号。
|
||||
- AI 内置浏览器 case 必须验证右侧浏览器面板、网页操作结果和最终 assistant 输出形成闭环,不能只验证面板出现。
|
||||
- docx apply 相关 case 必须使用真实 docx 文件验证预览与回退;仅写入 `.docx` 后缀文本文件不满足回归 case 口径。
|
||||
- docx apply 相关 case 必须使用真实 docx 文件验证预览与回退;仅写入 `.docx` 后缀文本文件不满足测试 case 口径。
|
||||
- 依赖本地文件语义的测试统一复用 `tests/fixtures/workspace` 作为共享输入目录,但该目录只作为真实输入文件来源;运行时通过设置页添加为文件地址,并先创建伙伴。
|
||||
- `How` 和 `Oracle` 必须映射到 [workbench.md](../prd/workbench.md) 的需求或验收编号。
|
||||
- `WB-BLOCKER-003`(上下文压缩提示)依赖真实模型使用量与正式压缩阈值触发,运行成本不确定,不作为每次源码回归的固定 case,发布时按影响评估单独执行真实检查,检查运行中与完成态过程组,且不得为 E2E 降低生产阈值或伪造 compaction 事件。压缩阈值随当前模型 effectiveWindow(`min(256000, floor(modelContext × 0.8))`)。
|
||||
- `WB-WPS-001` 正式 E2E 由 `wps-sync-dispatch-on-write-and-revert` 覆盖馆长对 docx / xlsx / pptx 写盘后的 open dispatch;真窗口刷新由 `wps-office-reload-on-write-and-revert`(`pnpm test:workbench:wps-office`)覆盖已授权 WPS 文字 / 表格 / 演示,发布时按影响范围选择,正式 E2E 全量回归包含该组。已打开文档在写盘前由加载项 close 放锁,加载项复查文档确实已关闭才上报成功,关不掉则上报失败且馆长不写盘;写盘前等到文件可写,写成功后再刷新窗口。通道按 close-result 的 `remaining` 与占位文档是否建起来选择,不得用 SSE 是否断开判断;`remaining` 为 0 且占位已建起时仍走加载项 open,占位建不起来才用对应组件 exe 拉起并轮询 list 要摘录,不得 `cmd start`;被指派实例 open 失败或超时降级为一次系统打开。未安装 WPS 或对应组件加载项未授权时后者跳过该格式;已授权却连不上则算该格式失败,不得只测 docx 就当作三种格式都过。Workbench e2e 启动时跳过覆盖拷加载项文件,仍启动回环 `/addon`;`publish.xml` 与授权 path 固定优先端口 `18723`,不得改写到临时端口。xlsx / pptx 窗口刷新还要求 `/status` 的 `clients` 出现 `et` / `wpp`,不能只靠文字组件。加载项不得探测其他组件 `Active*` 对象;同组件多实例时 close / open 只投给持有该文档的 `clientId`,旧实例的文档列表和失败回报都不得影响当前实例。
|
||||
- `WB-BLOCKER-003`(上下文压缩提示)依赖真实模型使用量与正式压缩阈值触发,运行成本不确定,不作为每次源码测试的固定 case,发布时按影响评估单独执行真实检查,检查运行中与完成态过程组,且不得为 E2E 降低生产阈值或伪造 compaction 事件。压缩阈值随当前模型 effectiveWindow(`min(256000, floor(modelContext × 0.8))`)。
|
||||
- `WB-WPS-001` 正式 E2E 由 `wps-sync-dispatch-on-write-and-revert` 覆盖馆长对 docx / xlsx / pptx 写盘后的 open dispatch;真窗口刷新由 `wps-office-reload-on-write-and-revert`(`pnpm test:workbench:wps-office`)覆盖已授权 WPS 文字 / 表格 / 演示,发布时按影响范围选择,正式 E2E 全量测试包含该组。已打开文档在写盘前由加载项 close 放锁,加载项复查文档确实已关闭才上报成功,关不掉则上报失败且馆长不写盘;写盘前等到文件可写,写成功后再刷新窗口。通道按 close-result 的 `remaining` 与占位文档是否建起来选择,不得用 SSE 是否断开判断;`remaining` 为 0 且占位已建起时仍走加载项 open,占位建不起来才用对应组件 exe 拉起并轮询 list 要摘录,不得 `cmd start`;被指派实例 open 失败或超时降级为一次系统打开。未安装 WPS 或对应组件加载项未授权时后者跳过该格式;已授权却连不上则算该格式失败,不得只测 docx 就当作三种格式都过。Workbench e2e 启动时跳过覆盖拷加载项文件,仍启动回环 `/addon`;`publish.xml` 与授权 path 固定优先端口 `18723`,不得改写到临时端口。xlsx / pptx 窗口刷新还要求 `/status` 的 `clients` 出现 `et` / `wpp`,不能只靠文字组件。加载项不得探测其他组件 `Active*` 对象;同组件多实例时 close / open 只投给持有该文档的 `clientId`,旧实例的文档列表和失败回报都不得影响当前实例。
|
||||
- WPS 相关 e2e 必须自带环境归零:进用例前和用例结束后各做一次「先不带 `/F` 请求关闭 wps / et / wpp,超时再强杀」,并清掉 `ncurator-workbench-wps-*` 临时工作区;三种格式之间也要归零。不归零时上一轮残留实例会连上本轮回环冒充本轮客户端,让 registry、dispatch 与断言随机失败,且临时工作区因文件锁删不掉。
|
||||
|
||||
## 4. 目录与命令
|
||||
|
||||
Workbench 回归测试目录:
|
||||
Workbench 测试目录:
|
||||
|
||||
```text
|
||||
tests/case/workbench/
|
||||
@@ -65,7 +63,7 @@ tests/case/workbench/
|
||||
timeline/
|
||||
message/
|
||||
scope/
|
||||
provider-matrix/ # 正式 E2E:发版按影响范围或全量回归
|
||||
provider-matrix/ # 正式 E2E:发版按影响范围或全量测试
|
||||
run/
|
||||
process/
|
||||
blocker/
|
||||
@@ -74,16 +72,16 @@ tests/case/workbench/
|
||||
result/
|
||||
preview/
|
||||
apply/
|
||||
wps-office/ # 正式 E2E:真开 WPS;发版按影响范围或全量回归
|
||||
wps-office/ # 正式 E2E:真开 WPS;发版按影响范围或全量测试
|
||||
scheduled-task/
|
||||
```
|
||||
|
||||
回归测试命令:
|
||||
测试命令:
|
||||
|
||||
- `pnpm test:workbench`
|
||||
- `pnpm test:workbench:e2e`
|
||||
- `pnpm test:workbench:provider-matrix`(全服务商冒烟,可单独执行;发版按影响范围或全量回归)
|
||||
- `pnpm test:workbench:wps-office`(本机已授权 WPS,可单独执行;发版按影响范围或全量回归)
|
||||
- `pnpm test:workbench:provider-matrix`(全服务商冒烟,可单独执行;发版按影响范围或全量测试)
|
||||
- `pnpm test:workbench:wps-office`(本机已授权 WPS,可单独执行;发版按影响范围或全量测试)
|
||||
|
||||
自动更新模拟(聚合入口,不证明真实安装成功):
|
||||
|
||||
@@ -101,12 +99,12 @@ pnpm test:update:e2e
|
||||
|
||||
补充规则:
|
||||
|
||||
- `pnpm test:workbench:e2e` 是 Workbench UI 源码 E2E 回归测试入口。
|
||||
- `pnpm test:workbench:e2e` 是 Workbench UI 源码 E2E 测试入口。
|
||||
- 需要验证正式安装包时,调试使用 `pnpm test:e2e:package -- --bundle <release-bundle.json>`;它会校验并安装已构建候选包,再对安装后的真实应用执行所选正式 E2E,不重新构建。发布时通过 `release:win` / `release:mac` 的 `--test-only` 按影响评估选择范围,不带过滤参数时执行全部正式 E2E。
|
||||
- `conversation / run / result / scheduled-task` 是稳定 suite,不因 PRD 小节增删而轻易重排。
|
||||
- suite 下的 `partner / composer / timeline / message / scope / process / blocker / browser / persistence / preview / apply` 是 group,只在同一 suite 内用于收敛相近 case。不存在 `search/` 目录。
|
||||
|
||||
## 5. 回归测试清单
|
||||
## 5. 测试清单
|
||||
|
||||
### 5.1 `conversation`
|
||||
|
||||
@@ -243,7 +241,7 @@ pnpm test:update:e2e
|
||||
- Why:日常全量 live 只跑 `AI_LIVE_PROVIDER`/`AI_LIVE_MODEL` 选定目标;需要单独 smoke 覆盖「有 Key 的全部内置服务商」连通性。
|
||||
- How:读取 `listConfiguredLiveLlmTargets()`;为每个目标走 Settings UI 创建推荐服务商;创建伙伴后依次点预设 option(不得走自定义搜索兜底)并发送「你好」,等待 run 完成。
|
||||
- Oracle:每个已配置 Key 的服务商都有非空最终回答;未配置 Key 的服务商不参与、不失败。
|
||||
- Not:不评价回答质量;正式 E2E 全量回归包含本 case,也可用 `pnpm test:workbench:provider-matrix` 或 `--case live-preset-provider-smoke` 单独执行。
|
||||
- Not:不评价回答质量;正式 E2E 全量测试包含本 case,也可用 `pnpm test:workbench:provider-matrix` 或 `--case live-preset-provider-smoke` 单独执行。
|
||||
|
||||
#### `user-message-actions`
|
||||
|
||||
@@ -258,10 +256,10 @@ pnpm test:update:e2e
|
||||
|
||||
- 测试类型:`e2e / live`
|
||||
- What:`+`、粘贴与拖入中间聊天区添加附件时,图片只以路径和元数据进入伙伴消息记录,常规文档和非白名单扩展名也能加入,并保持图片预览、文件打开、删除、普通文本粘贴和大文件提示行为。粘贴保存到伙伴 runtime assets。
|
||||
- Why:`+` 与拖放必须把源文件路径交给 AI,粘贴仍需保存副本,回归必须守住这两条不同链路。
|
||||
- Why:`+` 与拖放必须把源文件路径交给 AI,粘贴仍需保存副本,测试必须守住这两条不同链路。
|
||||
- How:创建伙伴;需要文件资料时通过设置页添加文件地址;通过系统文件窗口选择图片和多种文件,覆盖拖入、删除后重新添加图片、大文件 warning,并通过真实模型发送一次带附件消息;发送后读取 `ai_run` 与 log 投影消息。
|
||||
- Oracle:文件拖入中间聊天区时显示覆盖层,放下后消失;无伙伴时不添加附件;`+` 选择的文件保留原始源路径;粘贴文件落到 `userData/partners/{id}/runtime/assets/`;图片预览和删除正常;发送后图片附件仍是路径,持久消息不含 Base64,对齐 `WB-COMPOSER-010`、`WB-COMPOSER-013-AC2`、`WB-COMPOSER-013-AC3`;运行时缓存、HTTP(S) 原地址和失效占位由 AI tool 契约覆盖,对齐 `WB-COMPOSER-013-AC4`。
|
||||
- Not:不在跨平台业务回归中验证系统原生文件选择器的视觉细节;不通过 `attachmentPickResponse` 或直接 `attachmentSaveFile` 伪造附件结果。
|
||||
- Not:不在跨平台业务测试中验证系统原生文件选择器的视觉细节;不通过 `attachmentPickResponse` 或直接 `attachmentSaveFile` 伪造附件结果。
|
||||
|
||||
#### `reference-mention-keyboard`
|
||||
|
||||
@@ -285,7 +283,7 @@ pnpm test:update:e2e
|
||||
|
||||
- 测试类型:`e2e`
|
||||
- What:空伙伴输入区布局、右侧默认无占位折叠、标签栏密度与折叠入口、Tab 溢出滚动、伙伴级标签和展开状态恢复、中间|右分隔条拖拽与阈值吸合、窗口缩放时主区比例同步、浏览器缩放菜单、地址栏“前往”与“将打开外部浏览器”按钮。
|
||||
- Why:右侧资源工作台和聊天输入区共享窗口高度与标题栏命中区域,普通功能测试无法发现输入框被推出窗口、折叠按钮放错区域、Tab 无法滚动、分隔条拖拽/吸合失效或原生浏览器遮挡浮层等视觉交互回归。
|
||||
- Why:右侧资源工作台和聊天输入区共享窗口高度与标题栏命中区域,普通功能测试无法发现输入框被推出窗口、折叠按钮放错区域、Tab 无法滚动、分隔条拖拽/吸合失效或原生浏览器遮挡浮层等视觉交互测试。
|
||||
- How:直接进入真实 Workbench,先确认无伙伴空态右侧 shell 不存在并测量输入区位置;创建伙伴后展开右侧,拖拽中间|右分隔条确认宽度实时变化,拖至阈值以下确认立即吸合折叠;拉宽窗口确认中间与右侧按同一比例同步变宽;在 A/B 伙伴分别创建不同标签并设置不同活动标签和展开状态,来回切换;再连续创建八个浏览器 Tab 验证滚动和菜单。
|
||||
- Oracle:各伙伴恢复自己的标签、活动状态和展开状态;右侧宽度比例、分隔条与吸合对齐 `WB-PANEL-001-AC10`(含 macOS 窗口边缘 live-resize 限帧与缩放期关闭面板 transition);无消息时输入区保持居中,有消息后输入区固定在主区底部,对齐 `WB-COMPOSER-009-AC11`;其余布局、动画、滚动和菜单要求不变,对齐 `WB-PANEL-001`、`WB-SESSION-008`。
|
||||
- Not:不验证公网网页、模型回答质量或系统窗口按钮本身;Stagehand targetId、共享持久分区和历史恢复继续由 `browser-use-task-panel` 覆盖。
|
||||
@@ -611,9 +609,9 @@ pnpm test:update:e2e
|
||||
|
||||
#### `wps-office-reload-on-write-and-revert`
|
||||
|
||||
- 测试类型:`e2e / exclusive`(路径 `result/wps-office/`;可单独执行,发版按影响范围选择或随全量回归)
|
||||
- 测试类型:`e2e / exclusive`(路径 `result/wps-office/`;可单独执行,发版按影响范围选择或随全量测试)
|
||||
- What:本机已授权的 WPS 打开目标 docx、xlsx、pptx 后,真实 AI 写回/回退让对应组件加载项先 close 放锁再写盘再 open,窗口摘录分别含标记和恢复原文。
|
||||
- Why:只证明馆长 dispatch 不能证明用户看到的 WPS 窗口已换新稿。Windows 上 WPS 独占锁必须先 close 才能写盘。文字、表格、演示是独立客户端,只测 docx 不能证明 Excel / PPT 窗口会刷新。授权弹窗可能卡住无人值守自动化,因此提供单独命令;发版时按影响范围选择,发版全量回归包含该 case。
|
||||
- Why:只证明馆长 dispatch 不能证明用户看到的 WPS 窗口已换新稿。Windows 上 WPS 独占锁必须先 close 才能写盘。文字、表格、演示是独立客户端,只测 docx 不能证明 Excel / PPT 窗口会刷新。授权弹窗可能卡住无人值守自动化,因此提供单独命令;发版时按影响范围选择,发版全量测试包含该 case。
|
||||
- How:执行 `pnpm test:workbench:wps-office` 或 `--case wps-office-reload-on-write-and-revert`。不覆盖拷加载项、不点授权、不用辅助功能点 UI。进用例前先做 WPS 环境归零(不带 `/F` 请求关闭 wps / et / wpp,超时再强杀,然后清 `ncurator-workbench-wps-*` 临时工作区),否则上一轮残留实例会冒充本轮客户端。馆长回环先起来;`publish.xml` 与授权 path 保持 `http://127.0.0.1:18723/addon/`。若回环不在优先端口 `18723`(说明本机另有馆长占用),跳过整案,因为已打开的 WPS 仍从优先端口拉加载项。独占 `18723` 时,对 `sample-edit.docx`、`经营周报.xlsx`、`品牌策略提案.pptx` 分别用本机 WPS 打开临时工作区文件:macOS 走 `open -a`;Windows 按注册表 `InstallRoot` 与默认安装目录解析启动器 / 对应组件 exe(`wps.exe` / `et.exe` / `wpp.exe`),进程拉起后立即返回、不等待 WPS 退出。等待 `/status` 出现对应组件客户端(`wps` / `et` / `wpp`)且该文档已登记。再通过真实 Workbench UI 发送编辑;写盘前加载项 close 并上报 `remaining`,馆长等到文件锁释放再写盘;写回后读该路径 `reload-result` 摘录含标记,回退后摘录不含标记。标记落点必须在加载项摘录采样范围内(xlsx 指定写 `H1`,不能让模型自选任意空白单元格,否则摘录读不到),摘录采样为表格 200 行 × 50 列、演示前 10 页、单次上限 20000 字符。`remaining` 为 0 时由占位文档撑住组件进程后继续走加载项 open;占位建不起来才用对应组件 exe 拉起(不得 `cmd start` 把表格/演示塞进已打开的文字窗口),再经 list 轮询取摘录、不再二次 Open;被指派实例报 open 失败或超时则降级一次系统打开。每种格式跑完立即归零 WPS,下一种格式从空环境开始;单种格式失败只记该格式失败并继续跑后面的格式,不得让 docx 或 xlsx 的问题把 pptx 挡在门外。本机未装 WPS、或该组件 `authaddin` 未授权则跳过该格式;该组件已授权但约 90 秒内加载项未连接则该格式失败。三种格式都未授权才跳过整案。
|
||||
- Oracle:磁盘写回含标记、回退恢复原文;已授权的每种格式都必须给出结论,加载项 `reload-result` 写回后摘录含标记、回退后不含标记,对齐 `WB-WPS-001-AC1`、`WB-WPS-001-AC2`、`WB-WPS-001-AC3`。断言数据按格式列出 covered / failed 及失败原因,任一已授权格式未 covered 即失败。未连接时不发 close;刷新失败不回滚已成功写盘,对齐 `WB-WPS-001-AC4`。超时报错必须带上 `clientId`、已登记文档和被拒的 close / open 回报原因,便于区分「投错实例」和「组件真的打不开」。用例结束后在删除临时工作区前先归零 WPS,清理目录遇到占用不作为失败。
|
||||
- Not:不断言授权弹窗文案、功能区页签肉眼可见或滚动恢复。`WB-WPS-001-AC5` 只作为未授权跳过说明。验收以 `/status` 为准。
|
||||
@@ -656,7 +654,7 @@ pnpm test:update:e2e
|
||||
|
||||
### 5.4 `scheduled-task`
|
||||
|
||||
定时任务回归单独归类,Oracle 引用 [`workbench.md`](../prd/workbench.md) 的 `ST-*` 编号。调度触发时点由真实程序运行与系统时间决定,case 通过「下一分钟」级别的短周期调度验证端到端触发,不伪造系统时钟。下列 AC 由 unit `tests/case/unit/scheduled-task-service.test.ts` 承担,不进入 Workbench E2E 发现范围:`ST-PARTNER-001-AC2`、`ST-RUN-001-AC3`、`ST-RUN-001-AC4`、`ST-RUN-003-AC1/AC2`、`ST-RUN-004-AC2/AC3`、`ST-RUN-005-AC1/AC2/AC3`。`ST-PARTNER-001-AC1`(删除专属伙伴后任务仍在)标为不测。
|
||||
定时任务测试单独归类,Oracle 引用 [`workbench.md`](../prd/workbench.md) 的 `ST-*` 编号。调度触发时点由真实程序运行与系统时间决定,case 通过「下一分钟」级别的短周期调度验证端到端触发,不伪造系统时钟。下列 AC 由 unit `tests/case/unit/scheduled-task-service.test.ts` 承担,不进入 Workbench E2E 发现范围:`ST-PARTNER-001-AC2`、`ST-RUN-001-AC3`、`ST-RUN-001-AC4`、`ST-RUN-003-AC1/AC2`、`ST-RUN-004-AC2/AC3`、`ST-RUN-005-AC1/AC2/AC3`。`ST-PARTNER-001-AC1`(删除专属伙伴后任务仍在)标为不测。
|
||||
|
||||
#### `scheduled-task-view-entry-and-isolation`
|
||||
|
||||
|
||||
+24
-39
@@ -5,7 +5,6 @@
|
||||
- 本文是 NCurator-Desktop 的唯一测试总规范。
|
||||
- 各业务域的 suite、case 和领域规则只在对应 `doc/test-plan/**` 中维护,本文不重复登记 case。
|
||||
- `ai-test` 专门覆盖 AI 架构及其工具,全部是 backend;`settings-test` 和 `workbench-test` 专门覆盖对应 PRD 功能点,全部是 E2E;Unit 只补足前述范围未覆盖的 backend 函数、类和底层逻辑。
|
||||
- Showcase 是独立的显式采集任务,不属于产品回归或 E2E 集合;使用独立目录和 `pnpm test:showcase` 命令,范围只在 `doc/test-plan/showcase-test.md` 维护。
|
||||
|
||||
测试体系只沉淀一层长期执行产物:
|
||||
|
||||
@@ -17,17 +16,14 @@
|
||||
|
||||
### 2.1 测试分类
|
||||
|
||||
- 回归测试
|
||||
- 测试用例
|
||||
- 列入 `doc/test-plan/**`,放在 `tests/case/<domain>/<suite>/**`。
|
||||
- 用于长期维护、批量执行和生成可追溯运行产物。
|
||||
- 显式采集任务
|
||||
- 登记在 `doc/test-plan/showcase-test.md`,放在 `tests/showcase/**`。
|
||||
- 使用独立采集命令,不能被回归 runner 或发布命令发现。
|
||||
- `unit`
|
||||
- 放在 `tests/case/unit/**`。
|
||||
- 全部是 backend 单元测试,不允许导入 Renderer、React、jsdom 或 Electron UI。
|
||||
- 不进入 `doc/test-plan/**`,由 unit runner 独立发现和执行。
|
||||
- 不落测试文件的排查不属于测试文档治理对象;新增测试文件前必须先确认归入 AI、Settings、Workbench、Unit 或 Showcase。
|
||||
- 不落测试文件的排查不属于测试文档治理对象;新增测试文件前必须先确认归入 AI、Settings、Workbench 或 Unit。
|
||||
|
||||
### 2.2 目录结构
|
||||
|
||||
@@ -40,20 +36,18 @@ tests/
|
||||
unit/
|
||||
settings/
|
||||
workbench/
|
||||
showcase/
|
||||
logs/
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
- 目录使用 kebab-case。
|
||||
- 回归测试发现目录使用通用树形结构:`tests/case/<domain>/<suite>/<groups...>/<case>.test.ts`。
|
||||
- 回归 E2E 测试文件使用 `tests/case/<domain>/<suite>/<groups...>/<case>.e2e.test.ts`。
|
||||
- Showcase 采集文件使用 `tests/showcase/<case>.showcase.test.ts`,不进入回归 runner。
|
||||
- 正式测试发现目录使用通用树形结构:`tests/case/<domain>/<suite>/<groups...>/<case>.test.ts`。
|
||||
- 正式 E2E 测试文件使用 `tests/case/<domain>/<suite>/<groups...>/<case>.e2e.test.ts`。
|
||||
- `suite` 是第一层稳定分类;`groups...` 是 suite 下可选的子目录。
|
||||
- 各回归 domain 的 `suite` 列表与归属,只在对应 `doc/test-plan/**` 中定义;Showcase 不使用回归 domain/suite。
|
||||
- 当某个 `suite` 不需要继续细分时,回归 case 可以直接放在该 `suite` 目录下。
|
||||
- `tests/case/**` 中除 `unit/**` 外,只允许放已在 `doc/test-plan/**` 登记的回归 case。
|
||||
- 各测试 domain 的 `suite` 列表与归属,只在对应 `doc/test-plan/**` 中定义。
|
||||
- 当某个 `suite` 不需要继续细分时,测试 case 可以直接放在该 `suite` 目录下。
|
||||
- `tests/case/{ai,settings,unit,workbench}/**` 只允许放已在 `doc/test-plan/**` 登记的正式测试 case。
|
||||
- `tests/fixtures/workspace/` 是共享工作区 fixture 根目录;凡是依赖“工作区里有什么文件”的测试,以及 backend/unit 直接引用的固定文件输入,统一复用该目录。
|
||||
- `tests/fixtures/sqlite/` 放数据库迁移 fixture。
|
||||
- `tests/fixtures/**` 全部是只读测试输入:测试禁止对其中任何文件原地写入、覆盖或修改;需要写入时,必须通过 `fixtures: []` 声明由 runner/harness 复制到隔离临时 workspace(或按 E2E 规则复制到临时目录),测完删除。fixture 需要更新时直接提交新二进制,禁止引入任何 fixture 生成器脚本(生成器不得以 `.test.ts` 形态进入 `tests/case/**` 自动发现)。
|
||||
@@ -61,20 +55,20 @@ tests/
|
||||
|
||||
### 2.3 稳定映射模型
|
||||
|
||||
回归测试按 `domain / suite / groups... / caseId` 映射到目录和日志;普通 `.test.ts` 为 backend,`.e2e.test.ts` 为 E2E。固定边界为:`ai`、`unit` 只能是 backend,`settings`、`workbench` 只能是 E2E。Showcase 使用独立的 `showcase / collection / caseId` 采集日志映射。
|
||||
测试按 `domain / suite / groups... / caseId` 映射到目录和日志;普通 `.test.ts` 为 backend,`.e2e.test.ts` 为 E2E。固定边界为:`ai`、`unit` 只能是 backend,`settings`、`workbench` 只能是 E2E。
|
||||
|
||||
## 3. 回归与采集 case 规则
|
||||
## 3. 测试用例规则
|
||||
|
||||
### 3.1 准入规则
|
||||
|
||||
- 新增任何测试文件前,必须先与用户确认目标分类。
|
||||
- `doc/test-plan/**` 是回归 case 的唯一规格来源;新增、修改或补齐回归 case 时,必须先更新对应测试计划,再修改测试代码。Showcase 采集任务遵循 `doc/test-plan/showcase-test.md`。
|
||||
- `tests/case/<domain>/**` 只能放已登记的回归 case;`tests/case/unit/**` 不进入领域回归计划,但仍必须满足 Unit backend 边界。
|
||||
- 每个回归 `caseId` 都必须稳定映射到唯一测试定义与唯一日志目录。一个测试文件可以承载多个紧密相关的 case,但 `--case <caseId>` 必须能只执行目标 case。
|
||||
- `doc/test-plan/**` 是测试 case 的唯一规格来源;新增、修改或补齐测试 case 时,必须先更新对应测试计划,再修改测试代码。
|
||||
- `tests/case/<domain>/**` 只能放已登记的测试 case;`tests/case/unit/**` 不进入领域测试计划,但仍必须满足 Unit backend 边界。
|
||||
- 每个测试 `caseId` 都必须稳定映射到唯一测试定义与唯一日志目录。一个测试文件可以承载多个紧密相关的 case,但 `--case <caseId>` 必须能只执行目标 case。
|
||||
|
||||
### 3.2 回归 case 共享字段
|
||||
### 3.2 测试 case 共享字段
|
||||
|
||||
回归 case 和 Showcase 采集任务在 `doc/test-plan/**` 中统一使用以下字段:
|
||||
测试 case 在 `doc/test-plan/**` 中统一使用以下字段:
|
||||
|
||||
- `测试类型`
|
||||
- `backend` 或 `e2e`。
|
||||
@@ -89,7 +83,7 @@ tests/
|
||||
- `Not`
|
||||
- 明确不验证什么,防止实现时擅自扩张范围。
|
||||
|
||||
### 3.3 UI E2E 回归规则
|
||||
### 3.3 UI E2E 测试规则
|
||||
|
||||
- UI E2E 必须通过真实 UI 和产品链路完成被测行为;禁止 fake、mock、stub、直接写状态或内部写 IPC 绕过。
|
||||
- fixture 和 helper 只能准备真实输入、执行用户可见操作、等待结果和收集证据,不能替代产品输出。
|
||||
@@ -101,7 +95,7 @@ tests/
|
||||
### 3.4 真实 AI / live 断言规则
|
||||
|
||||
- live 模型配置(backend `ai/human/live` 与 Workbench AI E2E 共用)与 opt-in 命令只在对应 `doc/test-plan/**` 维护,本文不重复。
|
||||
- 涉及真实 AI 调用的回归测试,硬断言只验证完成态、关键事实、关键工具或事件、关键 artifact,以及用户诉求是否落地;最终自然语言回答不得作为主要正确性证据。
|
||||
- 涉及真实 AI 调用的测试,硬断言只验证完成态、关键事实、关键工具或事件、关键 artifact,以及用户诉求是否落地;最终自然语言回答不得作为主要正确性证据。
|
||||
- 不对最终文案做逐字断言,不断言固定工具顺序,不断言固定 prompt 原文,不因表达差异判失败。
|
||||
- 如果用户诉求已落地但断言过严,应先调整 `Oracle` 和测试代码,再根据 raw logs 记录完成度评分。
|
||||
- 完成度评分由执行者或 agent 写入运行结论;测试代码不得在执行过程中修改文档。
|
||||
@@ -111,12 +105,11 @@ tests/
|
||||
### 4.1 固定顺序
|
||||
|
||||
1. 先确认是否新增或调整测试,以及目标分类。
|
||||
2. 如果是回归测试,先更新对应 `doc/test-plan/**`,再修改 `tests/case/<domain>/**`。
|
||||
3. 如果是 Showcase 采集,先更新 `doc/test-plan/showcase-test.md`,再修改 `tests/showcase/**`。
|
||||
4. 如果是 Unit,放入 `tests/case/unit/**`,保持 backend-only,不更新 `doc/test-plan/**`。
|
||||
5. 回归测试通过 `scripts/test/workflow.mjs` 执行;Showcase 通过 `scripts/test/showcase.mjs` 执行。
|
||||
6. 先看 `timeline.jsonl`;不足时再看 `runtime-events.jsonl`、`meta.json` 和 `artifacts.json`。
|
||||
7. 最后基于 raw logs 回流结论,决定是否需要更新测试计划或实现代码。
|
||||
2. 如果是测试用例,先更新对应 `doc/test-plan/**`,再修改 `tests/case/<domain>/**`。
|
||||
3. 如果是 Unit,放入 `tests/case/unit/**`,保持 backend-only,不更新测试计划。
|
||||
4. 通过 `scripts/test/workflow.mjs` 执行并产出日志。
|
||||
5. 先看 `timeline.jsonl`;不足时再看 `runtime-events.jsonl`、`meta.json` 和 `artifacts.json`。
|
||||
6. 最后基于 raw logs 回流结论,决定是否需要更新测试计划或实现代码。
|
||||
|
||||
### 4.2 runner 与常用命令
|
||||
|
||||
@@ -151,19 +144,12 @@ runner 不负责:
|
||||
- 源码 E2E
|
||||
- `pnpm test:e2e:source`:构建当前源码并运行 `tests/case/**` 中的全部 E2E。
|
||||
- `pnpm test:e2e:package -- --bundle <release-bundle.json>`:校验并安装已经构建的正式包,再对安装后的可执行程序运行所选正式 E2E。安装落在本机 `NCurator-E2E` 目录;Windows 可能覆盖本机已安装的正式包。测完删除 E2E 安装目录及指向它的入口。
|
||||
- 发版回归 E2E
|
||||
- `pnpm release:win -- --tag <tag> --test-only [回归过滤参数]`
|
||||
- `pnpm release:mac -- --tag <tag> --test-only [回归过滤参数]`
|
||||
- 不带过滤参数执行全部发版回归;发版回归允许包含日常默认集合之外的正式回归用例,但不包含显式采集任务。具体决策见 `doc/deploy/release.md`。
|
||||
- Settings
|
||||
- `pnpm test:settings`
|
||||
- `pnpm test:settings:e2e`
|
||||
- Workbench
|
||||
- `pnpm test:workbench`
|
||||
- `pnpm test:workbench:e2e`
|
||||
- Showcase
|
||||
- `pnpm test:showcase`
|
||||
- `pnpm test:showcase -- --case <caseId>`
|
||||
|
||||
runner 支持的过滤参数:
|
||||
|
||||
@@ -184,10 +170,9 @@ runner 支持的过滤参数:
|
||||
|
||||
- runner 强制执行固定 domain/type 边界。backend 普通测试并发为 6;Source E2E 与正式包 E2E 在多 case 时都先串行执行全仓唯一的 `warmup` 用例(先冷启动索引共享 fixture,后续 case 复用缓存)。Source 的所有 case 直接共享按构建指纹保存的 split/vector 内容缓存,各 case 只隔离统计文件;正式包 E2E 则把缓存种子复制到后续 case 的隔离缓存目录。随后开放总并发 3、live 并发 2,`exclusive` 用例串行独占;某个 case 失败后不自动重跑,继续收集剩余 case;warm-up 失败则不启动后续并发。
|
||||
- E2E(source 与正式包)即使通过 `--domain`/`--suite`/`--case` 过滤范围,只要本次实际执行的 case 数超过 1,runner 也会自动把全仓唯一的 `warmup` 用例纳入执行并先串行预热,避免过滤后漏掉 warmup 导致全部 case 冷启动重复索引;`--case` 过滤时 `warmup` 用例不受 `--testNamePattern` 影响。
|
||||
- E2E 默认执行类型为 `normal`;真实 AI/服务调用声明 `execution: 'live'`,原生对话框、鼠标和桌面焦点用例声明 `execution: 'exclusive'`,唯一的向量冷启动用例声明 `execution: 'warmup'`。`provider-matrix` 与 `wps-office` 都属于正式 E2E,按影响评估选择或在全量回归时执行。
|
||||
- `source` 是源码目标,直接复用内容缓存;`package` 只接受既有 release bundle,安装后运行所选 E2E,不负责构建。两者都不发现 `tests/showcase/**`。
|
||||
- native binding、知识库缓存和临时 Electron app 由 runner 自动准备;普通回归不手工修改 `node_modules` 或复用正式包缓存。
|
||||
- 正式包测试、发布门禁、Tag 前 Unit/非 live AI(及发布准备必跑的 `human-prefix-cache-retain-live`)以及发布后日志清理只在 `doc/deploy/release.md` 定义,本文不重复发布流程。
|
||||
- E2E 默认执行类型为 `normal`;真实 AI/服务调用声明 `execution: 'live'`,原生对话框、鼠标和桌面焦点用例声明 `execution: 'exclusive'`,唯一的向量冷启动用例声明 `execution: 'warmup'`。
|
||||
- `source` 是源码目标,直接复用内容缓存;`package` 只接受既有 release bundle,安装后运行所选 E2E,不负责构建。
|
||||
- native binding、知识库缓存和临时 Electron app 由 runner 自动准备;普通测试不手工修改 `node_modules` 或复用正式包缓存。
|
||||
|
||||
### 4.3 读取与分析 raw logs
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ const ROOT = process.cwd()
|
||||
const require = createRequire(import.meta.url)
|
||||
const TESTS_ROOT = path.join(ROOT, 'tests')
|
||||
const TEST_CASES_ROOT = path.join(TESTS_ROOT, 'case')
|
||||
const SHOWCASE_ROOT = path.join(TESTS_ROOT, 'showcase')
|
||||
const SHOWCASE_ROOT = path.join(TEST_CASES_ROOT, 'showcase')
|
||||
const resolveLocalBin = (name) =>
|
||||
path.join(ROOT, 'node_modules', '.bin', process.platform === 'win32' ? `${name}.cmd` : name)
|
||||
const PNPM_BIN = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'
|
||||
@@ -665,7 +665,12 @@ const validateTestArchitecture = () => {
|
||||
}
|
||||
|
||||
const formatScope = (input) =>
|
||||
[[input.domain, input.suite, ...input.groups].filter(Boolean).join('/'), input.type]
|
||||
[
|
||||
input.showcase
|
||||
? 'showcase'
|
||||
: [input.domain, input.suite, ...input.groups].filter(Boolean).join('/'),
|
||||
input.type
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { describe, it } from 'vitest'
|
||||
import { runShowcaseCase } from '../harness/e2e/run-e2e-case'
|
||||
import { runShowcaseCase } from '../../harness/e2e/run-e2e-case'
|
||||
import {
|
||||
WORKBENCH_LIVE_AI_E2E_TIMEOUT_MS,
|
||||
assertNoWorkbenchFakeSignals,
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
selectWorkbenchModel,
|
||||
sendWorkbenchMessage,
|
||||
waitForWorkbenchAiRunCompletion
|
||||
} from '../harness/e2e/workbench'
|
||||
} from '../../harness/e2e/workbench'
|
||||
import { WEB_SEARCH_PROMPT } from './createSeeds'
|
||||
import {
|
||||
computeShowcaseCost,
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { describe, it } from 'vitest'
|
||||
import { runShowcaseCase } from '../harness/e2e/run-e2e-case'
|
||||
import { runShowcaseCase } from '../../harness/e2e/run-e2e-case'
|
||||
import {
|
||||
WORKBENCH_LIVE_AI_E2E_TIMEOUT_MS,
|
||||
assertNoWorkbenchFakeSignals,
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
selectWorkbenchModel,
|
||||
sendWorkbenchMessage,
|
||||
waitForWorkbenchAiRunCompletion
|
||||
} from '../harness/e2e/workbench'
|
||||
} from '../../harness/e2e/workbench'
|
||||
import { COURT_SEARCH_HOST, COURT_SEARCH_KEYWORDS, COURT_SEARCH_PROMPT } from './createSeeds'
|
||||
import {
|
||||
captureEmbeddedBrowserPng,
|
||||
File renamed without changes.
+2
-2
@@ -1,7 +1,7 @@
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { describe, it } from 'vitest'
|
||||
import { runShowcaseCase } from '../harness/e2e/run-e2e-case'
|
||||
import { runShowcaseCase } from '../../harness/e2e/run-e2e-case'
|
||||
import {
|
||||
WORKBENCH_LIVE_AI_E2E_TIMEOUT_MS,
|
||||
assertNoWorkbenchFakeSignals,
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
waitForApplyEntryByFileName,
|
||||
waitForWorkbenchAiRunCompletion,
|
||||
workbenchSelectors
|
||||
} from '../harness/e2e/workbench'
|
||||
} from '../../harness/e2e/workbench'
|
||||
import { DOCX_EDIT_PROMPT, DOCX_FILE_NAME } from './createSeeds'
|
||||
import {
|
||||
computeShowcaseCost,
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { describe, it } from 'vitest'
|
||||
import { runShowcaseCase } from '../harness/e2e/run-e2e-case'
|
||||
import { runShowcaseCase } from '../../harness/e2e/run-e2e-case'
|
||||
import {
|
||||
WORKBENCH_LIVE_AI_E2E_TIMEOUT_MS,
|
||||
assertNoWorkbenchFakeSignals,
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
waitForApplyEntryByFileName,
|
||||
waitForWorkbenchAiRunCompletion,
|
||||
workbenchSelectors
|
||||
} from '../harness/e2e/workbench'
|
||||
} from '../../harness/e2e/workbench'
|
||||
import {
|
||||
computeShowcaseCost,
|
||||
copyShowcaseFixture,
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { describe, it } from 'vitest'
|
||||
import { runShowcaseCase } from '../harness/e2e/run-e2e-case'
|
||||
import { runShowcaseCase } from '../../harness/e2e/run-e2e-case'
|
||||
import {
|
||||
WORKBENCH_LIVE_AI_E2E_TIMEOUT_MS,
|
||||
assertNoWorkbenchFakeSignals,
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
waitForApplyEntryByFileName,
|
||||
waitForWorkbenchAiRunCompletion,
|
||||
workbenchSelectors
|
||||
} from '../harness/e2e/workbench'
|
||||
} from '../../harness/e2e/workbench'
|
||||
import { EXCEL_EDIT_PROMPT, EXCEL_FILE_NAME } from './createSeeds'
|
||||
import {
|
||||
computeShowcaseCost,
|
||||
+2
-2
@@ -2,7 +2,7 @@ import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import ExcelJS from 'exceljs'
|
||||
import { describe, it } from 'vitest'
|
||||
import { runShowcaseCase } from '../harness/e2e/run-e2e-case'
|
||||
import { runShowcaseCase } from '../../harness/e2e/run-e2e-case'
|
||||
import {
|
||||
WORKBENCH_LIVE_AI_E2E_TIMEOUT_MS,
|
||||
assertNoWorkbenchFakeSignals,
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
waitForApplyEntryByFileName,
|
||||
waitForWorkbenchAiRunCompletion,
|
||||
workbenchSelectors
|
||||
} from '../harness/e2e/workbench'
|
||||
} from '../../harness/e2e/workbench'
|
||||
import { EXCEL_CREATE_PROMPT, EXCEL_FILE_NAME } from './createSeeds'
|
||||
import {
|
||||
computeShowcaseCost,
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { describe, it } from 'vitest'
|
||||
import { runShowcaseCase } from '../harness/e2e/run-e2e-case'
|
||||
import { runShowcaseCase } from '../../harness/e2e/run-e2e-case'
|
||||
import {
|
||||
WORKBENCH_LIVE_AI_E2E_TIMEOUT_MS,
|
||||
assertNoWorkbenchFakeSignals,
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
waitForApplyEntryByFileName,
|
||||
waitForWorkbenchAiRunCompletion,
|
||||
workbenchSelectors
|
||||
} from '../harness/e2e/workbench'
|
||||
} from '../../harness/e2e/workbench'
|
||||
import { PPT_EDIT_PROMPT, PPT_FILE_NAME } from './createSeeds'
|
||||
import {
|
||||
computeShowcaseCost,
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { describe, it } from 'vitest'
|
||||
import { runShowcaseCase } from '../harness/e2e/run-e2e-case'
|
||||
import { runShowcaseCase } from '../../harness/e2e/run-e2e-case'
|
||||
import {
|
||||
WORKBENCH_LIVE_AI_E2E_TIMEOUT_MS,
|
||||
assertNoWorkbenchFakeSignals,
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
waitForApplyEntryByFileName,
|
||||
waitForWorkbenchAiRunCompletion,
|
||||
workbenchSelectors
|
||||
} from '../harness/e2e/workbench'
|
||||
} from '../../harness/e2e/workbench'
|
||||
import {
|
||||
computeShowcaseCost,
|
||||
copyShowcaseFixture,
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
getWorkbenchLocator,
|
||||
getWorkbenchPrefixLocator,
|
||||
workbenchSelectors
|
||||
} from '../harness/e2e/workbench'
|
||||
} from '../../harness/e2e/workbench'
|
||||
|
||||
export const USD_CNY = 7.2
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { describe, it } from 'vitest'
|
||||
import { runShowcaseCase } from '../harness/e2e/run-e2e-case'
|
||||
import { runShowcaseCase } from '../../harness/e2e/run-e2e-case'
|
||||
import {
|
||||
WORKBENCH_LIVE_AI_E2E_TIMEOUT_MS,
|
||||
assertNoWorkbenchFakeSignals,
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
selectWorkbenchModel,
|
||||
sendWorkbenchMessage,
|
||||
waitForWorkbenchAiRunCompletion
|
||||
} from '../harness/e2e/workbench'
|
||||
} from '../../harness/e2e/workbench'
|
||||
import { KB_PROMPT, KB_SOURCE_PAGES, seedKnowledgeWorkspace } from './createSeeds'
|
||||
import { computeShowcaseCost, rasterizeNotePage, screenshotAssistantAnswer } from './shared'
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { describe, it } from 'vitest'
|
||||
import { runShowcaseCase } from '../harness/e2e/run-e2e-case'
|
||||
import { runShowcaseCase } from '../../harness/e2e/run-e2e-case'
|
||||
import {
|
||||
WORKBENCH_LIVE_AI_E2E_TIMEOUT_MS,
|
||||
appendWorkbenchInputText,
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
selectWorkbenchModel,
|
||||
submitWorkbenchCurrentDraft,
|
||||
waitForWorkbenchAiRunCompletion
|
||||
} from '../harness/e2e/workbench'
|
||||
} from '../../harness/e2e/workbench'
|
||||
import { PDF_FILE_NAME, PDF_PROMPT, seedPdfContractWorkspace } from './createSeeds'
|
||||
import {
|
||||
computeShowcaseCost,
|
||||
@@ -2,7 +2,7 @@ import { defineConfig } from 'vitest/config'
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ['tests/showcase/**/*.showcase.test.ts'],
|
||||
include: ['tests/case/showcase/**/*.showcase.test.ts'],
|
||||
exclude: ['tests/harness/**', 'tests/fixtures/**', 'tests/logs/**'],
|
||||
environment: 'node',
|
||||
globals: true,
|
||||
|
||||
Reference in new issue
Block a user