mcpField
E
expect

expect

github.com/yonatangross测试与质量30086 次安装今天更新
代码仓库

关于 expect

expect 是一款根据 Git 差异选定网页变更测试范围的技能。它将变更文件映射到受影响的路由,生成供审核的测试计划,并通过 agent-browser 执行。

主要功能

  1. 01依据 Git 差异限定范围
  2. 02将变更文件映射到路由
  3. 03生成 AI 测试计划
  4. 04使用 agent-browser 执行浏览器测试
  5. 05重放已保存的测试流程
  6. 06报告结果与测试证据

适用场景

  1. 01UI 修改后测试受影响页面
  2. 02集中检查分支差异涉及的页面
  3. 03重放已保存的登录流程

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yonatangross/orchestkit --skill expect

安装后在 Claude Code 中输入/expect确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

jev-shadow.defaults.yaml
flows/
crud.md
login.md
navigation.md
references/
aria-diffing.md
ci-integration.md
config-schema.md
diff-scanner.md
execution.md
fingerprint.md
human-review.md
jev-shadow.md
report.md
research.md
route-map.md
rrweb-recording.md
saved-flows.md
scope-strategy.md
test-plan.md
rules/
_sections.md
artifact-storage.md
diff-scope-boundaries.md
fingerprint-invalidation.md
no-parallel-browsers.md
timeout-and-retry.md
scripts/
coverage-context.sh
diff-scan.sh
fingerprint.sh
init.sh
jev_shadow.py

详细介绍

Expect — 差异感知型 AI 浏览器测试

分析 git 变更,生成有针对性的测试计划,并通过 AI 驱动的浏览器自动化执行。

注意: 如果启用了 disableSkillShellExecution(CC 2.1.91),代理浏览器的安装检查将不会运行。请确认已安装:npx agent-browser --version。

expect                              # Auto-detect changes, test affected pages
expect -m "test the checkout flow"  # Specific instruction
expect --flow login                 # Replay a saved test flow
expect --target branch              # Test all changes on current branch vs main
expect -y                           # Skip plan review, run immediately

核心原则: 只测试发生变更的内容。由 Git diff 确定范围,不在未受影响的页面上浪费时间。

参数解析

ARGS = "[-m <instruction>] [--target unstaged|branch|commit] [--flow <slug>] [-y]"

# Parse from full argument string
import re
raw = ""  # Full argument string from CC

INSTRUCTION = None
TARGET = "unstaged"  # Default: test unstaged changes
FLOW = None
SKIP_REVIEW = False

# Extract -m "instruction"
m_match = re.search(r'-m\s+["\']([^"\']+)["\']|-m\s+(\S+)', raw)
if m_match:
    INSTRUCTION = m_match.group(1) or m_match.group(2)

# Extract --target
t_match = re.search(r'--target\s+(unstaged|branch|commit)', raw)
if t_match:
    TARGET = t_match.group(1)

# Extract --flow
f_match = re.search(r'--flow\s+(\S+)', raw)
if f_match:
    FLOW = f_match.group(1)

# Extract -y
if '-y' in raw.split():
    SKIP_REVIEW = True

STEP 0:MCP 探测 + 前置条件检查

# memory is alwaysLoad in .mcp.json (CC 2.1.121+, #1541) — probe below kept as fallback for older CC:
ToolSearch(query="select:mcp__memory__search_nodes")

# Verify agent-browser is available (Rust-native, no Playwright)
Bash("command -v agent-browser || npx agent-browser --version")
# If missing: "Install agent-browser: npm i -g agent-browser"

# Load agent-browser's version-matched workflow guide (ships with the CLI).
# NOT `skills get agent-browser` — that resolves but returns only the thin
# top-level router; `core --full` is the actual 2,800+ line command reference.
Bash("agent-browser skills get core --full")

关键:任务管理

# 1. Create main task IMMEDIATELY
TaskCreate(
  subject="Expect: test changed code",
  description="Diff-aware browser testing pipeline",
  activeForm="Running diff-aware browser tests"
)

