13 KiB
13 KiB
NCurator-Desktop 测试架构规范(Script-first)
1. 目标
- 测试必须优先覆盖生产链路,避免“复制一套逻辑再测试自己”。
- 测试运行器统一使用
vitest。 - 测试目录优先按运行边界分层,而不是按“测试方法学名词”平铺:
main:直接打 Main 进程/服务入口。renderer:直接打 React 页面/组件入口,不走完整 Electron 链路。e2e:从用户入口打完整应用链路,覆盖renderer -> preload -> main -> renderer。
- 输出结构化报告,便于 AI 二次分析并给出优化建议。
2. 套件分层与边界
2.1 顶层测试分层
tests/main/**- 用于 Main 进程侧测试。
- 适合 AI runtime、workspace、storage、migration、web-source 等业务域。
- 特点是启动快、定位准,不依赖 DOM 或窗口。
tests/renderer/**- 用于 renderer 页面的状态机、交互和 preload 契约测试。
- 不要求完整 Electron 启动。
- 适合验证审批 UI、工作区阻塞 UI、面板切换、错误提示等页面行为。
tests/e2e/**- 用于完整应用链路测试。
- 必须从真实用户入口发起交互,并走完整的
renderer -> preload -> main -> renderer流程。 - 适合关键主链路验收与 AI 驱动的探索式 UI 诊断。
2.2 main 分层建议
推荐按业务域继续细分,而不是长期使用 integration 作为主目录名:
tests/main/ai/capability/**- 按 AI 已配置能力/tool 粒度验证能力正确性。
- 直连生产能力入口,如
src/main/services/ai/tools/**。
tests/main/ai/runtime/**- 验证 AI runtime、prompt contract、scope contract、阻塞语义等。
- 原先容易被归到
integration的 AI 侧测试,优先落到这里。
tests/main/ai/human-live/**- 在真实模型下验证 human 子图完成任务的效果。
- 必须只调 human 子图 runner,不经过 main graph。
tests/main/<domain>/service/**- 真实后端业务服务测试,例如 workspace、web-source、storage。
tests/main/<domain>/migration/**- 迁移与清理边界测试。
tests/main/<domain>/runtime/**- 特定业务域的运行时契约测试。
说明:
integration可以作为“测试性质”来描述,但不建议继续作为长期主目录名。- 目录名优先回答“从哪一层入口打进去”和“测哪个业务域”。
2.3 renderer 分层建议
tests/renderer/<page>/contract/**- 使用受控
DesktopApistub 和事件脚本验证页面状态机与 IPC 交互。 - 适合
ChatPage、ImportPage、SearchPage等状态密集页面。
- 使用受控
- selector 与挂载工具建议放在:
tests/harness/renderer/**- 或
tests/renderer/harness/**
2.4 e2e 分层建议
tests/e2e/<page>/deterministic/**- 真实 Electron 主链路回归。
- 适合 Chat 的
plan/artifact、approval_required、workspace_required等关键路径。
tests/e2e/<page>/ai-live/**- AI 探索式 UI 测试。
- 默认非阻塞,主要用于诊断与修复闭环,不作为主门禁。
3. 推荐技术方案
3.1 main
- 继续使用
Vitest - 默认运行在
node环境 - 复用现有 main harness、事件采集和结构化报告写盘
3.2 renderer
- 推荐方案:
Vitest + jsdom + React Testing Library + @testing-library/user-event - 适用范围:
- 页面状态机
- 审批/工作区阻塞 UI
- 面板切换
- preload API 调用参数验证
- 选择原因:
- 与现有
Vitest体系一致,接入成本最低 jsdom足够覆盖当前 React 页面交互测试- React Testing Library 更适合测用户可见行为,而不是组件内部实现
- 与现有
- 补充说明:
Vitest Browser Mode可作为少数真实浏览器能力 case 的补充,不作为默认路线
3.3 e2e
- 推荐方案:
Playwright的 Electron 自动化能力 - 适用范围:
- 真实
renderer -> preload -> main -> renderer链路 - Chat 关键主流程
- Import/Search 主链路
- AI live 探索式 UI 测试
- 真实
- 选择原因:
- 可以直接启动真实 Electron 应用并驱动窗口
- 原生支持 trace、screenshot 等取证能力,便于 AI 基于失败结果修复
3.4 不作为默认路线的方案
- 不默认使用
Playwright component testing代替 renderer contract- 对当前项目过重,反馈慢
- 不默认使用
Cypress作为 Electron 主 e2e- 对 Electron + preload + main 这类链路不如 Playwright 直接
- 不默认只做 e2e、不做 renderer contract
- 会导致大量页面状态逻辑只能靠慢测试兜底
4. 目录与文件约定
tests/
fixtures/
main/ # Main 侧输入(docx、workspace、事件脚本等)
renderer/ # Renderer 页面状态、IPC 脚本、页面样例
e2e/ # 端到端工作区、初始应用状态、运行场景
harness/
main/ # Main 侧运行器、上下文工厂、报告写入、env 加载
renderer/ # 页面挂载、DesktopApi stub、selector、事件回放
e2e/ # Electron 启动器、trace/screenshot、AI live 驱动
main/
ai/
capability/
runtime/
human-live/
workspace/
service/
migration/
renderer/
chat/
contract/
import/
contract/
search/
contract/
e2e/
chat/
deterministic/
ai-live/
import/
deterministic/
search/
deterministic/
tests/report/ # 每次执行的结构化报告
.env # 本地 live 配置(不入库)
.env-example # live 配置模板(入库)
当前状态:
- Main/AI 测试已经迁移到
tests/main/**。 - Main 共享 harness 已迁移到
tests/harness/main/**。 - Main fixture 已迁移到
tests/fixtures/main/**。 - 后续新增 Main 测试不再使用
tests/ai/**路径。
命名建议:
- main capability:
<capability>.<case>.test.ts - main runtime/service/migration:
<domain>.<case>.test.ts - main human-live:
human.<case>.live.test.ts - renderer contract:
<page>.<flow>.test.ts - e2e deterministic:
<page>.<flow>.e2e.test.ts - e2e ai-live:
<page>.<goal>.live.test.ts
5. 环境变量约定(根目录)
human-live 使用根目录 .env 配置:
AI_LIVE_ENABLEAI_LIVE_BASE_URLAI_LIVE_MODEL_NAMEAI_LIVE_API_KEY
规则:
.env-example作为模板入库。.env用于本机配置,不入库。- 测试运行器会优先读取当前 shell 环境;若缺失,再从根目录
.env补充。
6. Fixture 规则
- fixture 缺失必须 fail-fast,并在报告中输出缺失清单。
- Main 侧 docx/workspace 输入优先放在
tests/fixtures/main/**。 - renderer contract 输入优先放在
tests/fixtures/renderer/**。 - e2e 工作区和链路样例优先放在
tests/fixtures/e2e/**。 - 用例里必须显式声明:
requiredFixturesfixtureCopies
7. 报告契约(AI 分析输入)
每个 case 都输出到:
tests/report/<suite>/<case>/<timestamp>/
timestamp 格式:YYYY-MM-DD_HH:mm:ss(本地时间,便于人工阅读)
推荐的 suite 分组命名:
main-ai-capabilitymain-ai-runtimemain-ai-human-livemain-workspace-servicemain-workspace-migrationrenderer-chat-contractrenderer-import-contractrenderer-search-contracte2e-chate2e-importe2e-searche2e-chat-ai-live
固定文件:
events.jsonlassertions.jsonmetrics.jsonsignals.jsonsummary.md
消费原则:
events.jsonl:原始事件流,作为可回放证据。assertions.json:结构化断言结果,包含caseStatus、失败断言 ID 与断言明细。metrics.json:统一标量指标,至少包含caseStatus、caseErrorCode、executionStatus、executionResultCode及步骤、审批、产物计数。signals.json:结构化信号,至少包含toolSequence、toolCounts、toolResultCodeCounts、stepActionSequence、skillActivationSequence、failedAssertionIds,并在适用时补充expectedOutcome、scenarioTags、taskGoal、finalHumanAction。summary.md:事实性摘要,只转写上述结构化数据,不包含固定根因或优化建议。
renderer / e2e 可选附加证据:
artifacts.jsonscreenshots/*.pngtrace/trace.zipconsole.jsonldom/*.html
推荐的 renderer/e2e 附加信号:
routeSequenceuserActionSequenceipcInvokeSequenceselectorFailuresconsoleErrorCountscreenshotRefs
artifacts.json 建议作为 UI 证据索引,至少列出:
screenshotstracedomconsole
AI 消费 renderer / e2e 报告时,最小输入集合建议为:
assertions.jsonmetrics.jsonsignals.jsonsummary.mdartifacts.json
推荐修复顺序:
- 先看
assertions.json确认失败断言 ID 与失败面。 - 再看
metrics.json判断是运行时异常、阻塞还是纯断言失败。 - 再看
signals.json中的routeSequence、userActionSequence、ipcInvokeSequence、selectorFailures、taskGoal。 - 最后按
artifacts.json打开 DOM、console、截图、trace 做精确定位。 - 修复后优先回归同一 case,再回归同 suite 的相邻关键流。
8. AI阶段化测试顺序(能力先行)
推荐按以下顺序逐层放大测试半径:
tool capability- 先验证工具本身是否具备可用能力(正确性、边界、安全、显式缺口)。
- 当前阶段门禁默认只看
tests/main/ai/capability/**。
human 单任务- 在 tool 已可用后,再验证 human 子图能否完成单任务与阻塞收敛。
main context- 验证 main graph 的上下文收集、scope 语义与阻塞契约。
plan 质量- 验证计划拆解是否合理、任务粒度与收敛策略是否稳定。
端到端 AI- 最后验证完整
renderer -> preload -> main -> renderer闭环质量。
- 最后验证完整
说明:
- 若某阶段存在稳定性问题,应优先在该阶段收敛后再进入下一阶段。
explicit_gap属于“能力现状显式标注”,不应混淆为 harness 失败。
9. 扩展规则(目标目录口径)
新增 main AI capability 用例时:
- 新建
tests/main/ai/capability/*.test.ts - 复用
runCapabilityCase - 调用生产 tool 入口并断言结果
新增 main runtime/service/migration 用例时:
- 按业务域落到
tests/main/<domain>/<kind>/*.test.ts - 复用现有 main harness,或在
tests/harness/main/**中补充最小扩展 - 直接调用生产运行时/存储/迁移/范围装配入口,验证跨模块行为
新增 main human-live 用例时:
- 新建
tests/main/ai/human-live/*.live.test.ts - 复用
runHumanLiveCase - 明确
objective、审批策略和成功/阻塞断言
新增 renderer contract 用例时:
- 新建
tests/renderer/<page>/contract/*.test.ts - 复用 renderer mount/stub harness
- 使用受控
DesktopApistub 与事件脚本验证页面状态和 IPC 调用参数
新增 e2e deterministic 用例时:
- 新建
tests/e2e/<page>/deterministic/*.e2e.test.ts - 启动真实 Electron 应用
- 从用户入口触发完整
renderer -> preload -> main -> renderer链路并断言最终界面
新增 e2e ai-live 用例时:
- 新建
tests/e2e/<page>/ai-live/*.live.test.ts - 复用真实 Electron harness
- 明确
taskGoal、expectedOutcome、scenarioTags - 缺少
AI_LIVE_ENABLE=1时默认 skip,不污染主门禁 - 让 AI 在带目标约束的真实 UI 上探索,并输出可修复证据
10. 执行命令(目标口径)
- 当前仓库已实现的命令:
pnpm test:mainpnpm test:main:ai:capabilitypnpm test:main:ai:capability:analyzepnpm test:main:ai:runtimepnpm test:main:ai:human-livepnpm test:main:workspace:servicepnpm test:main:workspace:migrationpnpm test:rendererpnpm test:e2epnpm test:e2e:ai-livepnpm test:aipnpm test:ai:capabilitypnpm test:ai:integrationpnpm test:ai:human-live- 指定单文件:
pnpm test:main -- <path-to-test-file>
- 当前仓库已实现的命令仍以
package.json中现有脚本为准。
补充说明:
- 未配置 live 环境变量时,
human-live用例会按既定策略跳过;这不影响 capability suite 的通过判定。 e2e ai-live默认应作为非阻塞套件,不直接成为主 CI gate;缺少AI_LIVE_ENABLE=1时应 skip。pnpm test:ai*当前仅作为兼容别名保留,底层已指向tests/main/**。- 当前
tests/main/**的已知覆盖包括:tests/main/ai/capability/**:docx编辑与审批拒绝链路、local KB retrieval 范围约束tests/main/ai/runtime/**:runtime/source-scope/prompt contract 与 fail-fast 路径tests/main/workspace/service/**:workspace scan/diff/scope selectiontests/main/workspace/migration/**:legacy local import cleanuptests/main/ai/human-live/**:human 子图真实模型任务与阻塞路径