Skip to content

Latest commit

 

History

History
143 lines (107 loc) · 7.58 KB

File metadata and controls

143 lines (107 loc) · 7.58 KB

CLI E2E 测试规范

架构分层

层级 路径 测什么
共享基建 packages/e2e gating、子进程 runner、output、globalSetup(private,不发布)
命令 E2E packages/commands/tests/e2e help、缺参、dry-run、live(gated);每用例最小路由
bl smoke packages/cli/tests/e2e/registry.smoke.e2e.test.ts 产品 map 全部 path --help、分组 help、根 help
kscli smoke packages/kscli/tests/e2e/registry.smoke.e2e.test.ts kscli/src/commands.ts 推导 path/分组;identity(--versionsearch --help path)
runtime packages/runtime/tests proxy.e2e、console 跨域 flag 拒绝

依赖边界e2ecorecommands/testse2e + commands/src;产品 tests → e2e + 各自 src禁止产品 import commands/tests/**(子进程 spawn harness 路径除外)。

触发条件

  • 新增/修改 packages/commands/src/commands 下的 command 实现
  • 新增/修改 packages/cli/src/commands.tsbl 命令路径 map
  • 新建或扩展 packages/commands/tests/e2e/<topic>.e2e.test.ts
  • 新增 bl 产品 path → registry.smoke 自动覆盖 leaf path;commands topic 测试在 topic-routes.ts 补最小路由

跑测与环境变量见 .cursor/skills/bailian-cli-e2e/SKILL.md

规则:共享 command 行为在 commands/tests/e2e;产品 map、identity、CLI-only 命令留在对应产品 tests/e2e

文件与工具

commands E2E

  • 路径:packages/commands/tests/e2e/<kebab-topic>.e2e.test.ts
  • 子进程:runCommandE2e(routes, args) from ./helpers.ts(spawn harness/main.tsroutes 为本 topic 最小 path → export 映射)
  • fixtures:packages/commands/tests/e2e/fixtures/
  • 路由常量:topic-routes.ts(按 topic 维护,全量产品 map)

产品 smoke

  • bl:runCli from packages/cli/tests/e2e/helpers.ts
  • kscli:runKscli from packages/kscli/tests/e2e/helpers.ts

共享

  • gating / output / runner:e2e/gatinge2e/outpute2e/runner
  • globalSetup:根 vite.config.tspackages/e2e/src/global-setup.ts
  • 解析 JSON stdout:parseStdoutJson;输出目录:makeE2eOutputDir(e2eLabelFromMetaUrl(import.meta.url))
  • 长任务:cliTimeoutPrefix();视频用例加 test(..., 3_600_000) 等显式超时

双层 describe(固定结构)

// 1) 不 skip:--help,无密钥、无真实 API(分组 help 由 bl registry.smoke 覆盖)
describe("e2e: <topic>", () => {
  test("<subcommand> --help 正常退出", ...);
});

// 2) skipIf:缺参 / dry-run / 真实集成
describe.skipIf(<ready>)("e2e: <topic>(DashScope …)", () => {
  test("缺少 --<flag> 时退出为用法错误 (2)", ...);
  test("<cmd> --dry-run ...", ...); // 若适用
  test("【model】真实流程", ..., LONG_TIMEOUT);
});

skip 条件(e2e/gating,commands helpers re-export)

场景 条件
文本/搜索/记忆/配置 isDashScopeE2EReady()
图像/语音 isBailianE2EMediaEnabled() && isDashScopeE2EReady()
视频 isBailianE2EVideoEnabled() && isDashScopeE2EReady()
视频 download/task 另需 BAILIAN_E2E_VIDEO_TASK_ID
知识库 chat/search live isChatE2EReady() / isSearchE2EReady()knowledge chat/search,需 BAILIAN_WORKSPACE_ID + agent ID)

用例类型

  1. --helprunCommandE2e(ROUTES, [..., "--help"]) → stderr 含主要 flags
  2. 缺参:带无害全局 flag(如 --quiet)且不传 required flag → exitCode === 2
  3. --dry-run:实现在联网/上传/写盘之前返回;断言 stdout JSON/文本
  4. 真实集成:放在 skip 块末尾

增删命令同步

  • commands export + topic 路由topic-routes.ts 或测试文件内 ROUTES)+ 产品 mapcli/commands.ts / kscli/commands.ts
  • 分组 help 由产品 registry.smoke 负责,无需在 commands 重复

安全与例外

  • 禁止真实破坏性操作auth logout 只用 --dry-runconfig set 只用 --dry-run
  • 不加 dry-rundryRunresolveFileUrl / resolveCredential / 上传之后的命令(如 image editspeech recognize--url
  • --list-voices 等旁路:先于 --text 校验的 flag,缺参用例勿带该 flag
  • 新增 required option → 至少一条缺参用例;改 dry-run 输出 → 更新对应断言

新增 command 检查清单

  • packages/commands/src/index.ts 导出 + packages/cli/src/commands.ts 暴露路径 + topic-routes.ts 补最小路由
  • packages/commands/tests/e2e/<topic>.e2e.test.ts(新建或扩展)
  • 若改了 usageArgs / flags / exampleArgs,跑 pnpm --filter bailian-cli run generate:reference 更新 skills/bailian-cli/reference/ 并提交
  • 子命令 --help(分组 help 由 bl registry.smoke 覆盖)
  • skip 块:每个 required flag 缺参;可 dry-run 则加一条
  • 至少一条真实集成(或说明为何仅 smoke);不破坏已有集成用例顺序
  • vp test packages/commands/tests/e2e/<file> 通过

调试命令

pnpm --filter bailian-cli-commands exec vp test packages/commands/tests/e2e/text-chat.e2e.test.ts
pnpm --filter bailian-cli exec vp test packages/cli/tests/e2e/registry.smoke.e2e.test.ts
pnpm --filter knowledge-studio-cli exec vp test packages/kscli/tests/e2e/registry.smoke.e2e.test.ts
pnpm --filter bailian-cli-runtime exec vp test packages/runtime/tests/proxy.e2e.test.ts

示例片段

import { FOO_ROUTES } from "./topic-routes.ts";

test("foo bar 缺少 --prompt 时退出为用法错误 (2)", async () => {
  const { stderr, exitCode } = await runCommandE2e(FOO_ROUTES, ["foo", "bar", "--quiet"]);
  expect(exitCode).toBe(2);
  expect(stderr).toMatch(/--prompt|Missing required argument/i);
});

test("foo bar --dry-run 仅输出计划", async () => {
  const { stdout, stderr, exitCode } = await runCommandE2e(FOO_ROUTES, [
    "foo",
    "bar",
    "--dry-run",
    "--prompt",
    "x",
    "--output",
    "json",
  ]);
  expect(exitCode, stderr).toBe(0);
  const data = parseStdoutJson<{ request?: unknown }>(stdout);
  expect(data.request).toBeDefined();
});

与批量压测的关系

  • E2E:单条/少量调用、断言固定、可进 vp test(见上文 skip 条件)
  • 批量压测packages/cli/tests/stress/run.mjs + targets/*.mjs,并发 + 报告,仅手动 pnpm run test:stress -- <target>

勿把压测并入 E2E 或默认 CI。详见 stress-batch-tests.md.