# 2. Create subtasks for each pipeline phase
TaskCreate(subject="Check fingerprint (skip if unchanged)", activeForm="Checking fingerprint")  # id=2
TaskCreate(subject="Scan git diff and classify changes", activeForm="Scanning diff")            # id=3
TaskCreate(subject="Map changes to routes/URLs", activeForm="Mapping routes")                   # id=4
TaskCreate(subject="Generate AI test plan", activeForm="Generating test plan")                   # id=5
TaskCreate(subject="Execute tests via agent-browser", activeForm="Executing browser tests")     # id=6
TaskCreate(subject="Compile test report", activeForm="Compiling report")                        # id=7

# 3. Set dependencies for sequential phases
TaskUpdate(taskId="3", addBlockedBy=["2"])  # Diff scan needs fingerprint check
TaskUpdate(taskId="4", addBlockedBy=["3"])  # Route map needs diff results
TaskUpdate(taskId="5", addBlockedBy=["4"])  # Test plan needs route map
TaskUpdate(taskId="6", addBlockedBy=["5"])  # Execution needs test plan
TaskUpdate(taskId="7", addBlockedBy=["6"])  # Report needs execution results

# 4. Update status as you progress
TaskUpdate(taskId="2", status="in_progress")  # When starting
TaskUpdate(taskId="2", status="completed")    # When done — repeat for each subtask

流程概览

Git Diff → Route Map → Fingerprint Check → Test Plan → Execute → Report
阶段内容输出参考
1. 指纹变更文件的 SHA-256 哈希如果与上次运行相比没有变化,则跳过references/fingerprint.md
2. Diff 扫描解析 git diff,对变更分类ChangesFor 数据(文件、组件、路由)references/diff-scanner.md
3. 路由映射将变更文件映射到受影响的页面/URL指定范围的页面列表references/route-map.md
4. 测试计划根据 diff 和路由映射生成 AI 测试计划包含步骤的 Markdown 测试计划references/test-plan.md
5. 执行通过 agent-browser 运行测试计划每个步骤的通过/失败状态、截图references/execution.md
6. 报告汇总结果、产物和退出代码结构化报告 + 产物references/report.md

阶段 1:指纹检查

检查当前变更是否已经过测试:

Read(".expect/fingerprints.json")  # Previous run hashes
# Compare SHA-256 of changed files against stored fingerprints
# If match: "No changes since last test run. Use --force to re-run."
# If no match or --force: continue to Phase 2

加载:Read("references/fingerprint.md")

阶段 2:Diff 扫描

根据 --target 分析 git 变更:

if TARGET == "unstaged":
    diff = Bash("git diff")
    files = Bash("git diff --name-only")
elif TARGET == "branch":
    diff = Bash("git diff main...HEAD")
    files = Bash("git diff main...HEAD --name-only")
elif TARGET == "commit":
    diff = Bash("git diff HEAD~1")
    files = Bash("git diff HEAD~1 --name-only")

将每个变更文件分为 3 个级别:

  1. 直接 — 文件本身发生了变更
  2. 导入 — 导入了变更文件的文件
  3. 路由 — 渲染变更组件的页面/路由

加载:Read("references/diff-scanner.md")

阶段 3:路由映射

使用 .expect/config.yaml 将变更文件映射到可测试的 URL:

# .expect/config.yaml
base_url: http://localhost:3000
route_map:
  "src/components/Header.tsx": ["/", "/about", "/pricing"]
  "src/app/auth/**": ["/login", "/signup", "/forgot-password"]
  "src/app/dashboard/**": ["/dashboard"]

如果不存在路由映射,则根据 Next.js App Router / Pages Router 约定推断。

加载:Read("references/route-map.md")

阶段 4:生成测试计划

根据当前目标的范围策略,生成限定在 diff 范围内的 AI 测试计划:

