@szc-ft/mcp-szcd-client 0.38.0 → 0.39.0
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/opencode-extension/skills/local-browser-test/SKILL.md +95 -18
- package/opencode-extension/skills/local-browser-test/lib/global-setup.js +2 -1
- package/opencode-extension/skills/local-browser-test/lib/html-reporter.js +341 -164
- package/opencode-extension/skills/local-browser-test/local-browser-executor.js +47 -11
- package/package.json +1 -1
- package/qwen-extension/qwen-extension.json +1 -1
- package/qwen-extension/skills/local-browser-test/SKILL.md +95 -18
- package/qwen-extension/skills/local-browser-test/lib/global-setup.js +2 -1
- package/qwen-extension/skills/local-browser-test/lib/html-reporter.js +341 -164
- package/qwen-extension/skills/local-browser-test/local-browser-executor.js +47 -11
- package/standard-skill/local-browser-test/SKILL.md +95 -18
- package/standard-skill/local-browser-test/lib/global-setup.js +2 -1
- package/standard-skill/local-browser-test/lib/html-reporter.js +341 -164
- package/standard-skill/local-browser-test/local-browser-executor.js +47 -11
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: local-browser-test
|
|
3
|
-
description: 在用户真实 Chrome
|
|
3
|
+
description: 在用户真实 Chrome 中执行自动化测试,覆盖测试用例批量执行、深度表单填写、微前端测试、长任务生命周期、设计稿对比、JS 错误诊断。通过 puppeteer-core 连接 CDP,天然继承登录态/微前端环境。
|
|
4
4
|
compatibility:
|
|
5
5
|
tools:
|
|
6
6
|
- run_command
|
|
@@ -72,7 +72,7 @@ export EXECUTOR="$SKILL_DIR/local-browser-executor.js"
|
|
|
72
72
|
|
|
73
73
|
## 🎯 三种典型任务(场景驱动)
|
|
74
74
|
|
|
75
|
-
### 任务 A
|
|
75
|
+
### 任务 A:测试用例批量执行(首选)
|
|
76
76
|
|
|
77
77
|
用户说"执行 P0 用例 / 批量测试 / 生命周期测试"时,**不要写 ad-hoc puppeteer 脚本**,构造 testCase JSON:
|
|
78
78
|
|
|
@@ -144,7 +144,7 @@ NODE_PATH=~/.szcd-mcp/deps/node_modules node "$EXECUTOR" --action api-capture --
|
|
|
144
144
|
|
|
145
145
|
```
|
|
146
146
|
Agent / SKILL.md
|
|
147
|
-
→ testCase JSON ←
|
|
147
|
+
→ testCase JSON ← 测试用例首选入口
|
|
148
148
|
→ $SKILL_DIR/local-browser-executor.js ($EXECUTOR)
|
|
149
149
|
→ $SKILL_DIR/lib/browser-engine.js (executeTestCase + Ant 适配 + expect)
|
|
150
150
|
→ $SKILL_DIR/lib/ant-adapter.js (Select/TreeSelect/Input/Radio/...)
|
|
@@ -672,14 +672,32 @@ NODE_PATH=~/.szcd-mcp/deps/node_modules node "$EXECUTOR" \
|
|
|
672
672
|
- `--expect-result-contains <text>`:结果 JSON 包含指定文本
|
|
673
673
|
|
|
674
674
|
### 执行测试计划 JSON(ES Module 版)
|
|
675
|
+
|
|
676
|
+
**⚠️ 禁用 `--action plan`(该分支提前 `process.exit`,不会生成 HTML 报告)**
|
|
677
|
+
直接用 `--plan-file`:
|
|
678
|
+
|
|
675
679
|
```bash
|
|
676
680
|
NODE_PATH=~/.szcd-mcp/deps/node_modules node "$EXECUTOR" \
|
|
677
|
-
--action plan \
|
|
678
681
|
--plan-file /tmp/test-plan.json \
|
|
679
|
-
--
|
|
682
|
+
--config /path/to/config.yaml
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
工作区默认在 CWD 的 `.lbt/`,无需手动传 `--workspace`:
|
|
686
|
+
|
|
687
|
+
```
|
|
688
|
+
.lbt/
|
|
689
|
+
├── config.yaml ← 项目配置
|
|
690
|
+
├── reports/ ← HTML 报告(趋势图 + 过滤 + 详情页 + 截图)
|
|
691
|
+
│ ├── index.html
|
|
692
|
+
│ └── runs/<id>/
|
|
693
|
+
├── tmp/ ← 执行过程临时文件(截图等)
|
|
694
|
+
├── auth/ ← 保存的登录态
|
|
695
|
+
└── plans/ ← 回归脚本
|
|
680
696
|
```
|
|
681
697
|
|
|
682
|
-
`--
|
|
698
|
+
不传 `--workspace` 时默认 `cwd/.lbt`,也可用 `--workspace <dir>` 指定其他目录。
|
|
699
|
+
|
|
700
|
+
与 `--action test-case` 的区别:plan 不走 dataset 循环,适合单次执行。
|
|
683
701
|
|
|
684
702
|
### 快速诊断(JS错误 + 网络 + 资源 + iframe)
|
|
685
703
|
```bash
|
|
@@ -726,12 +744,15 @@ NODE_PATH=~/.szcd-mcp/deps/node_modules node "$EXECUTOR" \
|
|
|
726
744
|
### 可选参数
|
|
727
745
|
|
|
728
746
|
- `--cdp-url http://localhost:9222`:CDP 地址(默认 9222)
|
|
729
|
-
- `--url <url>`:目标页面 URL(不存在则导航)
|
|
747
|
+
- `--page-url <url>`:目标页面 URL(不存在则导航)
|
|
730
748
|
- `--url-contains <keyword>`:按关键词查找已打开的页面
|
|
731
749
|
- `--frame-url-contains <keyword>`:observe 时按 iframe URL 片段匹配目标 frame
|
|
732
750
|
- `--frame-content-contains <keyword>`:observe 时按 iframe 文本内容匹配目标 frame
|
|
733
751
|
- `--frame-index <n>`:observe 时按 frame 下标选择目标 frame
|
|
734
|
-
- `--
|
|
752
|
+
- `--plan-file <path>`:测试计划 JSON 文件路径
|
|
753
|
+
- `--config <path>`:配置文件路径(如 config.yaml)
|
|
754
|
+
- `--workspace <dir>`:工作区目录,默认 `cwd/.lbt`。存放 `reports/`(HTML 报告)、`tmp/`(临时文件)、`auth/`(登录态)、`plans/`(回归脚本)
|
|
755
|
+
- `--wait <ms>`:额外等待时间(默认因 action 而异:api-capture 15000,其余 5000)
|
|
735
756
|
- `--output <path>`:JSON 结果输出路径
|
|
736
757
|
- `--output-dir <dir>`:截图/产物目录
|
|
737
758
|
- `--filename <name>`:截图文件名
|
|
@@ -741,12 +762,41 @@ NODE_PATH=~/.szcd-mcp/deps/node_modules node "$EXECUTOR" \
|
|
|
741
762
|
- `--click <selector>`:点击元素(支持 text=/role=/~)
|
|
742
763
|
- `--type <text>`:输入文本
|
|
743
764
|
- `--hover <selector>`:悬停元素
|
|
744
|
-
- `--
|
|
745
|
-
- `--
|
|
746
|
-
- `--
|
|
765
|
+
- `--expression <js>`:evaluate 执行的 JS 表达式(需 IIFE 包裹)
|
|
766
|
+
- `--fail-on-falsy`:evaluate 结果为 falsy 时标记 FAIL
|
|
767
|
+
- `--expect-result-contains <text>`:evaluate 结果包含指定文本
|
|
768
|
+
- `--include-response-body`:api-capture 包含响应体
|
|
769
|
+
- `--include-all-targets`:api-capture 监听全部 target(含非 frame 的 worker/extension)
|
|
770
|
+
- `--reload`:api-capture 前重载页面
|
|
771
|
+
- `--url-pattern <pattern>`:api-capture 按 URL 过滤
|
|
772
|
+
- `--method <method>`:api-capture 按 HTTP 方法过滤
|
|
773
|
+
- `--capture-file <path>`:assert-api 读取的捕获结果文件
|
|
774
|
+
- `--max-failed <n>`:assert-api 允许的最大失败请求数
|
|
775
|
+
- `--forbid-status-gte <code>`:assert-api 禁止的状态码阈值
|
|
776
|
+
- `--required-url <pattern>`:assert-api 必需出现的 URL 模式
|
|
777
|
+
- `--include-request-body`:api-capture 包含请求体
|
|
778
|
+
- `--no-request-body`:api-capture 排除请求体
|
|
779
|
+
- `--target-url-contains <text>`:api-capture 目标 frame URL 包含
|
|
747
780
|
- `--interval <ms>`:watch 模式间隔(默认 5000)
|
|
748
781
|
- `--max-rounds <n>`:watch 最大轮数(默认 60)
|
|
749
782
|
- `--allow-launch`:根执行器 action 模式允许无 CDP 时启动 headless Chrome;默认不启用,优先保障真实用户浏览器链路
|
|
783
|
+
- `--ci`:CI 模式(自动设置 screenshot=always, video=on, trace=on, retries=2)
|
|
784
|
+
- `--retries <n>`:用例级重试次数
|
|
785
|
+
- `--flaky-threshold <n>`:Flaky 测试阈值
|
|
786
|
+
- `--screenshot <always|only-on-failure>`:截图策略
|
|
787
|
+
- `--video <on|off|only-on-failure>`:录像策略
|
|
788
|
+
- `--trace <on|off>`:trace 录制
|
|
789
|
+
- `--record-har`:录制 HAR
|
|
790
|
+
- `--storage-state <path>`:认证存储状态文件路径(用于 global-setup)
|
|
791
|
+
- `--global-setup`:全局设置模式(保存登录态)
|
|
792
|
+
- `--init-force`:强制初始化工作区
|
|
793
|
+
- `--project <name>`:多环境项目选择
|
|
794
|
+
- `--env <name>`:环境选择
|
|
795
|
+
- `--tags <tag>`:按 tag 筛选用例
|
|
796
|
+
- `--exclude-tags <tag>`:排除 tag
|
|
797
|
+
- `--tag-mode <any|all>`:tag 匹配模式
|
|
798
|
+
- `--no-retry-actions`:禁用写操作重试
|
|
799
|
+
- `--no-reload`:diagnose 跳过页面重载
|
|
750
800
|
|
|
751
801
|
## AI 语义断言(aiAssert)
|
|
752
802
|
|
|
@@ -822,24 +872,47 @@ cd ~/.szcd-mcp/deps && npm install --registry=https://registry.npmmirror.com --@
|
|
|
822
872
|
- passed = total:全部通过
|
|
823
873
|
- 有失败步骤:根据 `step` + `error` 字段定位代码问题
|
|
824
874
|
|
|
825
|
-
###
|
|
875
|
+
### HTML 报告(推荐)
|
|
876
|
+
|
|
877
|
+
传 `--workspace <dir>` 时自动生成 Playwright 风格 HTML 报告:
|
|
878
|
+
|
|
879
|
+
```
|
|
880
|
+
<workspace>/reports/
|
|
881
|
+
├── index.html ← 入口:趋势图 + 过滤 + 运行列表
|
|
882
|
+
├── trend.json ← 按日聚合数据
|
|
883
|
+
└── runs/
|
|
884
|
+
└── <timestamp>-pid<N>/
|
|
885
|
+
├── index.html ← 详情页:步骤表格、截图、错误展开
|
|
886
|
+
├── result.json ← 原始结果(脱敏)
|
|
887
|
+
└── screenshots/ ← 截图副本
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
入口支持交互过滤(状态 + 关键词搜索)、echarts 趋势图、详情页"返回列表"导航、截图展示。
|
|
891
|
+
|
|
892
|
+
### 结果 JSON 结构(stdout)
|
|
826
893
|
```json
|
|
827
894
|
{
|
|
828
895
|
"planId": "xxx",
|
|
896
|
+
"description": "...",
|
|
829
897
|
"mode": "connect",
|
|
898
|
+
"startTime": "2026-07-01T10:00:00.000Z",
|
|
899
|
+
"duration": "1583",
|
|
830
900
|
"steps": [
|
|
831
|
-
{ "index": 1, "step": "navigate", "status": "PASS", "duration": 1200, ... },
|
|
832
|
-
{ "index": 2, "step": "screenshot", "status": "PASS", "duration": 500,
|
|
833
|
-
|
|
901
|
+
{ "index": 1, "step": "navigate", "status": "PASS", "duration": "1200", ... },
|
|
902
|
+
{ "index": 2, "step": "screenshot", "status": "PASS", "duration": "500",
|
|
903
|
+
"filepath": "/tmp/.../screenshot.png", ... }
|
|
834
904
|
],
|
|
835
905
|
"summary": {
|
|
836
|
-
"total":
|
|
837
|
-
"fidelity":
|
|
906
|
+
"total": "9", "passed": "9", "failed": "0",
|
|
907
|
+
"fidelity": null
|
|
838
908
|
},
|
|
909
|
+
"browserInfo": { "mode": "connect", "cdpUrl": "...", "currentUrl": "...", "totalPages": 6 },
|
|
839
910
|
"outputDir": "/tmp/browser-test-xxx"
|
|
840
911
|
}
|
|
841
912
|
```
|
|
842
913
|
|
|
914
|
+
注意:`startTime`(非 `startedAt`)、`duration`(非 `durationMs`)。HTML 报告器内部会把 `startTime` → `startedAt`、`duration` → `durationMs`、`summary.*` → `stats.*` 做字段归一化。
|
|
915
|
+
|
|
843
916
|
## 批量动态菜单扫描(runTask)
|
|
844
917
|
|
|
845
918
|
适用场景:测试系统有 N 条动态路由(来自后端菜单接口),要逐条点击触发并验证接口是否返回 200。6/18 反馈中,AI 最终用 130 余条 `act --menu-path` + `api-capture` 手工组合走完 129 条菜单——`runTask` 把这套流水固化为单步骤。
|
|
@@ -966,7 +1039,7 @@ cat > /tmp/login.json <<EOF
|
|
|
966
1039
|
EOF
|
|
967
1040
|
|
|
968
1041
|
# 3. 执行登录
|
|
969
|
-
NODE_PATH=~/.szcd-mcp/deps/node_modules node "$EXECUTOR" --
|
|
1042
|
+
NODE_PATH=~/.szcd-mcp/deps/node_modules node "$EXECUTOR" --plan-file /tmp/login.json --config /path/to/config.yaml
|
|
970
1043
|
```
|
|
971
1044
|
|
|
972
1045
|
**LLM 处理流程:**
|
|
@@ -1014,6 +1087,10 @@ NODE_PATH=~/.szcd-mcp/deps/node_modules node "$EXECUTOR" --action plan --plan-fi
|
|
|
1014
1087
|
- ❌ **v20 格式**(生产环境,App-Bound Encryption):需 Python `pywin32` + `cryptography` 方案
|
|
1015
1088
|
- ⚠️ Windows 专属(DPAPI),macOS/Linux 需 Keychain/KWallet 方案
|
|
1016
1089
|
|
|
1090
|
+
## 已知技术债
|
|
1091
|
+
|
|
1092
|
+
- **代码重复**:`normalizeForReport`(executor.js)与 `normalizeRunResult`(html-reporter.js)是相同字段归一化逻辑的两份拷贝。修改任何字段映射时必须同步两处。
|
|
1093
|
+
|
|
1017
1094
|
## 反模式备忘(来自 6/17 + 6/18 实战反馈)
|
|
1018
1095
|
|
|
1019
1096
|
| 错误做法 | 正确做法 | 原因 |
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import fs from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
9
10
|
import { captureStorageState } from "./storage-state.js";
|
|
10
11
|
import { redact } from "./redact.js";
|
|
11
12
|
|
|
@@ -19,7 +20,7 @@ export async function globalSetupTakeover(page, outputPath) {
|
|
|
19
20
|
|
|
20
21
|
// 落盘前 redact(cookie value 也可能含敏感 token)
|
|
21
22
|
const safe = redact(state);
|
|
22
|
-
fs.mkdirSync(
|
|
23
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
23
24
|
fs.writeFileSync(outputPath, JSON.stringify(safe, null, 2));
|
|
24
25
|
console.log(`✓ storageState 已保存: ${outputPath}`);
|
|
25
26
|
console.log(` cookies: ${safe.cookies?.length ?? 0}, origins: ${safe.origins?.length ?? 0}`);
|