@kkeve/suite 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -0
- package/dist/bin/keve.d.ts +13 -0
- package/dist/bin/keve.js +164 -0
- package/dist/commands/auth-update.d.ts +16 -0
- package/dist/commands/auth-update.js +88 -0
- package/dist/commands/clean.d.ts +10 -0
- package/dist/commands/clean.js +78 -0
- package/dist/commands/config.d.ts +17 -0
- package/dist/commands/config.js +99 -0
- package/dist/commands/init.d.ts +15 -0
- package/dist/commands/init.js +292 -0
- package/dist/commands/report.d.ts +12 -0
- package/dist/commands/report.js +159 -0
- package/dist/commands/run.d.ts +29 -0
- package/dist/commands/run.js +417 -0
- package/dist/commands/test.d.ts +12 -0
- package/dist/commands/test.js +102 -0
- package/dist/commands/vitest.d.ts +14 -0
- package/dist/commands/vitest.js +166 -0
- package/dist/config.d.ts +109 -0
- package/dist/config.js +291 -0
- package/dist/core/action-log-writer.d.ts +47 -0
- package/dist/{tools/write-file.js → core/action-log-writer.js} +42 -26
- package/dist/core/auth.d.ts +17 -0
- package/dist/core/auth.js +224 -0
- package/dist/core/cdp-resolver.d.ts +5 -0
- package/dist/core/cdp-resolver.js +93 -0
- package/dist/core/generateReport/report.d.ts +19 -0
- package/dist/core/generateReport/report.js +91 -0
- package/dist/core/generateReport/reportData.d.ts +215 -0
- package/dist/core/generateReport/reportData.js +735 -0
- package/dist/core/global-setup.d.ts +6 -0
- package/dist/core/global-setup.js +113 -0
- package/dist/core/keve-aspect.d.ts +54 -0
- package/dist/core/keve-aspect.js +52 -0
- package/dist/core/keve-decorators.d.ts +51 -0
- package/dist/core/keve-decorators.js +95 -0
- package/dist/core/keve-registry.d.ts +38 -0
- package/dist/core/keve-registry.js +25 -0
- package/dist/core/keve-report.d.ts +27 -0
- package/dist/core/keve-report.js +357 -0
- package/dist/core/keve-test.d.ts +43 -0
- package/dist/core/keve-test.js +364 -0
- package/dist/core/learned-actions.d.ts +24 -0
- package/dist/core/learned-actions.js +65 -0
- package/dist/core/pw-config.d.ts +19 -0
- package/dist/core/pw-config.js +180 -0
- package/dist/index.d.ts +8 -23
- package/dist/index.js +36 -43
- package/dist/page-agent/agent.d.ts +129 -0
- package/dist/page-agent/agent.js +585 -0
- package/dist/page-agent/hooks.d.ts +13 -0
- package/dist/page-agent/hooks.js +218 -0
- package/dist/page-agent/system_prompt.md +240 -0
- package/dist/page-agent/tools.d.ts +29 -0
- package/dist/page-agent/tools.js +297 -0
- package/doc/README.md +124 -0
- package/doc/agents/keve-dev-test-agent.md +140 -0
- package/doc/agents/keve-test-agent.md +178 -0
- package/doc/asserts//346/265/213/350/257/225/345/220/204/351/230/266/346/256/265/350/257/264/346/230/216.png +0 -0
- package/doc/keve-agent-demo.html +370 -0
- package/doc/skills/keve-bddcase-gen/SKILL.md +332 -0
- package/doc/skills/keve-bddcase-gen/references/test-case-rules.md +91 -0
- package/doc/skills/keve-bddcase-gen/references/test-cases-example.md +103 -0
- package/doc/skills/keve-component-gen/SKILL.md +255 -0
- package/doc/skills/keve-component-gen/references/component-mock-strategy.md +74 -0
- package/doc/skills/keve-component-gen/references/component-model-template.md +98 -0
- package/doc/skills/keve-component-gen/references/component-test-template.md +100 -0
- package/doc/skills/keve-component-gen/references/vue-test-utils-guide.md +91 -0
- package/doc/skills/keve-e2e-gen/SKILL.md +179 -0
- package/doc/skills/keve-e2e-gen/references/code-analysis-guide.md +208 -0
- package/doc/skills/keve-e2e-gen/references/decisions.md +36 -0
- package/doc/skills/keve-e2e-gen/references/pom-generation-guide.md +140 -0
- package/doc/skills/keve-e2e-gen/references/script-generation-guide.md +236 -0
- package/doc/skills/keve-e2e-gen/references/test-auditor-guide.md +189 -0
- package/doc/skills/keve-e2e-gen/scripts/extract-components.sh +85 -0
- package/doc/skills/keve-e2e-gen/scripts/inject-testids.sh +95 -0
- package/doc/skills/keve-static-analysis/SKILL.md +362 -0
- package/doc/skills/keve-static-analysis/references/codegraph-analysis-guide.md +108 -0
- package/doc/skills/keve-static-analysis/references/git-impact-analysis.md +81 -0
- package/doc/skills/keve-static-analysis/references/lint-fix-guide.md +69 -0
- package/doc/skills/keve-static-analysis/references/runtime-risk-patterns.md +92 -0
- package/doc/skills/keve-static-analysis/references/security-scan-guide.md +32 -0
- package/doc/skills/keve-static-analysis/references/ts-error-patterns.md +98 -0
- package/doc/skills/keve-static-analysis/references/vue-security-guide.md +72 -0
- package/doc/skills/keve-test-eval/SKILL.md +78 -0
- package/doc/skills/keve-test-eval/references/common-fix-guide.md +166 -0
- package/doc/skills/keve-test-eval/references/confidence-data-guide.md +78 -0
- package/doc/skills/keve-test-eval/references/fix-loop-guide.md +67 -0
- package/doc/skills/keve-unit-gen/SKILL.md +203 -0
- package/doc/skills/keve-unit-gen/references/boundary-conditions.md +78 -0
- package/doc/skills/keve-unit-gen/references/unit-mock-strategy.md +71 -0
- package/doc/skills/keve-unit-gen/references/unit-test-template.md +105 -0
- package/package.json +46 -24
- package/dist/agent/factory.d.ts +0 -25
- package/dist/agent/factory.js +0 -99
- package/dist/agent/index.d.ts +0 -3
- package/dist/agent/index.js +0 -7
- package/dist/agent/loader.d.ts +0 -22
- package/dist/agent/loader.js +0 -117
- package/dist/agent/types.d.ts +0 -9
- package/dist/agent/types.js +0 -2
- package/dist/agent-loop/complete-task.d.ts +0 -28
- package/dist/agent-loop/complete-task.js +0 -70
- package/dist/agent-loop/index.d.ts +0 -16
- package/dist/agent-loop/index.js +0 -26
- package/dist/agent-loop/loop.d.ts +0 -42
- package/dist/agent-loop/loop.js +0 -282
- package/dist/agent-loop/runtime.d.ts +0 -40
- package/dist/agent-loop/runtime.js +0 -163
- package/dist/agent-loop/types.d.ts +0 -161
- package/dist/agent-loop/types.js +0 -105
- package/dist/context/index.d.ts +0 -8
- package/dist/context/index.js +0 -29
- package/dist/context/tokenCalculation.d.ts +0 -55
- package/dist/context/tokenCalculation.js +0 -95
- package/dist/context/truncation.d.ts +0 -67
- package/dist/context/truncation.js +0 -142
- package/dist/context/types.d.ts +0 -7
- package/dist/context/types.js +0 -27
- package/dist/llm/OpenAIClient.d.ts +0 -31
- package/dist/llm/OpenAIClient.js +0 -455
- package/dist/llm/constants.d.ts +0 -2
- package/dist/llm/constants.js +0 -6
- package/dist/llm/errors.d.ts +0 -25
- package/dist/llm/errors.js +0 -51
- package/dist/llm/index.d.ts +0 -49
- package/dist/llm/index.js +0 -158
- package/dist/llm/types.d.ts +0 -124
- package/dist/llm/types.js +0 -2
- package/dist/llm/utils.d.ts +0 -29
- package/dist/llm/utils.js +0 -284
- package/dist/skill/frontmatter-parser.d.ts +0 -50
- package/dist/skill/frontmatter-parser.js +0 -152
- package/dist/skill/index.d.ts +0 -12
- package/dist/skill/index.js +0 -17
- package/dist/skill/loader.d.ts +0 -96
- package/dist/skill/loader.js +0 -256
- package/dist/tools/ask-user.d.ts +0 -8
- package/dist/tools/ask-user.js +0 -47
- package/dist/tools/bash.d.ts +0 -47
- package/dist/tools/bash.js +0 -213
- package/dist/tools/edit-file.d.ts +0 -9
- package/dist/tools/edit-file.js +0 -76
- package/dist/tools/glob.d.ts +0 -8
- package/dist/tools/glob.js +0 -101
- package/dist/tools/grep.d.ts +0 -10
- package/dist/tools/grep.js +0 -76
- package/dist/tools/index.d.ts +0 -24
- package/dist/tools/index.js +0 -47
- package/dist/tools/read-files.d.ts +0 -8
- package/dist/tools/read-files.js +0 -81
- package/dist/tools/write-file.d.ts +0 -8
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: keve-test-agent
|
|
3
|
+
description: KEVE 测试流水线编排代理。用户输入 /keve-test 指令触发,协调 case-generation → script-generation → test-eval 三技能按序执行,并控制修复循环(errorCategory=script → 修复 → 重跑 → 再评估,≤3轮)。
|
|
4
|
+
tools:
|
|
5
|
+
- Bash(shell:*)
|
|
6
|
+
- Bash(npx:*)
|
|
7
|
+
- Bash(npm:*)
|
|
8
|
+
- Bash(node:*)
|
|
9
|
+
- Bash(git:*)
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# KEVE 测试流水线编排代理
|
|
13
|
+
|
|
14
|
+
> 本代理是**薄编排层**,只做三件事:检测起点、调度技能、控制循环。
|
|
15
|
+
> 不包含技能细节——不做代码分析、不写 POM/脚本、不定位具体错误、不修改源码。
|
|
16
|
+
> 目录结构参见 keve_test_spec/keve.yaml 顶部注释(Single Source of Truth)
|
|
17
|
+
|
|
18
|
+
## 触发方式
|
|
19
|
+
|
|
20
|
+
用户输入 `/keve-test-agent` 指令触发,跳过意图识别直接进入本流程。
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 整体流程
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
1. 阶段检测 → 确定起点,输出执行计划,等待用户确认
|
|
28
|
+
2. 调度 keve-bddcase-gen → 生成 test-cases.yaml
|
|
29
|
+
3. 调度 keve-e2e-gen → 分析代码 + 打标 + 生成 POM + 生成 spec
|
|
30
|
+
4. 调度 keve-test-eval(传入 taskDir)→ 执行测试 → 读 confidence-data.jsonl 评估
|
|
31
|
+
5. 根据评估结果决策下一步:
|
|
32
|
+
├─ 全通过 → 生成最终报告 → 结束
|
|
33
|
+
├─ errorCategory=env → 向用户确认 → 按确认结果处理
|
|
34
|
+
├─ errorCategory=assert + thought 提示需求变更 → 更新 test-cases.yaml → 重调度
|
|
35
|
+
├─ errorCategory=assert + thought 提示应用Bug → 记录 Bug → 继续
|
|
36
|
+
└─ errorCategory=script → 进入修复循环
|
|
37
|
+
6. 修复循环(script 类,最多 3 轮):
|
|
38
|
+
调度 script-generation 修复 → 调度 test-eval --last-failed → 再评估 → ≤3 轮
|
|
39
|
+
7. 止损 → 生成最终报告并标注"无法自动修复"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 阶段检测
|
|
45
|
+
|
|
46
|
+
### Step 0: 读取或创建 test-plan.yaml
|
|
47
|
+
|
|
48
|
+
1. **已有 test-plan.yaml**:
|
|
49
|
+
- 读取 `context.trigger` 和各 phase.status
|
|
50
|
+
- 输出:"检测到已有执行计划,当前进度:"
|
|
51
|
+
- 列出各阶段状态(✅ completed / 🔄 in_progress / ⏳ pending / ⏭️ skipped)
|
|
52
|
+
- 询问用户:"从断点继续 / 重新开始?"
|
|
53
|
+
|
|
54
|
+
2. **无 test-plan.yaml**:
|
|
55
|
+
- 根据 trigger=mr 创建新 test-plan.yaml
|
|
56
|
+
- MR 模式包含:static → unit → component → e2e-case → e2e-script → eval
|
|
57
|
+
- 开发阶段已完成的 static/unit/component 可标记 skipped
|
|
58
|
+
- 输出执行计划,等待用户确认
|
|
59
|
+
|
|
60
|
+
### 产物扫描(补充)
|
|
61
|
+
|
|
62
|
+
首次执行或增量执行前,扫描已有产物确定起点:
|
|
63
|
+
|
|
64
|
+
| 产物 | 检测路径 | 存在时行为 |
|
|
65
|
+
|------|----------|------------|
|
|
66
|
+
| KEVE 配置 | `keve_test_spec/keve-test.config.ts` | → 跳过配置初始化 |
|
|
67
|
+
| 测试用例 | `.keve/{branch}/test-cases.yaml` | → 跳过用例生成 |
|
|
68
|
+
| POM | `keve_test_spec/e2e/poms/*.ts` | → 跳过 POM 生成 |
|
|
69
|
+
| E2E 脚本 | `.keve/{branch}/keve_test_spec/*.spec.ts` | → 跳过脚本生成 |
|
|
70
|
+
| 单测 | `keve_test_spec/util/__test__/*.test.ts` | → 跳过单测生成 |
|
|
71
|
+
| 组件测试 | `keve_test_spec/component/__test__/*.test.ts` | → 跳过组件测试生成 |
|
|
72
|
+
| 执行结果 | `.keve/{branch}/test-artifacts/round-N/` | → 跳过执行 |
|
|
73
|
+
|
|
74
|
+
**检测后动作**:
|
|
75
|
+
1. 输出执行计划:**"将执行 Phase X, Y, Z"**
|
|
76
|
+
2. 等待用户确认后开始执行
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 调度技能
|
|
81
|
+
|
|
82
|
+
按顺序调用三个 skill,每个 skill 通过 `use_skill` 加载:
|
|
83
|
+
|
|
84
|
+
| 步骤 | 调度目标 | use_skill 名称 | 输入 | 期望输出 |
|
|
85
|
+
|------|----------|---------------|------|----------|
|
|
86
|
+
| Step 2 | 用例生成 | `keve-bddcase-gen` | 需求文档 + 代码变更 | `.keve/task_xxx/test-cases.yaml` |
|
|
87
|
+
| Step 3 | 脚本生成 | `keve-e2e-gen` | taskDir + 用例定义 | POM + spec(内部严格按 分析→打标→定位器→POM→脚本 顺序执行) |
|
|
88
|
+
| Step 4 | 测试执行 + 评估 | `keve-test-eval` | `taskDir`(任务目录路径) | `confidence-data.jsonl` + 评估推荐 |
|
|
89
|
+
|
|
90
|
+
> 每个步骤完成后确认产物已生成,再进入下一步。
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 评估结果决策
|
|
95
|
+
|
|
96
|
+
test-eval 执行后,读 `confidence-data.jsonl`,按 `data` + `errorCategory` 组合决策:
|
|
97
|
+
|
|
98
|
+
| data | errorCategory | 编排层决策 |
|
|
99
|
+
|------|--------------|-----------|
|
|
100
|
+
| 通过 | pass | 无需处理,继续下一批或结束 |
|
|
101
|
+
| 跳过 | env | **必须暂停** → ask_user_questions 确认:修环境/加mock/标记跳过 |
|
|
102
|
+
| 跳过 | script | 进入修复循环 |
|
|
103
|
+
| 不通过 | script | 进入修复循环 |
|
|
104
|
+
| 不通过 | assert | 读 thought:脚本缺陷→修 / 应用Bug→记录 / 需求变更→更新 test-cases.yaml |
|
|
105
|
+
| 待确认 | * | ask_user_questions 确认 |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 修复循环控制
|
|
110
|
+
|
|
111
|
+
当 confidence-data.jsonl 中存在 `errorCategory=script` 的失败用例时:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
修复循环(最多 3 轮):
|
|
115
|
+
|
|
116
|
+
Round N:
|
|
117
|
+
→ 调度 keve-e2e-gen 按 thought 描述修复 POM/spec
|
|
118
|
+
→ 调度 keve-test-eval 执行 --last-failed
|
|
119
|
+
→ 读新一轮 confidence-data.jsonl
|
|
120
|
+
→ script 类用例全部通过 → 记录修复成功 → 结束循环
|
|
121
|
+
→ 仍有 script 类 → 进入 Round N+1
|
|
122
|
+
→ 达到 3 轮 → 停止循环
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**止损条件**:
|
|
126
|
+
- 3 轮修复后通过数无增加 → 停止,标记"无法自动修复"
|
|
127
|
+
- 所有用例正常 + 置信度达标 → 停止,生成最终报告
|
|
128
|
+
|
|
129
|
+
**每轮结果天然隔离**:
|
|
130
|
+
- `$KEVE_TASK_DIR/test-artifacts/round-N/` 独立输出
|
|
131
|
+
- `latest` 符号链接始终指向最新轮次
|
|
132
|
+
- 在 `run-state.yaml` 中记录每轮 fixes
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## env 类确认
|
|
137
|
+
|
|
138
|
+
当 confidence-data.jsonl 中存在 `errorCategory=env` 的跳过用例时:
|
|
139
|
+
|
|
140
|
+
**必须暂停,向用户确认**:
|
|
141
|
+
|
|
142
|
+
| 选项 | 说明 | 后续动作 |
|
|
143
|
+
|------|------|----------|
|
|
144
|
+
| 修复环境 | 用户自行修复环境问题 | → 修复后重新调度执行 |
|
|
145
|
+
| 添加 mock | 由 script-generation 在 test-data.ts 中添加 mock 数据 | → 重新调度脚本生成 + 执行 |
|
|
146
|
+
| 标记跳过 | 暂不测试该用例 | → 更新 test-cases.yaml status=skipped → 继续 |
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 最终报告
|
|
151
|
+
|
|
152
|
+
所有用例处理完毕后(无论是否全部通过):
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Round N 报告生成
|
|
156
|
+
KEVE_TASK_DIR=.keve/mr-868-temp npx keve report --config=keve_test_spec/keve-test.config.ts
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
向用户展示报告路径和通过率摘要。
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 禁止事项
|
|
164
|
+
|
|
165
|
+
本代理**不做**以下事情(由各 skill 负责):
|
|
166
|
+
|
|
167
|
+
- 不做代码分析、POM 设计、定位器生成
|
|
168
|
+
- 不写测试脚本
|
|
169
|
+
- 不分析根因、计算置信度
|
|
170
|
+
- 不生成 HTML 报告
|
|
171
|
+
- 不自行决定修复策略(只根据 errorCategory 和 thought 决策调度方向)
|
|
172
|
+
|
|
173
|
+
执行命令时的**硬性禁止**:
|
|
174
|
+
|
|
175
|
+
- **禁止添加 `--reporter=list` 或任何 `--reporter=...` CLI 参数** — Playwright 的 `--reporter` 是覆盖式的,会完全替换 config 中定义的 reporter 数组
|
|
176
|
+
- **禁止 `2>&1` 重定向** — 会将 Playwright 的 JSON reporter 输出混入 stdout
|
|
177
|
+
|
|
178
|
+
本代理**只做**调度决策:什么时候调谁、调几次、什么时候停。
|
|
Binary file
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>KEVE Agent - AI 重建测试流程</title>
|
|
7
|
+
<style>
|
|
8
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
9
|
+
:root{
|
|
10
|
+
--dev:#4F46E5;--dev-l:#818CF8;--dev-bg:#EEF2FF;
|
|
11
|
+
--test:#059669;--test-l:#34D399;--test-bg:#ECFDF5;
|
|
12
|
+
--plat:#7C3AED;--plat-l:#A78BFA;--plat-bg:#F5F3FF;
|
|
13
|
+
--warn:#D97706;--warn-bg:#FEF3C7;
|
|
14
|
+
--in:#0369A1;--in-bg:#E0F2FE;
|
|
15
|
+
--g50:#F9FAFB;--g100:#F3F4F6;--g200:#E5E7EB;--g300:#D1D5DB;
|
|
16
|
+
--g400:#9CA3AF;--g500:#6B7280;--g600:#4B5563;--g700:#374151;
|
|
17
|
+
--g800:#1F2937;--g900:#111827;
|
|
18
|
+
--mono:'SF Mono','Fira Code','Cascadia Code',monospace;
|
|
19
|
+
--sans:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
|
|
20
|
+
}
|
|
21
|
+
body{font-family:var(--sans);height:100vh;overflow:hidden;background:var(--g50);display:flex;flex-direction:column}
|
|
22
|
+
|
|
23
|
+
/* HEADER */
|
|
24
|
+
.Hd{padding:14px 30px 0;display:flex;align-items:center;gap:16px}
|
|
25
|
+
.Hd-ico{width:36px;height:36px;background:var(--dev);border-radius:10px;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:16px;color:white}
|
|
26
|
+
.Hd-t{font-size:20px;font-weight:800;color:var(--g800)}
|
|
27
|
+
.Hd-s{font-size:12px;color:var(--g500)}
|
|
28
|
+
|
|
29
|
+
/* TOP: Flow */
|
|
30
|
+
.Top{padding:8px 30px 0;display:flex;align-items:flex-start;gap:0}
|
|
31
|
+
.Tph{flex:1;background:white;border-radius:12px;padding:12px 14px;border:1.5px solid var(--g200);min-width:0;transition:all .3s}
|
|
32
|
+
.Tph.d{border-color:var(--dev-l)}.Tph.t{border-color:var(--test-l)}.Tph.o{border-color:var(--plat-l)}
|
|
33
|
+
.Tph.act.d{border-color:var(--dev);background:var(--dev-bg)}
|
|
34
|
+
.Tph.act.t{border-color:var(--test);background:var(--test-bg)}
|
|
35
|
+
.Tph.act.o{border-color:var(--plat);background:var(--plat-bg)}
|
|
36
|
+
.Tph-hd{font-size:12px;font-weight:700}
|
|
37
|
+
.Tph.d .Tph-hd{color:var(--dev)}.Tph.t .Tph-hd{color:var(--test)}.Tph.o .Tph-hd{color:var(--plat)}
|
|
38
|
+
.Tph-sub{font-size:10px;color:var(--g500);margin-top:2px;line-height:1.3}
|
|
39
|
+
.Tph-nds{display:flex;gap:6px;margin-top:8px;justify-content:center}
|
|
40
|
+
.Tnd{background:var(--g50);border-radius:7px;padding:7px 10px;cursor:pointer;transition:all .3s;border:1.5px solid var(--g200);min-width:70px;text-align:center;flex:1}
|
|
41
|
+
.Tnd.d{border-color:rgba(79,70,229,.25)}.Tnd.t{border-color:rgba(5,150,105,.25)}.Tnd.o{border-color:rgba(124,58,237,.25)}
|
|
42
|
+
.Tnd.act{transform:scale(1.05)}
|
|
43
|
+
.Tnd.act.d{border-color:var(--dev);background:var(--dev-bg)}
|
|
44
|
+
.Tnd.act.t{border-color:var(--test);background:var(--test-bg)}
|
|
45
|
+
.Tnd.act.o{border-color:var(--plat);background:var(--plat-bg)}
|
|
46
|
+
.Tnd.done{opacity:.35}
|
|
47
|
+
.Tnd .cmd{font-size:9px;font-weight:700;font-family:var(--mono)}
|
|
48
|
+
.Tnd.d .cmd{color:var(--dev)}.Tnd.t .cmd{color:var(--test)}.Tnd.o .cmd{color:var(--plat)}
|
|
49
|
+
.Tnd .nm{font-size:10px;font-weight:600;color:var(--g700);margin-top:1px}
|
|
50
|
+
|
|
51
|
+
.Tarr{width:30px;display:flex;align-items:center;justify-content:center;padding-top:36px}
|
|
52
|
+
.Tarr svg{width:30px;height:18px}
|
|
53
|
+
|
|
54
|
+
/* Timeline */
|
|
55
|
+
.Tl{display:flex;gap:0;overflow-x:auto;padding:6px 30px 0;border-bottom:1px solid var(--g200)}
|
|
56
|
+
.Tl::-webkit-scrollbar{height:2px}.Tl::-webkit-scrollbar-thumb{background:var(--g300);border-radius:2px}
|
|
57
|
+
.Tl-i{flex-shrink:0;padding:6px 8px;font-size:10px;color:var(--g500);cursor:pointer;transition:all .2s;border-bottom:2px solid transparent;white-space:nowrap}
|
|
58
|
+
.Tl-i:hover{background:var(--g100)}
|
|
59
|
+
.Tl-i.act{color:var(--g800);font-weight:600}
|
|
60
|
+
.Tl-i.act.d{border-bottom-color:var(--dev)}.Tl-i.act.t{border-bottom-color:var(--test)}.Tl-i.act.o{border-bottom-color:var(--plat)}
|
|
61
|
+
.Tl-i.done{color:var(--g400)}
|
|
62
|
+
.Tl-sep{flex-shrink:0;width:1px;background:var(--g200);margin:3px 1px}
|
|
63
|
+
|
|
64
|
+
/* MIDDLE: Demo */
|
|
65
|
+
.Mid{flex:1;overflow-y:auto;padding:12px 30px 0}
|
|
66
|
+
.Mid::-webkit-scrollbar{width:4px}.Mid::-webkit-scrollbar-thumb{background:var(--g300);border-radius:2px}
|
|
67
|
+
|
|
68
|
+
/* Controls */
|
|
69
|
+
.Mc{display:flex;align-items:center;gap:8px;padding:0 0 10px}
|
|
70
|
+
.Mbtn{background:var(--dev);color:white;border:none;padding:7px 14px;border-radius:6px;font-size:12px;cursor:pointer;display:flex;align-items:center;gap:5px;font-family:var(--sans);transition:all .2s}
|
|
71
|
+
.Mbtn:hover{filter:brightness(1.15)}.Mbtn.on{background:var(--warn)}
|
|
72
|
+
.Msel{background:var(--g100);color:var(--g600);border:1px solid var(--g200);padding:4px 8px;border-radius:4px;font-size:11px;cursor:pointer;font-family:var(--sans)}
|
|
73
|
+
.Mlbl{font-size:11px;color:var(--g500);margin-left:auto}.Mlbl b{color:var(--g700)}
|
|
74
|
+
.Msc{font-size:11px;padding:5px 10px;background:var(--dev-bg);border-radius:6px;color:var(--g500)}.Msc b{color:var(--dev)}
|
|
75
|
+
|
|
76
|
+
/* Step card */
|
|
77
|
+
.Scard{background:white;border-radius:10px;border:1.5px solid var(--g200);padding:18px 20px;display:none;margin-bottom:12px}
|
|
78
|
+
.Scard.act{display:block}
|
|
79
|
+
.Scard.d{border-left:3px solid var(--dev)}.Scard.t{border-left:3px solid var(--test)}.Scard.o{border-left:3px solid var(--plat)}
|
|
80
|
+
|
|
81
|
+
.Sc-hd{display:flex;align-items:center;gap:10px;margin-bottom:14px}
|
|
82
|
+
.Sc-ph{font-size:10px;font-weight:700;padding:4px 10px;border-radius:6px;letter-spacing:.04em}
|
|
83
|
+
.Sc-ph.d{background:var(--dev-bg);color:var(--dev)}.Sc-ph.t{background:var(--test-bg);color:var(--test)}.Sc-ph.o{background:var(--plat-bg);color:var(--plat)}
|
|
84
|
+
.Sc-nm{font-size:16px;font-weight:700;color:var(--g800)}
|
|
85
|
+
.Sc-tm{font-size:11px;color:var(--g400);font-family:var(--mono);margin-left:auto}
|
|
86
|
+
|
|
87
|
+
/* Input / Output sections */
|
|
88
|
+
.Sc-io{display:flex;gap:16px;margin-bottom:12px}
|
|
89
|
+
.Sc-in,.Sc-out{flex:1;padding:12px 14px;border-radius:8px}
|
|
90
|
+
.Sc-in{background:var(--in-bg);border:1px solid rgba(3,105,161,.1)}
|
|
91
|
+
.Sc-out{background:var(--warn-bg);border:1px solid rgba(217,119,6,.1)}
|
|
92
|
+
.Sc-io-l{font-size:10px;font-weight:700;letter-spacing:.06em;margin-bottom:6px;display:flex;align-items:center;gap:4px}
|
|
93
|
+
.Sc-in .Sc-io-l{color:var(--in)}.Sc-out .Sc-io-l{color:var(--warn)}
|
|
94
|
+
.Sc-io-l .arrow{font-size:12px}
|
|
95
|
+
.Sc-io-v{font-size:12px;color:var(--g600);line-height:1.5}
|
|
96
|
+
.Sc-io-v b{color:var(--g800);font-weight:600}
|
|
97
|
+
.Sc-io-v code{font-family:var(--mono);font-size:11px;background:rgba(0,0,0,.04);padding:1px 4px;border-radius:3px}
|
|
98
|
+
|
|
99
|
+
/* AI thinking */
|
|
100
|
+
.Sc-think{padding:12px 14px;border-radius:8px;margin-bottom:10px;border:1px solid var(--g200)}
|
|
101
|
+
.Sc-think.d{background:rgba(79,70,229,.03);border-color:rgba(79,70,229,.1)}
|
|
102
|
+
.Sc-think.t{background:rgba(5,150,105,.03);border-color:rgba(5,150,105,.1)}
|
|
103
|
+
.Sc-think.o{background:rgba(124,58,237,.03);border-color:rgba(124,58,237,.1)}
|
|
104
|
+
.Sc-thk-l{font-size:10px;font-weight:700;letter-spacing:.06em;margin-bottom:4px;color:var(--g500)}
|
|
105
|
+
|
|
106
|
+
/* Keys */
|
|
107
|
+
.Sc-keys{display:flex;gap:6px;flex-wrap:wrap}
|
|
108
|
+
.Sc-k{font-size:10px;padding:4px 10px;border-radius:5px;font-weight:500}
|
|
109
|
+
.Sc-k.d{background:var(--dev-bg);color:var(--dev)}
|
|
110
|
+
.Sc-k.t{background:var(--test-bg);color:var(--test)}
|
|
111
|
+
.Sc-k.o{background:var(--plat-bg);color:var(--plat)}
|
|
112
|
+
|
|
113
|
+
/* BOTTOM */
|
|
114
|
+
.Btm{padding:10px 30px 14px}
|
|
115
|
+
.Btm-bar{background:var(--g800);border-radius:10px;padding:10px 18px;display:flex;align-items:center;gap:14px}
|
|
116
|
+
.Btm-lbl{font-size:12px;font-weight:700;color:white;white-space:nowrap}
|
|
117
|
+
.Btm-items{display:flex;gap:8px;flex-wrap:wrap;flex:1}
|
|
118
|
+
.Btm-item{font-size:10px;padding:4px 10px;border-radius:5px;background:rgba(255,255,255,.08);color:var(--g300);display:flex;align-items:center;gap:5px}
|
|
119
|
+
.Btm-item b{color:white;font-weight:600}
|
|
120
|
+
.Btm-tag{font-size:8px;padding:2px 6px;border-radius:3px;color:white;font-weight:600}
|
|
121
|
+
|
|
122
|
+
/* Glow */
|
|
123
|
+
@keyframes gd{0%,100%{box-shadow:0 0 10px rgba(79,70,229,.12)}50%{box-shadow:0 0 18px rgba(79,70,229,.25)}}
|
|
124
|
+
@keyframes gt{0%,100%{box-shadow:0 0 10px rgba(5,150,105,.12)}50%{box-shadow:0 0 18px rgba(5,150,105,.25)}}
|
|
125
|
+
@keyframes gp{0%,100%{box-shadow:0 0 10px rgba(124,58,237,.12)}50%{box-shadow:0 0 18px rgba(124,58,237,.25)}}
|
|
126
|
+
.Tnd.act.d{animation:gd 1.4s ease-in-out infinite}
|
|
127
|
+
.Tnd.act.t{animation:gt 1.4s ease-in-out infinite}
|
|
128
|
+
.Tnd.act.o{animation:gp 1.4s ease-in-out infinite}
|
|
129
|
+
</style>
|
|
130
|
+
</head>
|
|
131
|
+
<body>
|
|
132
|
+
|
|
133
|
+
<div class="Hd">
|
|
134
|
+
<div class="Hd-ico">K</div>
|
|
135
|
+
<div><div class="Hd-t">KEVE Agent · AI 重建测试流程</div><div class="Hd-s">开发·自测 → 测试·协同 → 运维·持续保障</div></div>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<div class="Top">
|
|
139
|
+
<div class="Tph d" id="ph-d">
|
|
140
|
+
<div class="Tph-hd">开发阶段 · AI自测闭环</div>
|
|
141
|
+
<div class="Tph-sub">提交代码自动触发 · 沉淀项目资产(agent维护)</div>
|
|
142
|
+
<div class="Tph-nds">
|
|
143
|
+
<div class="Tnd d" id="n1" onclick="go(1)">
|
|
144
|
+
<div class="cmd">提交→test</div>
|
|
145
|
+
<div class="nm">AI自测闭环</div>
|
|
146
|
+
</div>
|
|
147
|
+
<div class="Tnd d" id="n2" onclick="go(7)">
|
|
148
|
+
<div class="cmd">report</div>
|
|
149
|
+
<div class="nm">同步平台</div>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
<div class="Tarr"><svg viewBox="0 0 30 18"><path d="M4 9 L26 9 M20 3 L26 9 L20 15" stroke="#D1D5DB" stroke-width="2" fill="none"/></svg></div>
|
|
154
|
+
<div class="Tph t" id="ph-t">
|
|
155
|
+
<div class="Tph-hd">测试阶段 · 人机协同确认</div>
|
|
156
|
+
<div class="Tph-sub">提测触发 → 平台分发 → 参考开发资产二次测试</div>
|
|
157
|
+
<div class="Tph-nds">
|
|
158
|
+
<div class="Tnd t" id="n3" onclick="go(8)">
|
|
159
|
+
<div class="cmd">提测触发</div>
|
|
160
|
+
<div class="nm">分发+通知</div>
|
|
161
|
+
</div>
|
|
162
|
+
<div class="Tnd t" id="n4" onclick="go(10)">
|
|
163
|
+
<div class="cmd">run(桌面)</div>
|
|
164
|
+
<div class="nm">可视化协同</div>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
<div class="Tarr"><svg viewBox="0 0 30 18"><path d="M4 9 L26 9 M20 3 L26 9 L20 15" stroke="#D1D5DB" stroke-width="2" fill="none"/></svg></div>
|
|
169
|
+
<div class="Tph o" id="ph-o">
|
|
170
|
+
<div class="Tph-hd">运维阶段 · 持续保障</div>
|
|
171
|
+
<div class="Tph-sub">可执行脚本+自然语言用例沉淀 · 定时巡检</div>
|
|
172
|
+
<div class="Tph-nds">
|
|
173
|
+
<div class="Tnd o" id="n5" onclick="go(11)">
|
|
174
|
+
<div class="cmd">keve平台</div>
|
|
175
|
+
<div class="nm">脚本沉淀</div>
|
|
176
|
+
</div>
|
|
177
|
+
<div class="Tnd o" id="n6" onclick="go(12)">
|
|
178
|
+
<div class="cmd">keve平台</div>
|
|
179
|
+
<div class="nm">定时巡检</div>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
185
|
+
<div class="Tl" id="tlEl"></div>
|
|
186
|
+
|
|
187
|
+
<div class="Mid">
|
|
188
|
+
<div class="Mc">
|
|
189
|
+
<button class="Mbtn" id="Mbtn" onclick="tp()"><span id="Mi">▶</span><span id="Mt">播放</span></button>
|
|
190
|
+
<select class="Msel" id="Ms" onchange="cs()"><option value="2000">慢 2s</option><option value="1200" selected>中 1.2s</option><option value="600">快 0.6s</option></select>
|
|
191
|
+
<div class="Mlbl">步骤 <b id="Mn">1</b>/10</div>
|
|
192
|
+
<div class="Msc">MR <b>868</b></div>
|
|
193
|
+
</div>
|
|
194
|
+
<div id="cards"></div>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
<div class="Btm">
|
|
198
|
+
<div class="Btm-bar">
|
|
199
|
+
<div class="Btm-lbl">keve 平台底座</div>
|
|
200
|
+
<div class="Btm-items">
|
|
201
|
+
<div class="Btm-item"><span class="Btm-tag" style="background:var(--dev)">CLI</span><b>keve</b> init / test / run / report</div>
|
|
202
|
+
<div class="Btm-item"><span class="Btm-tag" style="background:var(--test)">桌面端</span><b>keve</b> 可视化协同</div>
|
|
203
|
+
<div class="Btm-item"><span class="Btm-tag" style="background:var(--plat)">Web</span><b>keve</b> 资产沉淀 + 巡检调度</div>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
|
|
208
|
+
<script>
|
|
209
|
+
const S=[
|
|
210
|
+
{ph:'d',nm:'环境初始化(每项目一次)',tm:'一次性',
|
|
211
|
+
in:'<code>项目仓库</code>(llm-agent) → <b>keve init --force</b>',
|
|
212
|
+
out:'<code>.keve/</code> 工作区<br><code>keve_test_spec/poms/</code>(7个Page Object)<br><code>keve_test_spec/fixtures/test-data.ts</code><br><code>keve.yaml</code> + <code>playwright.config.ts</code><br><b>3 Skills</b> + <b>1 Agent</b>',
|
|
213
|
+
th:'keve init只需在每个项目中执行一次。创建工作区、注入Skills和Agent、生成配置。后续每次提交代码不再重复初始化。',
|
|
214
|
+
ks:['keve init','每项目一次','3 Skills','1 Agent']},
|
|
215
|
+
{ph:'d',nm:'AI分析(需求+代码+知识库)',tm:'~5min',
|
|
216
|
+
in:'<b>PRD</b>: xxx/d/home/fcAB5rrt...<br><b>MR 868 代码变更</b> + <b>项目源码</b>',
|
|
217
|
+
out:'<b>case-generation skill</b> → <code>test-cases.yaml</code> 版本1.0<br>5模块: <b>AG</b>(遮罩层,8用例) <b>KB</b>(禁用筛选,4用例) <b>WW</b>(字符限制,5用例) <b>SK</b>(锁定权限,6用例) <b>RG</b>(回归,2用例)<br><b style="color:var(--warn)">需求偏差2处</b>: 欢迎语300≠PRD200 / 去掉"可在DataAgent中@"<br><br><b>script-generation skill</b> → <code>poms/AgentDetailPage.ts</code> (5.21KB) / <code>NotAvailablePage.ts</code> (10.36KB) / <code>SkillDetailPage.ts</code> (12.54KB)<br><code>fixtures/test-data.ts</code> → <b>agents.tcPortal.id=636</b><br><b>@keveModel/@keveScene</b> 打标<br><br><b>有疑惑 → 人工check补齐</b>',
|
|
218
|
+
th:'提交代码时自动触发keve test。两个skill并行工作: case-generation分析PRD+MR生成test-cases.yaml(发现2处需求偏差);script-generation分析项目源码生成POM+test-data.ts+打标。中间有疑惑信息(如定位器歧义、需求模糊)需要人工check补齐。',
|
|
219
|
+
ks:['case-generation','script-generation','需求偏差2处','人工check']},
|
|
220
|
+
{ph:'d',nm:'测试计划设计(可执行脚本)',tm:'~4min',
|
|
221
|
+
in:'<code>test-cases.yaml</code>(25+用例) + <b>POM类</b>(7个) + <code>test-data.ts</code>(tcPortal.id=636)',
|
|
222
|
+
out:'__CODE_BLOCK__',
|
|
223
|
+
th:'基于test-cases.yaml(测试用例)和POM(测试知识),编写6个Playwright可执行测试计划(spec)。每个spec定义模块、场景、测试目标(步骤和预期)。这就是集成/E2E脚本编写。',
|
|
224
|
+
ks:['6 spec','@keveGoal','keveAssert','可执行测试计划']},
|
|
225
|
+
{ph:'d',nm:'执行+评估+修复(loop)',tm:'18轮/4h',
|
|
226
|
+
in:'<b>可执行测试计划</b>(6 Playwright spec) + <code>playwright.config.ts</code> + <b>3 workers</b> 并行',
|
|
227
|
+
out:'<b>测试报告</b>: R18 最终结果 24 fail / 48 total<br>keveAssert评估: <b>confidence</b>评分 + <b>4分类根因</b><br>67% visual(B类-遮罩层断言噪声) / 20% script(D类) / 8% assert(C类) / 5% env(A类)<br><b style="color:var(--warn)">关键结论</b>: B类不应进修复循环 → D类进修复循环(loop) → R2:32→R18:24',
|
|
228
|
+
th:'keve-test-agent编排执行+评估+修复的闭环loop。Round 2执行32 fail→keveAssert智能评估根因→D类(script)进入修复循环→修复spec→重跑→再评估→loop直到通过或达到上限。实际18轮: 67% B类(visual)不应进循环但被混入,导致修复无效。结论: loop应只针对D类。',
|
|
229
|
+
ks:['keve-test-agent','闭环loop','D类修复','B类跳过']},
|
|
230
|
+
{ph:'d',nm:'同步平台(测试计划+结果)',tm:'~30s',
|
|
231
|
+
in:'<code>test-cases.yaml</code>(测试计划) + <b>执行结果</b>(24/48 failed) + <b>MR 868 diff</code>(代码变更) + <b>PRD链接</b>(需求信息)',
|
|
232
|
+
out:'<b>keve平台任务记录</b>(MR 868)<br><b>项目资产沉淀</b>:<br>POM库(7个Page Object) → agent维护<br>test-data.ts → agent维护<br>test-cases.yaml → agent维护<br>评估基线(confidence历史)',
|
|
233
|
+
th:'测试计划和执行结果同步到keve平台。项目资产(POM+用例+数据)由agent持续维护更新。同步不阻塞——失败仅warning。',
|
|
234
|
+
ks:['测试计划','执行结果','代码变更','项目资产']},
|
|
235
|
+
{ph:'t',nm:'提测触发→平台分发',tm:'~1s',
|
|
236
|
+
in:'<b>开发标记提测</b>(MR 868 ready for test)',
|
|
237
|
+
out:'<b>keve平台拉取</b>: 测试计划 + 代码变更 + 需求<br>→ <b>自动分发</b>: 张三(AG+SK模块) / 李四(KB+WW模块)<br>→ <b>桌面推送</b>: "MR 868测试完成, 24个问题"',
|
|
238
|
+
th:'开发标记提测后,keve平台拉取相关信息(测试计划、代码变更、需求),自动分发到各测试人员。桌面应用推送通知。',
|
|
239
|
+
ks:['提测触发','信息拉取','人员分发','桌面推送']},
|
|
240
|
+
{ph:'t',nm:'桌面应用通知',tm:'~实时',
|
|
241
|
+
in:'<b>平台分发信息</b>(MR标题+AI概要+根因+报告链接)',
|
|
242
|
+
out:'<b>桌面推送</b>:<br>MR 868 测试完成<br>24个问题 (67%视觉类)<br>点击查看 → bs3.../report.html',
|
|
243
|
+
th:'keve桌面应用推送通知到测试同学。',
|
|
244
|
+
ks:['桌面推送','即时通知','一键查看']},
|
|
245
|
+
{ph:'t',nm:'可视化查看+二次测试+修正',tm:'~15min',
|
|
246
|
+
in:'<b>开发资产</b>: POM(AgentDetailPage.ts等) + test-cases.yaml + test-data.ts<br><b>AI测试结果</b>: 截图回放 + confidence + 根因标注(B类67%/D类20%)',
|
|
247
|
+
out:'<b>确认</b>: B类为系统性缺陷(断言噪声),非bug<br><b>修正</b>: 遮罩层断言→容忍噪声描述<br><b>补充</b>: 增加WW-06(300字符边界用例)<br><b>筛选</b>: AG核心流程 → 定时巡检',
|
|
248
|
+
th:'测试同学参考开发资产和AI结果二次测试: 确认B类为系统性缺陷而非bug,修正断言容忍噪声,补充遗漏用例,筛选核心流程交给keve平台巡检。',
|
|
249
|
+
ks:['参考开发资产','二次测试','修正断言','筛选巡检']},
|
|
250
|
+
{ph:'o',nm:'沉淀可执行脚本+用例',tm:'持续',
|
|
251
|
+
in:'<b>开发+测试阶段产出</b>: 6 Playwright spec + test-cases.yaml + 7 POM + 修正断言',
|
|
252
|
+
out:'<b>keve平台资产库</b>:<br><code>agent-mask.spec.ts</code> (可执行,含修正后的断言)<br><code>test-cases.yaml</code> (自然语言: AG-01 TC类型无权限状态描述简化)<br><code>poms/*.ts</code> (POM库,可复用)<br><b>agent持续维护更新</b>',
|
|
253
|
+
th:'keve平台沉淀可直接执行的Playwright脚本和自然语言用例。由agent持续维护更新。',
|
|
254
|
+
ks:['可执行脚本','自然语言用例','POM库','agent维护']},
|
|
255
|
+
{ph:'o',nm:'定时巡检调度执行',tm:'定时',
|
|
256
|
+
in:'<b>keve平台资产</b>(spec+yaml) + <b>调度配置</b>(每日10:00 / 每周一)',
|
|
257
|
+
out:'<b>线上巡检结果</b> → 平台报告<br>自动回归: AG核心流程(遮罩层) + SK核心流程(锁定权限)<br>环境稳定性检查',
|
|
258
|
+
th:'keve平台配置调度任务,复用可执行脚本定时线上巡检。',
|
|
259
|
+
ks:['调度配置','脚本复用','线上巡检','自动回归']},
|
|
260
|
+
];
|
|
261
|
+
|
|
262
|
+
const NM=[1,1,1,1,2,3,3,4,5,6];
|
|
263
|
+
// step0→n1(init), step1→n1(AI分析), step2→n1(测试计划), step3→n1(执行loop), step4→n2(同步), step5→n3(分发), step6→n3(通知), step7→n4(协同), step8→n5(沉淀), step9→n6(巡检)
|
|
264
|
+
|
|
265
|
+
const CODE_SPEC=`@keveScene("AG-01: TC类型-无权限状态描述简化")
|
|
266
|
+
static async testTcPortalNoPermissionMask({ page, keveGoal, keveAssert }) {
|
|
267
|
+
const notAvailablePage = new NotAvailablePage(page);
|
|
268
|
+
await keveGoal({
|
|
269
|
+
precondition: "通过链接改id访问TC来源且无权限的智能应用",
|
|
270
|
+
step: "进入TC类型智能应用详情页(无权限)",
|
|
271
|
+
expected: "页面显示遮罩层,描述含...即将下线,不再独立维护"
|
|
272
|
+
}, async () => {
|
|
273
|
+
await notAvailablePage.navigateToAgentDetail(
|
|
274
|
+
testData.agents.tcPortal.id, "edit", false);
|
|
275
|
+
await notAvailablePage.assertNotAvailableVisible(true);
|
|
276
|
+
await keveAssert("遮罩层可见,描述包含...", { label: "AG01-Step1" });
|
|
277
|
+
});
|
|
278
|
+
await keveGoal({
|
|
279
|
+
step: "观察按钮组区域",
|
|
280
|
+
expected: "按钮组不显示,整个按钮组区域被隐藏"
|
|
281
|
+
}, async () => {
|
|
282
|
+
await notAvailablePage.assertButtonGroupHidden();
|
|
283
|
+
await keveAssert("按钮组区域完全隐藏", { label: "AG01-Step2" });
|
|
284
|
+
});
|
|
285
|
+
}`;
|
|
286
|
+
|
|
287
|
+
function mkCode(code){
|
|
288
|
+
const pre=document.createElement('pre');
|
|
289
|
+
pre.style.cssText='font-size:11px;background:#1e293b;color:#e2e8f0;padding:10px 12px;border-radius:6px;margin:6px 0;line-height:1.45;overflow-x:auto;font-family:var(--mono)';
|
|
290
|
+
pre.textContent=code;
|
|
291
|
+
return pre;
|
|
292
|
+
}
|
|
293
|
+
const NDS=[document.getElementById('n1'),document.getElementById('n2'),document.getElementById('n3'),document.getElementById('n4'),document.getElementById('n5'),document.getElementById('n6')];
|
|
294
|
+
const PHS=[document.getElementById('ph-d'),document.getElementById('ph-t'),document.getElementById('ph-o')];
|
|
295
|
+
|
|
296
|
+
let cur=0,playing=false,timer=null,spd=1200;
|
|
297
|
+
const tlEl=document.getElementById('tlEl');
|
|
298
|
+
const cardsEl=document.getElementById('cards');
|
|
299
|
+
|
|
300
|
+
function build(){
|
|
301
|
+
tlEl.innerHTML='';
|
|
302
|
+
let lp='';
|
|
303
|
+
S.forEach((s,i)=>{
|
|
304
|
+
if(s.ph!==lp){lp=s.ph;if(i>0){const sep=document.createElement('div');sep.className='Tl-sep';tlEl.appendChild(sep)}}
|
|
305
|
+
const t=document.createElement('div');t.className='Tl-i '+s.ph;t.onclick=()=>go(i);t.textContent=s.nm;tlEl.appendChild(t);
|
|
306
|
+
});
|
|
307
|
+
cardsEl.innerHTML='';
|
|
308
|
+
S.forEach((s,i)=>{
|
|
309
|
+
const c=document.createElement('div');c.className='Scard '+s.ph;c.id='c'+i;
|
|
310
|
+
const phTxt=s.ph==='d'?'开发阶段':s.ph==='t'?'测试阶段':'运维阶段';
|
|
311
|
+
c.innerHTML=`
|
|
312
|
+
<div class="Sc-hd">
|
|
313
|
+
<div class="Sc-ph ${s.ph}">${phTxt}</div>
|
|
314
|
+
<div class="Sc-nm">${s.nm}</div>
|
|
315
|
+
<div class="Sc-tm">${s.tm}</div>
|
|
316
|
+
</div>
|
|
317
|
+
<div class="Sc-think ${s.ph}">
|
|
318
|
+
<div class="Sc-thk-l">AI 思考过程</div>
|
|
319
|
+
<div style="font-size:12px;color:var(--g600);line-height:1.5">${s.th}</div>
|
|
320
|
+
</div>
|
|
321
|
+
<div class="Sc-io">
|
|
322
|
+
<div class="Sc-in">
|
|
323
|
+
<div class="Sc-io-l">▶ 输入 <span class="arrow">→</span></div>
|
|
324
|
+
<div class="Sc-io-v">${s.in}</div>
|
|
325
|
+
</div>
|
|
326
|
+
<div class="Sc-out">
|
|
327
|
+
<div class="Sc-io-l">▶ 输出 <span class="arrow">→</span></div>
|
|
328
|
+
<div class="Sc-io-v">${s.out==='__CODE_BLOCK__'?'<b>6个可执行Playwright spec</b> — 每个包含模块+场景+测试目标(步骤+预期)<br><br><b>agent-mask.spec.ts</b> (15.49KB) @keveModel("智能应用详情页-遮罩层"):':s.out}</div>
|
|
329
|
+
</div>
|
|
330
|
+
</div>
|
|
331
|
+
<div class="Sc-keys">${s.ks.map(k=>`<div class="Sc-k ${s.ph}">${k}</div>`).join('')}</div>
|
|
332
|
+
`;
|
|
333
|
+
cardsEl.appendChild(c);
|
|
334
|
+
if(s.out==='__CODE_BLOCK__'){
|
|
335
|
+
const outV=c.querySelector('.Sc-out .Sc-io-v');
|
|
336
|
+
if(outV)outV.appendChild(mkCode(CODE_SPEC));
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function go(i){
|
|
342
|
+
cur=i;document.getElementById('Mn').textContent=i+1;
|
|
343
|
+
tlEl.querySelectorAll('.Tl-i').forEach((el,j)=>{el.classList.remove('act','done');if(j===i)el.classList.add('act');else if(j<i)el.classList.add('done')});
|
|
344
|
+
S.forEach((s,j)=>{document.getElementById('c'+j).classList.toggle('act',j===i)});
|
|
345
|
+
const ni=NM[i];
|
|
346
|
+
NDS.forEach((n,j)=>{n.classList.remove('act','done');if(j===ni)n.classList.add('act');else if(j<ni)n.classList.add('done')});
|
|
347
|
+
PHS.forEach((p,j)=>{p.classList.remove('act');
|
|
348
|
+
if(S[i].ph==='d'&&j===0)p.classList.add('act');
|
|
349
|
+
if(S[i].ph==='t'&&j===1)p.classList.add('act');
|
|
350
|
+
if(S[i].ph==='o'&&j===2)p.classList.add('act');
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function tp(){
|
|
355
|
+
if(playing){playing=false;clearTimeout(timer);
|
|
356
|
+
document.getElementById('Mbtn').classList.remove('on');
|
|
357
|
+
document.getElementById('Mi').innerHTML='▶';document.getElementById('Mt').textContent='播放';
|
|
358
|
+
}else{playing=true;if(cur>=9)cur=-1;
|
|
359
|
+
document.getElementById('Mbtn').classList.add('on');
|
|
360
|
+
document.getElementById('Mi').innerHTML='▮▮';document.getElementById('Mt').textContent='停止';
|
|
361
|
+
nx();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
function nx(){if(!playing)return;cur++;if(cur>9){cur=0;tlEl.querySelectorAll('.Tl-i').forEach(e=>e.classList.remove('done'))}go(cur);timer=setTimeout(nx,spd)}
|
|
365
|
+
function cs(){spd=parseInt(document.getElementById('Ms').value);if(playing){clearTimeout(timer);timer=setTimeout(nx,spd)}}
|
|
366
|
+
|
|
367
|
+
build();go(0);
|
|
368
|
+
</script>
|
|
369
|
+
</body>
|
|
370
|
+
</html>
|