scope_strategy = get_scope_strategy(TARGET)  # See references/scope-strategy.md

prompt = f"""
{scope_strategy}

Changes: {diff_summary}
Affected pages: {affected_urls}
Instruction: {INSTRUCTION or "Test that the changes work correctly"}

Generate a test plan with:
1. Page-level checks (loads, no console errors, correct content)
2. Interaction tests (forms, buttons, navigation affected by the diff)
3. Visual regression (compare ARIA snapshots if saved)
4. Accessibility (axe-core scan on affected pages)
"""

如果指定了 --flow,则从 .expect/flows/{slug}.yaml 加载已保存的工作流,而不是生成测试计划。

如果未指定 --y,则通过 AskUserQuestion 向用户展示计划,以便在执行前审核。

加载:Read("references/test-plan.md")

阶段 5:执行

agent-browser 快速入门

最低版本为 >= 0.31.1(已记录 0.27.1 在生产页面上存在问题);当前测试版本为 0.38.1(参见 upstream-version-tested)。以下命令在此版本范围内均适用。0.30+ 新增了 agent-browser read(提取便于 Agent 阅读的文本),以及 --restore / --namespace 会话恢复工作流,可在多次 Agent 运行之间稳定、隔离地保持浏览器状态。0.33.0 新增了 agent-browser a11y [url],这是一项内置的 axe-core 审计功能(支持 WCAG 标签筛选、选择器范围限定,以及支持 iframe 的文本/JSON 输出),既可作为 CLI 命令使用,也可作为 MCP 工具使用。0.34.0 新增了共享 Chrome 会话的持久会话到标签页绑定;使用 --pin-tab 可将绑定设为严格模式,这样外部关闭标签页时会返回稳定的 tab_gone 错误。0.35.0 新增了 --ca-cert <path>,用于在 SSL 检查代理后信任本地 CA(仅限 Linux;这是 --ignore-https-errors 的针对性替代方案)。0.35.1 更改了下方 Diff 行所依赖的行为:diff snapshot 现在会为每次 diff 重置 ref 编号,并在页面导航时使 ref 失效,因此导航前捕获的 ref 必须重新读取,不能重复使用。0.36.0 新增了实验性的 WebMCP 工具发现功能(webmcp list/invoke/result/cancel,在 open 时提供简短的不可信目录摘要)。0.37.0 使 record 以 30 fps 捕获当前活动页面,并将会话设置继承到新标签页。0.38.0 新增了 snapshot --delta(先提供完整基线,之后提供 unchanged 或精简的结构变更)、screenshot --if-changed --threshold、可在同一文档 DOM 变更后继续使用的持久 ref、--human / --input-mode 指针拟真,以及 auth login --no-navigate。完整命令列表:references/upstream.md 和 agent-browser skills get core --full。

区域命令说明
Snapshotagent-browser snapshot -iARIA 树,带有 @eN ref。-C/--cursor 已在 0.22 中移除
Snapshot delta (0.38+)agent-browser snapshot --delta首次提供完整树,之后提供 unchanged 或精简的结构差异;同一文档变更后 ref 仍有效
语义定位器agent-browser find role button click --name "Continue"语法:find <locator> <value> [action];是 @eN ref 的稳定替代方案
交互fill @e1 "..."、click @e2、press Enter、drag @e1 @e2、upload @e1 file.pdf均使用 ARIA ref。添加 --human 可采用曲线移动,而不是瞬间跳转
等待wait --load networkidle、wait --text "Success"、wait --fn "window.ready"由事件驱动,不使用基于休眠的等待
网络network route "*analytics*" --abort、network route "https://api/*" --body '{...}'拦截并模拟响应
状态state save/load auth.json、--session-name <name>在多次运行之间保留身份验证状态
Vaultvault store github_pat、vault load github_pat加密凭据存储
Diffdiff snapshot、diff screenshot --baseline /tmp/x.png对不同运行之间的 ARIA 和像素进行差异比较;在同一次运行中比较同一页面的前后状态时,优先使用 snapshot --delta
捕获screenshot --annotate、screenshot --if-changed --threshold <n> (0.38+)、pdf、record start/stop --fps <n>对未变化的截图,--if-changed 会跳过重新编码;record 默认为 30 fps(0.37+)
控制面板agent-browser dashboard start (0.25+)浏览器端运行时检查器,地址为 :4848
运行测试计划
expect_task = Agent(
  subagent_type="ork:expect-agent",
  prompt=f"""Execute this test plan:
  {test_plan}

  For each step:
  1. Navigate to the URL
  2. Execute the test action
  3. Take a screenshot on failure
  4. Report PASS/FAIL with evidence
  """,
  run_in_background=True,
  model="sonnet",
  max_turns=50
)

