# 行为用例

用例在独立的声明式状态会话中运行，不调用 AI、真实服务或项目脚本，不影响正在体验的页面。它检查明确声明的路径，不是穷举、浏览器点击测试、像素布局或业务需求验收。

## 编写与运行

项目可选声明 `flow.testCases`。每例指定初始 `scenario`，每例重新创建会话；不继承上一例的字段或任务。最多 50 例，每例 100 步，用例声明总计不超过 1 MB。

在 Agent 工作台展开“行为用例”，读取当前修订，编辑用例数组并运行。运行不会保存；保存用例沿用修订冲突检查和一次撤销。也可提交 `{"testCases":[...]}` 局部变更包，整体替换用例列表，与页面、共享逻辑一起原子保存。空数组表示清除声明，不表示行为已验证。

结构检查会检查用例声明；结构错误阻止保存。行为断言失败独立报告，暂不阻止保存。页面／完整项目／变更包检查会运行候选项目的全部声明用例，变更包保存回执也会附上新修订的运行结果。检查当前页面后保存时，应重新核对返回结果；其他用户的过时修订仍无法覆盖。

```json
[
  {
    "id": "complete-and-return",
    "title": "继续后能够返回",
    "scenario": "default",
    "steps": [
      {"type":"assert","page":"start"},
      {"type":"click","blockId":"start-next"},
      {"type":"assert","page":"finish"},
      {"type":"back"},
      {"type":"assert","page":"start","layers":[]}
    ]
  }
]
```

这个例子可用于空白项目。实际项目应以其稳定页面／块 ID 与情境 ID 编写。

## 步骤

| type | 字段 | 行为 |
| --- | --- | --- |
| click | blockId | 点击当前页可操作的动作块，不按任意 actionId 绕过真实入口 |
| input | blockId, value | 向当前页输入组件赋值，触发其 onChange 及依赖选项清理 |
| taskResult | taskId, outcome | 为当前活跃任务注入已声明结果，使用当前任务 Token；非活跃任务默认失败，可用 accepted:false 核对被拒绝 |
| event | eventId | 注入已声明外部事件 |
| back | 无 | 使用当前页公开的返回动作 |
| dismiss | 无 | 关闭可关闭的顶层弹层 |
| assert | page / base / layers / state / errors | 核对当前页、底层页、弹层栈、指定字段和校验错误字段 |

非 assert 步骤可声明 `accepted:false`，明确预期动作被条件或表单校验拒绝。未知控件、未知动作、错误类型等配置错误始终失败，不能借此伪装成正确拒绝。隐藏、禁用、只读或被阻塞的控件不能当作普通可点击入口。

`state` 只断言列出的字段，支持 JSON 数组与对象；不返回全部会话字段。`errors` 按顺序核对 `session.errors()` 的字段名（没有字段的错误使用空字符串）。例如表单提交被拒绝后，可断言 `{"type":"assert","page":"form","errors":["name"]}`。字段确实不存在与字段值为 null 不相同。

只有已声明用例全部执行且断言通过，报告才标为 passed。未声明、结构错误未运行和执行失败分别呈现。失败提供用例 ID、步骤序号、错误码及相关 expected／actual；不自动改流程，也不将模拟成功等同于真实服务完成。

本轮不支持任意脚本、选择器、坐标、延迟等待、网络请求、重复集合行选择或轮播／展开操作步骤；需要这些交互的路径不能据此声称已覆盖。
