默认原则
issue #81 起,仓库测试体系默认以离线可复现为第一层保障。普通pnpm test 不连接 Supabase、LLM、GitLab、外部 CLI 或真实服务器;这些真实环境验证只放进后续 opt-in smoke 套件,避免本地开发被环境状态阻断。
测试分层如下:
| 层级 | 命令 | 用途 |
|---|---|---|
| 旧有基础测试 | pnpm test:legacy | 继续运行现有 node:test 用例,覆盖 core、server 和 App 纯函数脚本。 |
| 单元/组件测试 | pnpm test:unit | 使用 Vitest 跑 app、server/web、shared run-workspace-input、server/cli 的离线测试。 |
| UI 测试 | pnpm test:ui | 只跑 App、默认 server/web 与 shared run-workspace-input 的 Vitest/jsdom 测试。 |
| Workspace workflow 契约 | pnpm test:workspace | 检查 workspace/workflow/* 示例的专属 fixture、结构快照与离线 runtime smoke。 |
| 浏览器 smoke | pnpm test:e2e | 使用 Playwright 跑不依赖 dev server 的首轮 smoke;后续可扩展到真实页面。 |
| 聚合入口 | pnpm test | 顺序运行默认离线测试层。 |
| 覆盖率 | pnpm coverage | 基于 Vitest 输出覆盖率报告。 |
| 真实环境 smoke | pnpm smoke:real | 第六轮 opt-in 套件;默认 skip,只有设置 WORKFLOW_CODE_REAL_SMOKE=1 且提供对应变量时才连接真实服务。 |
给新代码补测试
- 修改
core/**或 root CLI 时,优先补core/*.test.ts或保持现有node:test入口可运行。 - 修改
server/src/**时,优先扩展server/src/*.test.ts或server/src/routes/*.test.ts,用 stub storage / mock repository 保持离线。 - 修改
server/cli/**时,优先把参数解析、路径处理、输出格式和错误码做成可 import 的 helper,再用 Vitest 测试;真实 server 调用留到 smoke。 - 修改默认管理端
server/web/**时,优先补server/web/src/**/*.test.ts(x),覆盖 API client、路由、状态转换和关键组件 loading / empty / error / disabled 状态。 - 修改
shared/run-workspace-input/**时,优先补shared/run-workspace-input/**/*.test.ts(x),覆盖 Run workspace 输入、conversation 列表、附件、Markdown/output item、图片预览、Enter 发送、右键/更多菜单、标题锁定和窄屏/宽屏响应式状态。 - 修改
app/**时,优先补app/src/renderer/src/**/*.test.ts(x),覆盖参数转换、运行状态合并、Diagram 工具、主题/路由和关键组件;完整 Electron 流程后续放到 Playwright/Electron smoke。 - 修改或新增
workspace/workflow/<name>时,至少确保pnpm test:workspace通过;外部服务依赖必须 mock、skip 或放入 opt-in smoke。
第二/三轮覆盖重点
issue #81 第二轮开始,后端与 CLI 覆盖不只检查 happy path,还要覆盖 public routes、storage/persistence、运行队列、取消/超时、错误码和打包后 CLI smoke:server/src/routes/*.test.ts覆盖管理端 API、公开 Embed、Webhook 和 Dify 风格 external run。External run 默认验证 blocking / streaming 两种模式,SSE 使用data: {...}行格式,external.source会标记为external;公开 Embed conversation streaming 默认验证 NDJSON runtime event、run_result和responseMode: "streaming"。server/src/storage.test.ts覆盖 run file 附件存储、Webhook 映射与 header 脱敏、Embed token 拒绝、Embed streaming 元数据、run queue 配置、PostgreSQL 持久化 SQL 和版本生命周期边界。- root CLI 与
server/cli的 dist smoke 测试在构建产物存在时执行;focused test 中没有dist会跳过,首轮/二轮验收仍应先跑pnpm build再跑聚合命令确认 packaged CLI。
- App jsdom 测试覆盖主题选择、手动诊断抽屉、连接缺 token 禁用态、显式 Run/Send 后保持 Run 主视图、runtime event 合并、conversation 图片附件、assistant 输出状态、重复新建空白会话防重、会话重命名/删除、标题锁定以及锁定后忽略 runtime 标题更新。
- 默认 server/web jsdom 测试覆盖项目详情里的 run queue 控件、日志抽屉、版本上下线、Webhook 映射/过滤摘要、Embed 表单保存禁用态,以及公开 Embed conversation 的 NDJSON 分片解析、runtime chunk 追加、最终结果去重、会话列表新到旧排序、分页加载、Enter 发送、右键/更多菜单、会话重命名/删除和标题锁定。
- shared run-workspace-input jsdom 测试覆盖 App、server web 日志回放和公开 Embed 共同复用的 conversation shell:会话 rail、紧凑选择器、新旧排序、分页加载、拖拽/键盘调宽、运行中会话切换、工具调用状态、Advanced options、图片预览、Enter 发送、右键/更多菜单、会话重命名/删除和标题锁定。
- dark/light、窄屏、抽屉与图片预览后续可以继续加 Playwright 视觉 smoke;默认仍保持离线,真实 Electron 或真实 server 只进入 opt-in smoke。
第四轮 Workspace Workflow 专属套件
issue #81 第四轮开始,每个workspace/workflow/<name> 示例都要把自己的测试约定放在示例目录内:
__fixtures__/smoke.json:记录离线 runtime smoke 的参数、conversation id、期望输出和必要节点。需要外部进程或真实 SDK 的样例可以设置run: false,但必须写清skipReason。__snapshots__/structure.json:记录精简结构快照,包括源码文件、节点 factory、参数、conversation、registry、分支和 loop 摘要。- 外部依赖默认 mock:LLM 由测试中的
MockLLMProvider注入,文件输入使用本地 fixture,GitLab webhook 样例只解析本地 payload,不访问 GitLab。 - 如果示例 workflow 自身包含专属工具或解析逻辑,可以在示例目录内补充
*.test.ts;pnpm test:workspace会同时执行workspace/**/*.test.ts和workspace/workflow/**/*.test.ts,外部 HTTP 仍需用 fixture fetch 或同等方式离线化。
game:覆盖多层runIf、LLM 节点、classifier 和多个输出节点。loop:覆盖runFor、runWhile、嵌套runIf和最终达标输出。details-output:覆盖 details output payload 的 title、icon 和 markdown content。runtime-timer:覆盖createTimerNode/endTimer的显式结束计时,并断言输入毫秒数会体现在最终durationMs中。claude-agent:覆盖 fixture、structure、conversation 与 tokenUsage 元数据;真实 Claude Agent SDK 运行需要ANTHROPIC_API_KEY和外部 Claude Code 进程,因此默认 runtime smoke 设置run: false并保留 opt-in README 命令。conversation:覆盖 conversation、图片附件、本地 file store、KV trace 与 mock LLM 消息输入。gpt-image:覆盖图片 file param、离线 mock image runner、conversation 上下文、generate/edit 模式和不支持的透明背景参数校验。
__fixtures__/smoke.json 和 __snapshots__/structure.json,并运行:
第五轮本地质量门禁
当前仓库不再把 GitLab CI 作为默认质量门禁或发布入口;提交前在当前电脑本地顺序运行默认阻断命令。建议先确认pnpm --version 与根 packageManager 一致,再执行:
| 分层 | 命令 |
|---|---|
| 类型检查 | pnpm typecheck、pnpm -C app typecheck、pnpm -C server/web typecheck |
| 单元测试 | pnpm test:legacy、pnpm test:unit |
| 覆盖率 | pnpm coverage |
| 构建 | pnpm build、pnpm -C app build、pnpm -C server/web build |
| workspace smoke | pnpm test:workspace、pnpm smoke:runtime |
| 浏览器 smoke | pnpm test:e2e |
| 真实环境 smoke | 手动 opt-in pnpm smoke:real |
pnpm test。
第六轮真实环境 Smoke
真实环境 smoke 只在显式 opt-in 时执行:| 子项 | 变量 |
|---|---|
| Supabase storage | WORKFLOW_SUPABASE_URL、WORKFLOW_SUPABASE_SERVICE_ROLE_KEY、可选 WORKFLOW_STORAGE_BUCKET |
| LLM provider | LLM_TYPE、LLM_API_KEY、可选 LLM_BASE_URL、LLM_MODEL |
| GitLab webhook | WORKFLOW_CODE_GITLAB_WEBHOOK_URL、可选 WORKFLOW_CODE_GITLAB_WEBHOOK_TOKEN |
| 本地 server | WORKFLOW_SERVER_URL、WORKFLOW_SERVER_ADMIN_KEY |
| 远程 server | WORKFLOW_CODE_REMOTE_SERVER_URL、WORKFLOW_CODE_REMOTE_SERVER_ADMIN_KEY |
| Electron app | WORKFLOW_CODE_ELECTRON_SMOKE=1,并先完成 pnpm -C app build |
WORKFLOW_CODE_REAL_SMOKE=1 时才连接真实 Supabase、LLM、GitLab webhook、Electron 或远程 server;普通本地默认测试不会触发这些外部依赖。
Smoke 边界
真实环境 smoke 可以继续增加这些套件,但不能进入默认pnpm test:
- Supabase / PostgreSQL 真实连接与 migration smoke。
- LLM provider、Codex SDK、GitLab webhook、Lark CLI 等外部集成。
- Electron App 真实启动、主进程 IPC、文件系统和本地 CLI 调用。
- server/web 连接真实 Workflow Server 的登录、项目详情、日志、KV、Webhook 页面回归。