# Stream agent-browser progress line-by-line instead of polling (CC 2.1.98+)
# Each stdout line from agent-browser arrives as a notification — useful for
# catching a failing step early rather than waiting for the full plan.
# Full pattern: Read("${CLAUDE_PLUGIN_ROOT}/skills/chain-patterns/references/monitor-patterns.md")
Monitor(pid=expect_task.agent_id)

# For long test plans (>3 min typical), notify on completion — requires
# Remote Control + "Push when Claude decides" config (CC 2.1.110+).
# Skip silently if the user doesn't have Remote Control enabled.
if test_plan_duration_estimate > 180:
    PushNotification(
        message=f"ork:expect complete — {passed}/{total} steps passed on {len(affected_urls)} pages",
        status="proactive"
    )

加载:Read("references/execution.md")

阶段 6:报告

expect Report
═══════════════════════════════════════
Target: unstaged (3 files changed)
Pages tested: 4
Duration: 45s

Results:
  ✓ /login — form renders, submit works
  ✓ /signup — validation triggers on empty fields
  ✗ /dashboard — chart component crashes (TypeError)
  ✓ /settings — preferences save correctly

3 passed, 1 failed

Artifacts:
  .expect/reports/2026-03-26T16-30-00.json
  .expect/screenshots/dashboard-error.png

加载:Read("references/report.md")

已保存的流程

存储在 .expect/flows/ 中的可复用测试序列:

# .expect/flows/login.yaml
name: Login Flow
steps:
  - navigate: /login
  - fill: { selector: "#email", value: "[email protected]" }
  - fill: { selector: "#password", value: "password123" }
  - click: button[type="submit"]
  - assert: { url: "/dashboard" }
  - assert: { text: "Welcome back" }

运行方式:expect --flow login

UI 编辑后自动触发(M125 #2)

当开发栈已启动(dev)时,保存任何 .tsx、.jsx、.css 或 .scss 文件(以及 app/**/page.tsx、pages/**/*.tsx 等 Next.js 路由文件)都会发出提示,建议运行 expect <route>。此钩子(posttool/ui-change-detector)默认启用,并且:

  • 如果 dev 尚未启动,则静默跳过(没有可供连接的 agent-browser 会话);
  • 对每个路由强制执行 30 秒冷却时间,以防快速保存时产生垃圾信息;
  • 将 .claude/state/expect-skip.<sessionId> 作为每个会话的选择退出标记(写入任意内容即可);
  • 将 ORK_EXPECT_AUTO=0 作为环境级紧急开关。

路由解析:app/dashboard/page.tsx → /dashboard,pages/settings.tsx → /settings,组件 / 全局样式编辑 → /(以主页作为代理)。app/(marketing)/pricing/page.tsx 等路由组会被剥离,解析为 /pricing。

ARIA 快照录制(M125 #6)

运行通过后,posttool/expect/snapshot-recorder 钩子会将捕获的 ARIA 树保存到 .claude/state/expect-snapshots/<route-slug>/<parent-commit>.json。之后运行 expect <route> --diff 时,会与该路由最近的前一份快照进行比较,无需基准截图即可发现结构性回归(按钮增删、标签变更、层级变化)。

要触发快照录制器,expect 运行输出必须包含 RUN_COMPLETED|passed、ROUTE|<route> 和 ARIA|<json-summary> 标签。由 agent-browser 驱动的流程已会输出这些标签。

Jev 步骤判定器(选择启用,三种模式)

ORK_EXPECT_JEV 用于选择模式。未设置或值为 false 时,功能关闭;关闭时不会产生任何网络请求。shadow(兼容模式下,设置为 truthy 的 ORK_EXPECT_JEV_SHADOW 也会启用)会在 Agent 的选择旁为每个步骤记录一次 Jev 请求:从交互式 ARIA 元素构建的有界合法操作集合中进行 Choice,并附带三个 verify Noul,同时在报告中记录概率和每步的一致性。设置为 1 或 act 时,由 Jev 选择并驱动该步骤;遇到任何错误、超时、空答案或格式错误的答案,或置信度低于 act_confidence_floor 时,会安全回退到 Agent 自己的选择。可调参数位于 .expect/config.yaml 的 jev_shadow: 中。加载:Read("references/jev-shadow.md")

不适用场景

  • 单元测试 — 改用 cover
  • 仅 API 的变更 — 没有需要测试的浏览器 UI
  • 生成文件 — 跳过构建产物和锁定文件
  • 仅文档变更 — 除非你想验证文档站点的渲染效果

质量标准

满足以下所有条件才算完成:

  • 测试计划的范围根据所选 --target 的 git diff 确定 — 计划中不会出现未受影响的页面。
  • 每个变更文件都至少对应一个经过测试的路由(通过 .expect/config.yaml 或推断约定),或被明确排除为仅 API、生成文件或仅文档。
  • 首先运行指纹检查;如果与上次运行相比 diff 未变化,则跳过执行,不重复测试。
  • 除非传入 -y,否则在运行任何浏览器操作前先展示计划以供审核。
  • 每个已执行步骤都会报告 PASS 或 FAIL,并附带证据(失败时提供截图);报告中的通过 / 失败总数与实际运行的步骤一致。
  • 只要有任何步骤失败,报告的退出代码就为非零。

预算:总计最多 30 分钟,每个页面最多 5 分钟(较慢的页面会被跳过,详见 references/test-plan.md;默认值及 .expect/config.yaml 覆盖项),最多 50 个执行器轮次(max_turns=50),只运行一个顺序执行的 ork:expect-agent,绝不并行运行浏览器(rules/no-parallel-browsers.md);到达截止时间或触及第一个上限时立即停止并报告部分结果。

相关技能

  • agent-browser — 浏览器自动化引擎(必需依赖)
  • ork:cover — 测试套件生成(单元 / 集成 / 端到端)
  • ork:verify — 评估现有测试质量
  • testing-e2e — Playwright 模式与最佳实践

参考资料

使用 Read("references/<file>") 按需加载:

文件内容
fingerprint.mdSHA-256 门控逻辑
diff-scanner.mdGit 差异解析 + 3 级分类
route-map.md文件到 URL 的映射约定
test-plan.mdAI 测试计划生成提示词模板
execution.mdagent-browser 编排模式
report.md报告格式 + 产物存储
config-schema.md.expect/config.yaml 完整架构
aria-diffing.md用于语义差异的 ARIA 快照比较
scope-strategy.md按目标模式制定的测试深度策略
saved-flows.mdMarkdown+YAML 流程格式、自适应重放
rrweb-recording.mdrrweb DOM 重放集成
human-review.mdAskUserQuestion 计划审核关卡
ci-integration.mdGitHub Actions 工作流 + 推送前钩子
research.mdmillionco/expect 架构分析
jev-shadow.md按步骤启用 Jev 步骤判定器:有界操作 Choice + 验证 Nouls;影子日志,act 驱动并在失败时关闭回退

版本: 1.0.0(2026 年 3 月)—— 初始脚手架,M99 里程碑

评论

支持 Markdown