@microi.net/cli 4.9.5 → 4.9.7
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/.codebuddy-plugin/marketplace.json +2 -2
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.workbuddy-plugin/marketplace.json +2 -2
- package/.workbuddy-plugin/plugin.json +1 -1
- package/README.md +7 -12
- package/assets/build-meta.json +6 -5
- package/package.json +1 -1
- package/scripts/mcp-server.js +83 -83
- package/scripts/microi-cli.js +80 -92
- package/scripts/microi-codex-broker.js +418 -0
- package/scripts/microi-codex-router.js +159 -65
- package/scripts/microi-skills.meta.json +349 -190
- package/skills/.microi-skills-version.json +2 -2
- package/skills/.progressive-disclosure-manifest.json +3566 -0
- package/skills/ai-engine/SKILL.md +1 -1
- package/skills/ai-platform-governance/SKILL.md +22 -167
- package/skills/ai-platform-governance/references/progressive-01-/345/212/237/350/203/275/345/274/200/345/205/263.md +190 -0
- package/skills/app-store/SKILL.md +1 -1
- package/skills/business-blueprint/SKILL.md +1 -1
- package/skills/datasource-engine/SKILL.md +1 -1
- package/skills/dos-orm/SKILL.md +1 -1
- package/skills/job-engine/SKILL.md +1 -1
- package/skills/message-notification/SKILL.md +1 -1
- package/skills/microi-ai-application/SKILL.md +1 -1
- package/skills/microi-client-frontend/SKILL.md +18 -435
- package/skills/microi-client-frontend/references/progressive-01-3-/345/212/250/346/200/201/346/214/211/351/222/256/347/263/273/347/273/237.md +144 -0
- package/skills/microi-client-frontend/references/progressive-02-8-/350/277/220/350/241/214/346/227/266/351/253/230/351/242/221/345/235/221/345/244/215/347/233/230.md +178 -0
- package/skills/microi-client-frontend/references/progressive-03-vue3-/345/211/215/347/253/257/345/276/256/346/234/215/345/212/241/345/256/277/344/270/273/350/247/204/345/210/231.md +144 -0
- package/skills/microi-codex/SKILL.md +4 -4
- package/skills/microi-codex-installer/SKILL.md +25 -36
- package/skills/microi-datasource-mapping/SKILL.md +1 -1
- package/skills/microi-db-schema/SKILL.md +4 -4
- package/skills/microi-db-schema/references/schema-overview.md +1 -1
- package/skills/microi-db-schema/references/schema.md +1 -1
- package/skills/microi-db-schema/references/table-catalog.md +1 -1
- package/skills/microi-deployment/SKILL.md +1 -1
- package/skills/microi-docs-coverage/SKILL.md +1 -1
- package/skills/microi-form-engine/SKILL.md +2 -2
- package/skills/microi-form-layout/SKILL.md +20 -226
- package/skills/microi-form-layout/references/progressive-01-3-/344/270/211/347/247/215/345/210/206/347/273/204/347/232/204/345/255/230/345/202/250/344/270/216/351/205/215/347/275/256.md +235 -0
- package/skills/microi-frontend-sdk/SKILL.md +18 -152
- package/skills/microi-frontend-sdk/references/progressive-01-token-/345/275/223/345/211/215/347/231/273/345/275/225/347/224/250/346/210/267/344/270/216/345/275/223/345/211/215/347/273/210/347/253/257/347/231/273/345/275/225/345/215/217/350/256/256.md +171 -0
- package/skills/microi-left-right-layout/SKILL.md +1 -1
- package/skills/microi-microservice/SKILL.md +8 -1
- package/skills/microi-microservice/references/runtime-delivery.md +4 -0
- package/skills/microi-mobile-app-quality/SKILL.md +23 -289
- package/skills/microi-mobile-app-quality/references/progressive-01-4-/351/207/215/350/246/201/346/214/211/351/222/256/345/277/205/351/241/273/345/270/246/345/233/276/346/240/207.md +209 -0
- package/skills/microi-mobile-app-quality/references/progressive-02-9-/344/270/273/351/242/230/345/210/207/346/215/242/345/277/205/351/241/273/347/234/237/345/256/236/344/270/224/345/205/250/345/261/200/347/224/237/346/225/210.md +117 -0
- package/skills/microi-solution-quotation/SKILL.md +1 -1
- package/skills/microi-system-delivery/SKILL.md +17 -381
- package/skills/microi-system-delivery/references/progressive-01-/346/240/207/345/207/206/345/267/245/344/275/234/346/265/201.md +186 -0
- package/skills/microi-system-delivery/references/progressive-02-/350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/345/277/205/351/241/273/350/246/206/347/233/226/347/232/204/345/235/221.md +210 -0
- package/skills/microi-ui/SKILL.md +20 -170
- package/skills/microi-ui/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/234/272/346/231/257/350/223/235/345/233/276.md +183 -0
- package/skills/microi-uniapp-frontend/SKILL.md +27 -336
- package/skills/microi-uniapp-frontend/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/210/206/347/261/273-/345/217/214/346/240/217/345/210/227/350/241/250/347/213/254/347/253/213/346/273/232/345/212/250.md +225 -0
- package/skills/microi-uniapp-frontend/references/progressive-02-/345/205/263/351/224/256/344/270/232/345/212/241/350/265/204/344/272/247/344/270/215/345/276/227/351/273/230/350/256/244/351/200/211/344/270/255.md +154 -0
- package/skills/module-engine/SKILL.md +1 -1
- package/skills/ocr-engine/SKILL.md +1 -1
- package/skills/page-engine/SKILL.md +24 -272
- package/skills/page-engine/references/progressive-01-/346/211/200/346/234/211/347/273/204/344/273/266/347/261/273/345/236/213.md +234 -0
- package/skills/page-engine/references/progressive-02-/347/211/210/346/234/254/345/216/206/345/217/262-/345/271/266/345/217/221/344/277/235/345/255/230/344/270/216/345/233/236/346/273/232.md +60 -0
- package/skills/performance-testing/SKILL.md +1 -1
- package/skills/playwright-e2e/SKILL.md +25 -591
- package/skills/playwright-e2e/references/progressive-01-/345/205/250/350/207/252/345/212/250/347/231/273/345/275/225-/345/205/215/351/252/214/350/257/201/347/240/201-/344/275/206/344/270/215/345/205/215/345/257/206/347/240/201-/345/277/205/350/257/273.md +173 -0
- package/skills/playwright-e2e/references/progressive-02-/346/226/207/345/255/227/345/257/271/346/257/224/345/272/246/344/270/216/345/217/257/350/257/273/346/200/247/350/207/252/345/212/250/345/214/226/346/243/200/346/237/245-/345/277/205/345/201/232.md +183 -0
- package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +221 -0
- package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +69 -0
- package/skills/print-engine/SKILL.md +1 -1
- package/skills/production-readonly-audit/SKILL.md +1 -1
- package/skills/report-engine/SKILL.md +1 -1
- package/skills/scripts/optimize-progressive-disclosure.mjs +204 -0
- package/skills/scripts/refresh-progressive-disclosure.mjs +64 -0
- package/skills/scripts/validate-progressive-disclosure.mjs +52 -0
- package/skills/search-engine/SKILL.md +1 -1
- package/skills/spider-engine/SKILL.md +1 -1
- package/skills/translate-engine/SKILL.md +1 -1
- package/skills/ui-design/SKILL.md +27 -1462
- package/skills/ui-design/references/progressive-01-/351/242/234/350/211/262/344/275/223/347/263/273-css-variables-/346/224/257/346/214/201/344/270/273/351/242/230/345/210/207/346/215/242.md +218 -0
- package/skills/ui-design/references/progressive-02-/345/255/227/344/275/223.md +155 -0
- package/skills/ui-design/references/progressive-03-/345/212/250/346/225/210/350/247/204/350/214/203-/344/270/260/345/257/214/344/275/206/344/270/215/345/215/241.md +235 -0
- package/skills/ui-design/references/progressive-04-/347/273/204/344/273/266/351/243/216/346/240/274/351/200/237/346/237/245.md +152 -0
- package/skills/ui-design/references/progressive-05-/347/247/273/345/212/250/347/253/257/344/270/223/347/224/250/350/247/204/350/214/203.md +238 -0
- package/skills/ui-design/references/progressive-06-/344/270/273/351/242/230/345/210/207/346/215/242/345/256/236/347/216/260.md +194 -0
- package/skills/ui-design/references/progressive-07-/351/200/237/346/237/245-/344/273/216/345/244/264/346/220/255/345/273/272/344/270/200/344/270/252/347/247/273/345/212/250/347/253/257/351/241/265/351/235/242.md +207 -0
- package/skills/ui-design/references/progressive-08-/350/241/250/345/215/225/345/210/206/347/273/204/350/247/204/350/214/203-tabs-vs-collapsegroup-/345/274/272/345/210/266.md +142 -0
- package/skills/uniapp-mall-assets/SKILL.md +1 -1
- package/skills/unity-integration/SKILL.md +1 -1
- package/skills/v8-api-config/SKILL.md +1 -1
- package/skills/v8-cache-pattern/SKILL.md +1 -1
- package/skills/v8-crud-api/SKILL.md +21 -246
- package/skills/v8-crud-api/references/progressive-01-/346/237/245/350/257/242/345/210/227/350/241/250-/345/210/206/351/241/265.md +226 -0
- package/skills/v8-crud-api/references/progressive-02-where-/346/235/241/344/273/266/350/257/255/346/263/225/351/200/237/346/237/245.md +49 -0
- package/skills/v8-debugging/SKILL.md +1 -1
- package/skills/v8-explorer-tree/SKILL.md +1 -1
- package/skills/v8-export-import/SKILL.md +16 -426
- package/skills/v8-export-import/references/progressive-01-excellayout-/351/253/230/347/272/247/350/207/252/347/224/261/345/270/203/345/261/200.md +211 -0
- package/skills/v8-export-import/references/progressive-02-powerpoint-/345/257/274/345/207/272.md +202 -0
- package/skills/v8-export-import/references/progressive-03-/345/256/211/345/205/250-/346/200/247/350/203/275/346/263/250/346/204/217.md +42 -0
- package/skills/v8-file-upload/SKILL.md +17 -355
- package/skills/v8-file-upload/references/progressive-01-/345/205/254/346/234/211/346/241/266-vs-/347/247/201/346/234/211/346/241/266.md +227 -0
- package/skills/v8-file-upload/references/progressive-02-office-/346/226/207/344/273/266/345/234/250/347/272/277/347/274/226/350/276/221/347/211/210/346/234/254/345/217/267/350/247/204/345/210/231.md +149 -0
- package/skills/v8-formengine-http/SKILL.md +1 -1
- package/skills/v8-frontend-events/SKILL.md +20 -206
- package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +219 -0
- package/skills/v8-http-integration/SKILL.md +15 -237
- package/skills/v8-http-integration/references/progressive-01-get-/350/257/267/346/261/202.md +220 -0
- package/skills/v8-http-integration/references/progressive-02-/351/224/231/350/257/257/345/244/204/347/220/206/346/250/241/345/274/217.md +44 -0
- package/skills/v8-image-processing/SKILL.md +1 -1
- package/skills/v8-menu-buttons/SKILL.md +16 -512
- package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +221 -0
- package/skills/v8-menu-buttons/references/progressive-02-8-/346/250/241/345/274/217-f-/345/220/216/345/217/260/344/273/273/345/212/241/346/214/211/351/222/256-/351/225/277/344/273/273/345/212/241.md +224 -0
- package/skills/v8-menu-buttons/references/progressive-03-10-/345/217/215/346/250/241/345/274/217-/351/201/277/345/205/215.md +104 -0
- package/skills/v8-mongodb/SKILL.md +1 -1
- package/skills/v8-mq-mqtt/SKILL.md +12 -176
- package/skills/v8-mq-mqtt/references/progressive-01-v8-mqtt-iot-/347/211/251/350/201/224/347/275/221.md +181 -0
- package/skills/v8-saas-multi-tenant/SKILL.md +1 -1
- package/skills/v8-security/SKILL.md +17 -330
- package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +199 -0
- package/skills/v8-security/references/progressive-02-7-/346/227/245/345/277/227/350/256/260/345/275/225.md +158 -0
- package/skills/v8-sql-query/SKILL.md +1 -1
- package/skills/v8-table-event/SKILL.md +17 -237
- package/skills/v8-table-event/references/progressive-01-informv8-js-/350/241/250/345/215/225/346/211/223/345/274/200/344/272/213/344/273/266.md +216 -0
- package/skills/v8-table-event/references/progressive-02-/345/211/215/347/253/257/344/272/213/344/273/266/345/220/215-v8-eventname-/345/217/257/350/203/275/347/232/204/345/200/274.md +46 -0
- package/skills/v8-template-engine/SKILL.md +1 -1
- package/skills/v8-utilities/SKILL.md +1 -1
- package/skills/v8-workflow/SKILL.md +20 -161
- package/skills/v8-workflow/references/progressive-01-/350/212/202/347/202/271/345/274/200/345/247/213-v8-/344/272/213/344/273/266.md +180 -0
- package/skills/workspace-conventions/SKILL.md +36 -369
- package/skills/workspace-conventions/references/progressive-01-/347/211/210/346/234/254/346/233/264/346/226/260/346/227/245/345/277/227/344/277/235/346/212/244/350/247/204/345/210/231-/345/274/272/345/210/266.md +208 -0
- package/skills/workspace-conventions/references/progressive-02-microi-net-api-/346/234/254/345/234/260/345/220/257/345/212/250/347/272/246/345/256/232.md +196 -0
- package/skills/workspace-conventions/references/progressive-03-cli-/344/270/216-ide-/346/217/222/344/273/266/351/224/231/347/211/210/345/205/261/345/255/230/347/272/246/345/256/232.md +27 -0
|
@@ -3,7 +3,7 @@ name: playwright-e2e
|
|
|
3
3
|
description: 按 Microi 系统真实业务逻辑进行 Playwright 全自动化、全面测试。用于测试 PC Vue、uni-app H5、网站、界面引擎、移动商城、ApiEngine/FormEngine 契约、登录流程、写入闭环、网络防护、截图、报告和 Playwright Test for VSCode 集成。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
> **Codex
|
|
6
|
+
> **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
|
|
7
7
|
|
|
8
8
|
# Microi 吾码 Playwright E2E 自动化测试
|
|
9
9
|
|
|
@@ -15,6 +15,8 @@ description: 按 Microi 系统真实业务逻辑进行 Playwright 全自动化
|
|
|
15
15
|
|
|
16
16
|
`E2E` 是 `End-to-End`,中文通常叫"端到端测试"。它强调从用户入口开始,穿过前端页面、接口引擎、表单引擎、权限、缓存、数据库等真实链路,验证一条业务路径是否真的可交付。
|
|
17
17
|
|
|
18
|
+
<!-- microi-progressive:begin -->
|
|
19
|
+
<!-- microi-progressive:chunk id=playwright-e2e-000 sha256=f04614f276c139cfa50b9e46e89857675c6dc5e7cf0cfbfde76d6e6dbe9746c9 -->
|
|
18
20
|
## 是否需要 `-e2e` 后缀
|
|
19
21
|
|
|
20
22
|
建议保留 `playwright-e2e` 这个 skill 名称。
|
|
@@ -23,6 +25,8 @@ description: 按 Microi 系统真实业务逻辑进行 Playwright 全自动化
|
|
|
23
25
|
- `-e2e` 能让 AI 明确区分它和 `v8-debugging`、`v8-crud-api`、`playwright-ct` 等其他能力。
|
|
24
26
|
- 如果未来要补更细的能力,可以新增 `playwright-api` 或 `visual-regression`,不要把当前 skill 改成泛泛的 `playwright`。
|
|
25
27
|
|
|
28
|
+
<!-- /microi-progressive:chunk -->
|
|
29
|
+
<!-- microi-progressive:chunk id=playwright-e2e-001 sha256=703786ae7a5a52cb39664f1c82de7fb7aa7dfece511046d3757da64918c23063 -->
|
|
26
30
|
## 适用范围
|
|
27
31
|
|
|
28
32
|
- PC 管理端:`Microi.Client`、租户后台、运营后台。
|
|
@@ -33,6 +37,8 @@ description: 按 Microi 系统真实业务逻辑进行 Playwright 全自动化
|
|
|
33
37
|
|
|
34
38
|
不适合把 Playwright 用来替代 V8 单函数调试。单个接口引擎的入参输出优先用 VS Code 插件远程执行、MCP `microi_run_engine` 或后端单元测试。
|
|
35
39
|
|
|
40
|
+
<!-- /microi-progressive:chunk -->
|
|
41
|
+
<!-- microi-progressive:chunk id=playwright-e2e-002 sha256=a2524636727c51268a2daefdd617e5b90e105e245143b652bc095ac857ad4995 -->
|
|
36
42
|
## 临时文件与产物放置规则(必须遵守)
|
|
37
43
|
|
|
38
44
|
AI 在工作区内生成的**一次性临时脚本、诊断文件、截图、测试报告**等,**绝对不能放在工作区根目录**,必须放在以下指定位置:
|
|
@@ -51,6 +57,8 @@ AI 在工作区内生成的**一次性临时脚本、诊断文件、截图、测
|
|
|
51
57
|
|
|
52
58
|
**2026-06 强制补充**:AI 手写的一次性 Playwright 验证脚本、运行日志、截图和报告只能写到工作区根目录 `.tmp/`。不要写到 `Microi.Client/`、`Microi.Server/`、`microi.doc/` 或其它子项目目录,即使这些目录已有 `tests/` 目录也不例外。只有 Microi.VSCode 插件正式初始化的可复用 E2E 工程,才使用 `.microi-e2e/`。
|
|
53
59
|
|
|
60
|
+
<!-- /microi-progressive:chunk -->
|
|
61
|
+
<!-- microi-progressive:chunk id=playwright-e2e-003 sha256=69b8842a221a0de60f8605c5059deee391be0f16f0b6cbc5ddfb3cfd210268db -->
|
|
54
62
|
## 标准目录
|
|
55
63
|
|
|
56
64
|
前端项目中推荐使用 `tests/e2e`,而不是根目录 `e2e`,这样能和单元测试、组件测试并列。
|
|
@@ -70,6 +78,8 @@ AI 在工作区内生成的**一次性临时脚本、诊断文件、截图、测
|
|
|
70
78
|
report/
|
|
71
79
|
```
|
|
72
80
|
|
|
81
|
+
<!-- /microi-progressive:chunk -->
|
|
82
|
+
<!-- microi-progressive:chunk id=playwright-e2e-004 sha256=2f145cd29044043fb84cefd07fde14c86a4d0f4757443d56e75f5494516453cb -->
|
|
73
83
|
## 必备环境变量
|
|
74
84
|
|
|
75
85
|
```bash
|
|
@@ -90,6 +100,8 @@ PW_TEST_PASSWORD=<从本地配置读取或用环境变量覆盖>
|
|
|
90
100
|
PW_HOME_PATH=/#/pages/index/index
|
|
91
101
|
```
|
|
92
102
|
|
|
103
|
+
<!-- /microi-progressive:chunk -->
|
|
104
|
+
<!-- microi-progressive:chunk id=playwright-e2e-005 sha256=e348db509b586871f19b16b6b49da840c93aa438dd891d827af7107744513e00 -->
|
|
93
105
|
## 本地测试账号自动发现
|
|
94
106
|
|
|
95
107
|
当没有显式传入 `PW_TEST_ACCOUNT` / `PW_TEST_PASSWORD` / `MICROI_OSCLIENT` 时,AI 不要把账号密码写入后端配置来制造旁路:
|
|
@@ -99,6 +111,8 @@ PW_HOME_PATH=/#/pages/index/index
|
|
|
99
111
|
3. 这些值只作为自动化进程的登录输入或接口请求参数使用。日志、最终回复、截图说明、报告和异常消息中必须写成 `<redacted>` 或“本地配置凭据”,不要展开真实账号密码、Token、连接串或 Redis 密码。
|
|
100
112
|
4. 如果凭据不存在或登录失败,再报告具体阻塞点,例如“未提供受保护测试凭据”“本地后端未启动”“登录接口返回 Code=0”,不要泛泛说无法测试。
|
|
101
113
|
|
|
114
|
+
<!-- /microi-progressive:chunk -->
|
|
115
|
+
<!-- microi-progressive:chunk id=playwright-e2e-006 sha256=6aeefebda3a9e598564c53c2f8028a4ccefe2291c4c7c7ae4781ca15fb5d0697 -->
|
|
102
116
|
## 后端改动后的 E2E 前置动作
|
|
103
117
|
|
|
104
118
|
如果本轮任务修改过 `Microi.Server/**` 后端源码、配置、控制器、服务、依赖项目或接口行为,跑 Playwright、页面截图、接口验收或前后端联调前,必须先按 `workspace-conventions` 的“后端代码改动后的重启验收”完成:
|
|
@@ -110,68 +124,8 @@ PW_HOME_PATH=/#/pages/index/index
|
|
|
110
124
|
|
|
111
125
|
不要只说“代码已编译”或“需要用户自己重启后端”;除非用户明确要求不要中断当前服务,否则 AI 要主动完成重启。
|
|
112
126
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
E2E 自动化最容易卡在「登录页有图形验证码」。Microi 后端允许自动化跳过验证码,但账号和密码必须始终走真实校验;如果密码配置错了,登录接口必须返回账号或密码错误。源码见 `Microi.Server/Microi.net.Api/Controllers/SysUserController.cs`(`Login` 方法开头)。
|
|
116
|
-
|
|
117
|
-
### 方式 A:自动化登录参数(远端/本地通用)
|
|
118
|
-
|
|
119
|
-
- 触发条件:请求体传 `_AutomationTestLogin=true` 或 `_SkipCaptchaForAutomation=true`,且当前租户 `sys_config.AutoTestSkipCaptcha=true`(中文 Label:允许自动化测试登录时绕开验证码;字段缺失时按默认开启兼容旧库)。
|
|
120
|
-
- 效果:只跳过图形验证码,仍校验 `Account` / `Pwd`。
|
|
121
|
-
- 适用:MCP 连接远端租户、CI、Playwright 截图验收、接口自动化登录。
|
|
122
|
-
- 风险控制:如果远端环境不希望自动化免验证码,请在系统设置关闭【允许自动化测试登录时绕开验证码】。
|
|
123
|
-
|
|
124
|
-
Playwright 登录助手(直接拿 Token,不走登录页):
|
|
125
|
-
|
|
126
|
-
```js
|
|
127
|
-
// helpers/microi-login.js
|
|
128
|
-
export async function automationLogin(page, {
|
|
129
|
-
backend = process.env.BACKEND || 'https://localhost:61501',
|
|
130
|
-
osClient = process.env.MICROI_OSCLIENT || 'iTdos',
|
|
131
|
-
account = process.env.PW_TEST_ACCOUNT || 'admin',
|
|
132
|
-
password = process.env.PW_TEST_PASSWORD || '',
|
|
133
|
-
frontend = process.env.FRONTEND || 'http://localhost:61500',
|
|
134
|
-
} = {}) {
|
|
135
|
-
const resp = await page.request.post(`${backend}/api/SysUser/Login`, {
|
|
136
|
-
headers: { OsClient: osClient },
|
|
137
|
-
data: { Account: account, Pwd: password, OsClient: osClient, _AutomationTestLogin: true },
|
|
138
|
-
ignoreHTTPSErrors: true,
|
|
139
|
-
});
|
|
140
|
-
const json = await resp.json();
|
|
141
|
-
if (json.Code !== 1) throw new Error('automationLogin failed: ' + JSON.stringify(json).slice(0, 300));
|
|
142
|
-
const token = json.Data?.Token || json.Token;
|
|
143
|
-
const userId = json.Data?.Id || json.Id;
|
|
144
|
-
await page.goto(frontend, { waitUntil: 'domcontentloaded' });
|
|
145
|
-
await page.evaluate(({ t, u, oc, account }) => {
|
|
146
|
-
localStorage.setItem('Token', t);
|
|
147
|
-
localStorage.setItem('CurrentUser', JSON.stringify({ Id: u, Account: account }));
|
|
148
|
-
localStorage.setItem('OsClient', oc);
|
|
149
|
-
}, { t: token, u: userId, oc: osClient, account });
|
|
150
|
-
return { token, userId };
|
|
151
|
-
}
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### 选型口诀
|
|
155
|
-
|
|
156
|
-
- 容器、CI、本机接口自动化都使用 **`_AutomationTestLogin=true` + 真实密码**,直接 request 拿 Token。
|
|
157
|
-
- 需要验证真实 UI 登录时,用同一真实账号密码填写页面;目标租户仍由 `sys_config.AutoTestSkipCaptcha` 决定是否允许自动化跳过验证码。
|
|
158
|
-
- 失败时再退回 UI 兜底并保留原始错误;禁止新增 `DevLoginBypass`、Dev Key 或 `_DEV_BYPASS_`。
|
|
159
|
-
- Token 可能在响应体 `Data.Token`,也可能在响应头 `Authorization`,两处都要兜底取。
|
|
160
|
-
- 不要把 Token 明文写进最终报告/附件。
|
|
161
|
-
|
|
162
|
-
### ⚠️ 关键实测结论(Microi.Client SPA 守卫)
|
|
163
|
-
|
|
164
|
-
> 实测:**仅把 Token 写进 localStorage 并不能通过前端路由守卫**——页面会反复跳回 `/login`,且动态菜单路由(如 `/order`)在登录态建立前会报 `No match found`。Dev Key 头旁路(方式 A)只对 `page.request` 直连接口有效(见 `blueprint-e2e.spec.mjs`),SPA 仍需要一次真实 UI 登录会话。
|
|
165
|
-
>
|
|
166
|
-
> 在浏览器内做 E2E(点页面、拖拽、截图)时最稳的登录顺序:
|
|
167
|
-
> 1. 跳到 `#/login`;
|
|
168
|
-
> 2. 填从受保护测试进程变量或用户本轮提供的真实账号密码;
|
|
169
|
-
> 3. 目标租户开启 `AutoTestSkipCaptcha` 时传自动化标记跳过验证码,否则按真实页面流程填写验证码;
|
|
170
|
-
> 4. 点「登 录」,落到首页;
|
|
171
|
-
> 5. 再 `location.hash = '#/<目标路由>'` 进入目标页。
|
|
172
|
-
>
|
|
173
|
-
> 直连接口验收(不进页面)使用自动化标记拿 Token;历史 `_DEV_BYPASS_`、Dev Key 和 `DevLoginBypass` 均不得继续使用。
|
|
174
|
-
|
|
127
|
+
<!-- /microi-progressive:chunk -->
|
|
128
|
+
<!-- microi-progressive:chunk id=playwright-e2e-007 sha256=8776ce89491f11cbf6c6e6e9ef0cd430aa21efc60c1dbe1559ec9e905c5d0a9e -->
|
|
175
129
|
## 服务自启动纪律(必做)
|
|
176
130
|
|
|
177
131
|
执行自动化测试、截图巡检、接口引擎回读、`/apiengine/{key}` 验收时,如果本地后端或前端不可达,不能把 `fetch failed`、`ECONNREFUSED`、`000 Failed to connect`、端口无人监听当作任务终点。必须先自动启动所需服务,再继续完整验证。
|
|
@@ -213,533 +167,13 @@ uni-app H5 或移动端前端按项目自身命令启动,例如 `npm run dev:h
|
|
|
213
167
|
|
|
214
168
|
执行顺序:先检查端口/健康接口是否可达;不可达则用后台终端启动;等待服务输出监听地址;再重试接口同步、页面打开、Playwright 截图和断言。只有启动命令失败、缺少依赖、数据库连接失败、端口冲突无法自动换端口且无替代配置时,才算真正阻塞,并且要报告具体失败命令和错误。
|
|
215
169
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
当用户反馈“新增抽屉卡死”“设计页卡死”“点击控件无响应”“Maximum recursive updates exceeded”等表单引擎问题时,优先做可复现的 Playwright 诊断,而不是只靠猜测改代码。
|
|
219
|
-
|
|
220
|
-
Microi.Client 已提供专用入口:
|
|
221
|
-
|
|
222
|
-
```powershell
|
|
223
|
-
Push-Location Microi.Client
|
|
224
|
-
npm run test:form-freeze:auto
|
|
225
|
-
Pop-Location
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
该入口会执行 `scripts/run-form-engine-freeze-trace.mjs`,完整流程如下:
|
|
229
|
-
|
|
230
|
-
1. 自动配置 `Microi.Server/Microi.net.Api/Properties/launchSettings.json` 中指定 profile 的 `ASPNETCORE_ENVIRONMENT` 和 `DOTNET_ENVIRONMENT`。
|
|
231
|
-
2. 从 `PW_TEST_ACCOUNT` / `PW_TEST_PASSWORD` 读取真实测试凭据;脚本不得修改后端 `appsettings.*.json`。
|
|
232
|
-
3. 本地后端未启动时,自动进入 `Microi.Server/Microi.net.Api` 后执行 `dotnet run --launch-profile Microi.net.Api`。
|
|
233
|
-
4. 启动 Playwright,打开指定前端页面,开启 `MicroiFormTrace`,采集 `window.__MICROI_FORM_TRACE__`、console、pageerror、当前 URL 和 Playwright trace。
|
|
234
|
-
5. 页面卡住或断言失败时,先看最后一批 `[MicroiFormTrace #n]`,定位是停在 `runtime:*`、`diy-select:*`、`inform-v8-*`、`field-v8-*` 还是业务 console。
|
|
235
|
-
|
|
236
|
-
常用环境变量:
|
|
237
|
-
|
|
238
|
-
```powershell
|
|
239
|
-
$env:FRONTEND='http://localhost:61500'
|
|
240
|
-
$env:BACKEND='https://localhost:61501'
|
|
241
|
-
$env:PW_BACKEND_ENV='iTdos'
|
|
242
|
-
$env:PW_ASPNETCORE_ENVIRONMENT='iTdos'
|
|
243
|
-
$env:PW_DOTNET_ENVIRONMENT='iTdos'
|
|
244
|
-
$env:PW_APPSETTINGS_ENV='iTdos'
|
|
245
|
-
$env:MICROI_OSCLIENT='iTdos'
|
|
246
|
-
$env:PW_TEST_ACCOUNT='<从本地配置读取或手工覆盖>'
|
|
247
|
-
$env:PW_TEST_PASSWORD='<从本地配置读取或手工覆盖>'
|
|
248
|
-
$env:MICROI_FREEZE_PATH='/#/diy/diy-design/<TableId>?PageType='
|
|
249
|
-
npm run test:form-freeze:auto
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
可选开关:
|
|
253
|
-
|
|
254
|
-
- `PW_START_BACKEND=0`:不自动启动后端,只跑测试。
|
|
255
|
-
- `PW_CONFIG_BACKEND=0`:不修改 `launchSettings.json`。
|
|
256
|
-
- `PW_BACKEND_PROFILE=Microi.net.Api`:指定 launch profile。
|
|
257
|
-
- `PW_TEST_ACCOUNT`、`PW_TEST_PASSWORD`:仅注入当前自动化进程,必须使用真实账号密码且不得写回文件。
|
|
258
|
-
- `PW_HEADED=0`:无头运行。
|
|
259
|
-
|
|
260
|
-
诊断代码要遵守这些规则:
|
|
261
|
-
|
|
262
|
-
- 登录优先用真实后端 `/api/SysUser/Login`,token 可能在响应头 `Authorization`,不要只从 `Data.Token` 取。
|
|
263
|
-
- 如果 direct-token 被前端守卫踢回登录页,必须保留 UI 登录兜底,模拟真实用户输入账号密码点击登录。
|
|
264
|
-
- trace 只在 URL、localStorage 或 `window.__MICROI_FORM_TRACE_ENABLED__` 开启时输出,避免生产默认刷屏。
|
|
265
|
-
- 卡死类问题要捕获 `pageerror`;Vue 的 `Maximum recursive updates exceeded` 通常直接暴露根因组件。
|
|
266
|
-
- 不要把 token 打印到最终报告里;console 附件中如包含 token,只用于本地诊断,不要转述完整值。
|
|
267
|
-
- 修复后必须重跑同一个诊断用例,确认最后 trace 不再无限重复,并且页面在 10-15 秒后仍可响应。
|
|
268
|
-
|
|
269
|
-
## 移动端视觉与资源验收
|
|
270
|
-
|
|
271
|
-
uni-app H5、移动商城、分享海报、首页改版这类任务不能只跑接口和 DOM 断言。每次涉及页面风格、图片、二维码、商品卡片、首页聚合时,Playwright 必须补齐以下检查:
|
|
272
|
-
|
|
273
|
-
- 每个核心页面都保存全页截图到 `tests/e2e/screenshots/`,并用 `view_image` 人眼复核首页、登录页、分享海报、商品列表等关键截图。
|
|
274
|
-
- 对关键文字选择器做对比度检查,至少覆盖品牌名、搜索占位、公告、快捷入口、促销卡、分类、商品标题、价格、资产金额。浅底弱灰、金色按钮白字、渐变上低透明文字都应判为失败。
|
|
275
|
-
- 图片不能只断言 URL 不为空;必须验证图片真实加载,例如检查 `img.naturalWidth > 0`、uni-image 背景图、或 HTTP 200。坏图、404、空白图都算失败。
|
|
276
|
-
- 平台应用图片、海报二维码、公告图、商品图必须来自平台 HDFS/API 或数据库字段。测试中应拦截并拒绝 `qrserver.com`、`create-qr-code`、`picsum.photos`、`placeholder.com`、`dummyimage.com` 等第三方图床/二维码服务。
|
|
277
|
-
- 如果接口返回了不可用图片,优先修数据源、上传平台文件或修接口引擎,不要用第三方 fallback 把测试“跑绿”。
|
|
278
|
-
- 对分享海报二维码,优先断言平台接口,如 `/api/Os/CreateQRCodeImage`,或平台接口引擎返回的 HDFS 图片路径。
|
|
279
|
-
|
|
280
|
-
## 测试证据必须绑定需求编号
|
|
281
|
-
|
|
282
|
-
当用户一次提出多个问题时,Playwright 用例、截图文件名和最终测试报告必须能回到原始 `1、2、3...` 编号。
|
|
283
|
-
|
|
284
|
-
- 每个问题至少要有一个验证入口:DOM 断言、接口回读、数据库回读、截图或人眼复核;不能只测“页面能打开”。
|
|
285
|
-
- 截图命名建议包含问题编号和页面,例如 `issue-01-mine-message-recharge-row.png`、`issue-02-certify-approved-consistent.png`。
|
|
286
|
-
- 最终报告必须列出:编号、测试命令、是否通过、截图路径、未覆盖原因。
|
|
287
|
-
- 如果某项属于后台元数据或数据库配置,仍需通过接口/数据库回读给出证据;前端截图只能证明展示,不等价于后台配置已改。
|
|
288
|
-
|
|
289
|
-
## 移动端/H5 回归纪律
|
|
290
|
-
|
|
291
|
-
处理 uni-app H5 移动商城的交易、资产、登录、购物车、抢购、充值、分享或图片相关问题时,不能只改代码后让用户手工发现问题。完成实现后必须至少执行(以下变量按项目实际情况替换):
|
|
292
|
-
|
|
293
|
-
```powershell
|
|
294
|
-
Set-Location '<uniapp-project-root>' # 替换为项目实际路径
|
|
295
|
-
$env:PW_API_BASE='https://localhost:61501' # 替换为项目后端地址
|
|
296
|
-
$env:PW_API_ENV='development'
|
|
297
|
-
$env:PW_PORT='5192' # 替换为项目实际端口
|
|
298
|
-
npm run build:h5:local
|
|
299
|
-
npx playwright test --reporter=list
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
业务口径规则因项目而异,应在各项目自己的 `tests/e2e/` 目录中维护 spec 断言,不要写进通用 skill。
|
|
303
|
-
|
|
304
|
-
表单引擎冻结高频根因:
|
|
305
|
-
|
|
306
|
-
- 在 computed/render/watch 路径里写回同一个响应式依赖,例如 `field.Data` watcher 里再次写 `field.Data`。
|
|
307
|
-
- 程序性同步 `el-select` 值时触发 `change`,又执行 V8/FormSet,形成循环。
|
|
308
|
-
- 折叠分组、字段 Tabs 等运行态字段属性反复写入 `_isShow`、`_collapseClass`、`_fieldTabsPanes`。
|
|
309
|
-
- 前端 InFormV8 或字段 V8 中持续 `FormSet` 同一字段,且没有值相等保护。
|
|
310
|
-
|
|
311
|
-
当前 Microi.Client 的表单冻结诊断文件是 `tests/form-engine-freeze-trace.spec.mjs`。新增类似测试时,可以复制它的结构:`addInitScript` 注入 `ApiBase/OsClient/Trace`,登录后跳转目标 hash,等待设计/表单 DOM,延迟观察响应性,最后 attach trace 和 console。
|
|
312
|
-
|
|
313
|
-
## 文字对比度与可读性自动化检查(必做)
|
|
314
|
-
|
|
315
|
-
凡涉及前端样式、卡片、芯片、按钮、价格区间筛选条、退出登录、徽章、覆盖文字(金色/渐变背景上的小字)、列表副标题、空状态等,**测试与人眼复核都必须执行对比度检查**。典型教训:筛选条文字、幽灵按钮、轻色副标题在近似底色下肉眼几乎不可见,但接口/DOM 断言全部通过——这类对比度问题必须通过自动化审计捕捉。
|
|
316
|
-
|
|
317
|
-
### 自动化对比度审计
|
|
318
|
-
|
|
319
|
-
对每个核心页面,遍历可见文本节点,计算前景色与最近不透明背景色的 WCAG 对比度,<4.5:1 直接失败:
|
|
320
|
-
|
|
321
|
-
```js
|
|
322
|
-
const lowContrast = await page.evaluate(() => {
|
|
323
|
-
const ratio = (fg, bg) => {
|
|
324
|
-
const lum = (c) => {
|
|
325
|
-
const v = c.map(x => x/255).map(x => x <= 0.03928 ? x/12.92 : Math.pow((x+0.055)/1.055, 2.4));
|
|
326
|
-
return 0.2126*v[0] + 0.7152*v[1] + 0.0722*v[2];
|
|
327
|
-
};
|
|
328
|
-
const parse = (s) => (s.match(/\d+(\.\d+)?/g) || []).slice(0,3).map(Number);
|
|
329
|
-
const lf = lum(parse(fg)); const lb = lum(parse(bg));
|
|
330
|
-
return (Math.max(lf,lb)+0.05)/(Math.min(lf,lb)+0.05);
|
|
331
|
-
};
|
|
332
|
-
const findBg = (el) => {
|
|
333
|
-
let cur = el;
|
|
334
|
-
while (cur) {
|
|
335
|
-
const c = getComputedStyle(cur).backgroundColor;
|
|
336
|
-
if (c && c !== 'rgba(0, 0, 0, 0)' && c !== 'transparent') return c;
|
|
337
|
-
cur = cur.parentElement;
|
|
338
|
-
}
|
|
339
|
-
return 'rgb(255,255,255)';
|
|
340
|
-
};
|
|
341
|
-
const issues = [];
|
|
342
|
-
document.querySelectorAll('*').forEach(el => {
|
|
343
|
-
const t = (el.innerText || '').trim();
|
|
344
|
-
if (!t || el.children.length) return;
|
|
345
|
-
const cs = getComputedStyle(el);
|
|
346
|
-
if (cs.visibility === 'hidden' || cs.display === 'none' || parseFloat(cs.opacity) < 0.5) return;
|
|
347
|
-
const fz = parseFloat(cs.fontSize);
|
|
348
|
-
if (fz < 9) return;
|
|
349
|
-
const r = ratio(cs.color, findBg(el));
|
|
350
|
-
if (r < 4.5) issues.push({ text: t.slice(0,40), color: cs.color, bg: findBg(el), ratio: +r.toFixed(2), fontSize: fz });
|
|
351
|
-
});
|
|
352
|
-
return issues;
|
|
353
|
-
});
|
|
354
|
-
expect(lowContrast, '低对比度文字: ' + JSON.stringify(lowContrast.slice(0,5))).toEqual([]);
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
### 必须人眼复核(view_image)的页面
|
|
358
|
-
|
|
359
|
-
完成功能后强制 `fullPage` 截图并 `view_image` 人眼审阅以下页面,截图存入 `tests/e2e/screenshots/`:
|
|
360
|
-
|
|
361
|
-
| 页面 | 路径(以项目实际路由为准) | 重点检查 |
|
|
362
|
-
|------|------|---------|
|
|
363
|
-
| 首页 | `/#/pages/index/index` 等 | 横幅、公告、商品卡价格 |
|
|
364
|
-
| 分类 | `/#/pages/category/...` | tab、商品标题副信息 |
|
|
365
|
-
| 商品详情 | `/#/pages/product/detail?id=...` | 价格、规格、按钮 |
|
|
366
|
-
| 购物车 | `/#/pages/cart/...` | 数量、合计、结算按钮 |
|
|
367
|
-
| 订单列表/详情 | `/#/pages/order/...` | 状态徽章、金额、提交按钮 |
|
|
368
|
-
| 我的 | `/#/pages/mine/...` | **退出登录按钮**、菜单标签、账户信息 |
|
|
369
|
-
| 业务专题页 | 项目自定义路径 | 核心功能区域、状态、可交互元素 |
|
|
370
|
-
|
|
371
|
-
判定标准:任意小号文字 < 12px 在彩色/渐变背景上,或纯文字按钮在与页面同色调底色上无明显边框/填充——一律视为缺陷,必须修复后再发版。
|
|
372
|
-
|
|
373
|
-
### 设计禁忌(直接判失败)
|
|
374
|
-
|
|
375
|
-
1. 幽灵按钮(ghost button)在近似底色上当独立操作按钮使用——必须改成实心按钮或显式覆盖背景填充。
|
|
376
|
-
2. 中性灰/浅色文字(如 `#999` 等)直接放在与其色调接近的背景上,且字号较小——WCAG 对比度 < 4.5:1 直接判失败。
|
|
377
|
-
3. 渐变彩色背景上展示透明度较低的小字。
|
|
378
|
-
4. 与背景色调接近的文字颜色放在同色调底色上——必须加深文字颜色或改变底色。
|
|
379
|
-
5. 价格区间、状态、筛选这类**导航/筛选元素出现在列表中部作为标题**——必须移到顶部 sticky 工具栏,并与正文形成色彩区隔。
|
|
380
|
-
|
|
381
|
-
## 安装
|
|
382
|
-
|
|
383
|
-
```bash
|
|
384
|
-
npm i -D @playwright/test
|
|
385
|
-
npx playwright install chromium
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
### 浏览器选择强制顺序
|
|
389
|
-
|
|
390
|
-
做本地页面级 Playwright 验收时,不能因为 Playwright 官方 Chromium 缓存缺失或下载超时就结束任务。必须按下面顺序自动兜底:
|
|
391
|
-
|
|
392
|
-
1. 优先读取 `PW_CHROMIUM_EXECUTABLE` / `PW_BROWSER_EXECUTABLE`。
|
|
393
|
-
2. Windows 优先探测本机 Edge / Chrome:`C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe`、`C:/Program Files/Microsoft/Edge/Application/msedge.exe`、`C:/Users/Administrator/AppData/Local/Google/Chrome/Bin/chrome.exe`、`C:/Program Files/Google/Chrome/Application/chrome.exe`、`C:/Program Files (x86)/Google/Chrome/Application/chrome.exe`。
|
|
394
|
-
3. 再探测工作区本地缓存:`.cache/chromium/**/chrome.exe`、`.tmp/playwright-browsers/**/chrome.exe`。
|
|
395
|
-
4. 仍没有浏览器时,才从吾码 CDN 下载到 `.tmp/playwright-browsers/`,并设置 `PW_CHROMIUM_EXECUTABLE`。
|
|
396
|
-
5. 只有系统浏览器、本地缓存和 CDN 下载全部失败时,才允许报告“浏览器不可用”;报告中必须说明已经尝试过哪些路径。
|
|
397
|
-
|
|
398
|
-
手写一次性脚本必须把浏览器探测逻辑写在 `.tmp/*.mjs` 中,截图和报告也必须输出到 `.tmp/screenshots/` 或 `.tmp/reports/`,不要写到 `Microi.Client/`、`Microi.Server/` 等子项目目录。
|
|
399
|
-
|
|
400
|
-
国内或内网环境如果下载浏览器困难,可以使用本机 Edge:
|
|
401
|
-
|
|
402
|
-
```bash
|
|
403
|
-
$env:PW_BROWSER_CHANNEL='msedge'
|
|
404
|
-
npx playwright test
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
如果本机没有可用 Edge,或必须使用 Chromium,优先从吾码 CDN 下载浏览器压缩包,不要反复卡在 Playwright 官方下载通道:
|
|
408
|
-
|
|
409
|
-
| 系统 | CDN 地址 |
|
|
410
|
-
|------|----------|
|
|
411
|
-
| Windows x64 | `https://static.itdos.com/openclaw/chromium/chrome-win64-137.0.7151.68.zip` |
|
|
412
|
-
| macOS x64 | `https://static.itdos.com/openclaw/chromium/chrome-mac-x64-137.0.7151.68.zip` |
|
|
413
|
-
| macOS arm64 | `https://static.itdos.com/openclaw/chromium/chrome-mac-arm64-137.0.7151.68.zip` |
|
|
414
|
-
|
|
415
|
-
Windows 示例:
|
|
416
|
-
|
|
417
|
-
```powershell
|
|
418
|
-
$browserRoot = Join-Path (Resolve-Path '.tmp').Path 'playwright-browsers'
|
|
419
|
-
New-Item -ItemType Directory -Force -Path $browserRoot | Out-Null
|
|
420
|
-
$zipPath = Join-Path $browserRoot 'chrome-win64-137.0.7151.68.zip'
|
|
421
|
-
Invoke-WebRequest 'https://static.itdos.com/openclaw/chromium/chrome-win64-137.0.7151.68.zip' -OutFile $zipPath
|
|
422
|
-
Expand-Archive $zipPath -DestinationPath $browserRoot -Force
|
|
423
|
-
$env:PW_CHROMIUM_EXECUTABLE = (Resolve-Path (Join-Path $browserRoot 'chrome-win64/chrome.exe')).Path
|
|
424
|
-
npx playwright test
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
手写 Playwright 脚本时读取 `PW_CHROMIUM_EXECUTABLE` / `PW_BROWSER_EXECUTABLE` 并传给 `chromium.launch({ executablePath })`;Playwright Test 配置中通过 `use.launchOptions.executablePath` 读取该环境变量。只有 CDN、系统浏览器和本地缓存都不可用时,才报告浏览器不可用。
|
|
428
|
-
|
|
429
|
-
## playwright.config.js 模板
|
|
430
|
-
|
|
431
|
-
```js
|
|
432
|
-
import { defineConfig, devices } from '@playwright/test';
|
|
433
|
-
|
|
434
|
-
const port = process.env.PW_PORT || '5180';
|
|
435
|
-
const baseURL = process.env.PW_BASE_URL || `http://127.0.0.1:${port}`;
|
|
436
|
-
const webServerUrl = process.env.PW_WEB_SERVER_URL || baseURL;
|
|
437
|
-
const channel = process.env.PW_BROWSER_CHANNEL || undefined;
|
|
438
|
-
const executablePath = process.env.PW_CHROMIUM_EXECUTABLE || process.env.PW_BROWSER_EXECUTABLE || undefined;
|
|
439
|
-
const defaultCommand = process.env.PW_APP_TYPE === 'uniapp-h5'
|
|
440
|
-
? `npm run dev:h5 -- --host 0.0.0.0 --port ${port}`
|
|
441
|
-
: `npm run dev -- --host 0.0.0.0 --port ${port}`;
|
|
442
|
-
|
|
443
|
-
export default defineConfig({
|
|
444
|
-
testDir: './tests/e2e',
|
|
445
|
-
timeout: 60_000,
|
|
446
|
-
expect: { timeout: 10_000 },
|
|
447
|
-
fullyParallel: false,
|
|
448
|
-
retries: process.env.CI ? 2 : 0,
|
|
449
|
-
workers: process.env.CI ? 1 : undefined,
|
|
450
|
-
reporter: [['list'], ['html', { open: 'never', outputFolder: 'tests/e2e/report' }]],
|
|
451
|
-
use: {
|
|
452
|
-
baseURL,
|
|
453
|
-
...(executablePath ? { launchOptions: { executablePath } } : {}),
|
|
454
|
-
trace: 'retain-on-failure',
|
|
455
|
-
screenshot: 'only-on-failure',
|
|
456
|
-
video: 'retain-on-failure',
|
|
457
|
-
extraHTTPHeaders: {
|
|
458
|
-
OsClient: process.env.PW_OS_CLIENT || 'demo'
|
|
459
|
-
}
|
|
460
|
-
},
|
|
461
|
-
webServer: {
|
|
462
|
-
command: process.env.PW_WEB_SERVER_COMMAND || defaultCommand,
|
|
463
|
-
url: webServerUrl,
|
|
464
|
-
reuseExistingServer: true,
|
|
465
|
-
timeout: 120_000
|
|
466
|
-
},
|
|
467
|
-
projects: [
|
|
468
|
-
{
|
|
469
|
-
name: 'desktop',
|
|
470
|
-
use: { ...devices['Desktop Chrome'], ...(channel ? { channel } : {}) }
|
|
471
|
-
},
|
|
472
|
-
{
|
|
473
|
-
name: 'mobile',
|
|
474
|
-
use: { ...devices['iPhone 13'], ...(channel ? { channel } : {}) }
|
|
475
|
-
}
|
|
476
|
-
]
|
|
477
|
-
});
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
uni-app H5 如果采用静态产物测试,可以把 `PW_WEB_SERVER_COMMAND` 设置为:
|
|
481
|
-
|
|
482
|
-
```bash
|
|
483
|
-
npm run build:h5 && npx --yes http-server dist/build/h5 -p 5180 -s -c-1
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
## Microi helper 模板
|
|
487
|
-
|
|
488
|
-
```js
|
|
489
|
-
// tests/e2e/helpers/microi.js
|
|
490
|
-
import { expect } from '@playwright/test';
|
|
491
|
-
|
|
492
|
-
export const microiEnv = {
|
|
493
|
-
apiBase: process.env.PW_API_BASE || 'https://api.example.com',
|
|
494
|
-
osClient: process.env.PW_OS_CLIENT || 'demo',
|
|
495
|
-
loginEngine: process.env.PW_LOGIN_ENGINE || 'member_login'
|
|
496
|
-
};
|
|
497
|
-
|
|
498
|
-
// 仅用于需要在 URL 中显式携带租户的普通 GET;POST 不调用此函数。
|
|
499
|
-
export function withOsClientQuery(url) {
|
|
500
|
-
const sep = url.includes('?') ? '&' : '?';
|
|
501
|
-
return `${url}${sep}OsClient=${encodeURIComponent(microiEnv.osClient)}`;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
export async function callEngine(request, apiEngineKey, data = {}, token = '') {
|
|
505
|
-
const res = await request.post(`${microiEnv.apiBase}/apiengine/${apiEngineKey}`, {
|
|
506
|
-
headers: {
|
|
507
|
-
'Content-Type': 'application/json',
|
|
508
|
-
apiengine: '1',
|
|
509
|
-
osclient: microiEnv.osClient,
|
|
510
|
-
...(token ? { Token: token } : {})
|
|
511
|
-
},
|
|
512
|
-
data: { ...data, OsClient: data.OsClient || microiEnv.osClient }
|
|
513
|
-
});
|
|
514
|
-
expect(res.ok(), `${apiEngineKey} HTTP status`).toBeTruthy();
|
|
515
|
-
const json = await res.json();
|
|
516
|
-
return json;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
export async function loginByEngine(request, account, password) {
|
|
520
|
-
const json = await callEngine(request, microiEnv.loginEngine, {
|
|
521
|
-
Account: account,
|
|
522
|
-
Phone: account,
|
|
523
|
-
Pwd: password,
|
|
524
|
-
Password: password
|
|
525
|
-
});
|
|
526
|
-
expect(json.Code, json.Msg || 'login Code').toBe(1);
|
|
527
|
-
const data = json.Data || {};
|
|
528
|
-
const token = data.Token || data.token || data.AccessToken || '';
|
|
529
|
-
expect(token, 'login token').toBeTruthy();
|
|
530
|
-
return { token, data };
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
export async function injectStorage(page, values) {
|
|
534
|
-
await page.addInitScript((storageValues) => {
|
|
535
|
-
for (const [key, value] of Object.entries(storageValues)) {
|
|
536
|
-
localStorage.setItem(key, typeof value === 'string' ? value : JSON.stringify(value));
|
|
537
|
-
}
|
|
538
|
-
}, values);
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
export async function injectH5Storage(page, token, member = null) {
|
|
542
|
-
return injectStorage(page, {
|
|
543
|
-
mall_token: token,
|
|
544
|
-
mall_member: member || {}
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
export function assertDosResultShape(json, label = 'DosResult') {
|
|
549
|
-
expect(json, label).toBeTruthy();
|
|
550
|
-
expect(json, label).toHaveProperty('Code');
|
|
551
|
-
expect(typeof json.Code, `${label}.Code type`).toBe('number');
|
|
552
|
-
}
|
|
553
|
-
```
|
|
554
|
-
|
|
555
|
-
## 典型用例
|
|
556
|
-
|
|
557
|
-
```js
|
|
558
|
-
import { test, expect } from '@playwright/test';
|
|
559
|
-
import { callEngine, loginByEngine, injectH5Storage } from '../helpers/microi.js';
|
|
560
|
-
|
|
561
|
-
test('公开首页能打开', async ({ page }) => {
|
|
562
|
-
await page.goto(process.env.PW_HOME_PATH || '/');
|
|
563
|
-
await expect(page.locator('body')).toBeVisible();
|
|
564
|
-
});
|
|
565
|
-
|
|
566
|
-
test('登录接口能拿到 Token 并进入首页', async ({ page, request }) => {
|
|
567
|
-
const { token, data } = await loginByEngine(
|
|
568
|
-
request,
|
|
569
|
-
process.env.PW_TEST_ACCOUNT || 'admin',
|
|
570
|
-
process.env.PW_TEST_PASSWORD || '123456'
|
|
571
|
-
);
|
|
572
|
-
await injectH5Storage(page, token, data.Member);
|
|
573
|
-
await page.goto(process.env.PW_HOME_PATH || '/');
|
|
574
|
-
await expect(page.locator('body')).toBeVisible();
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
test('公开接口引擎返回标准 DosResult', async ({ request }) => {
|
|
578
|
-
const json = await callEngine(request, process.env.PW_SMOKE_ENGINE || 'home_data', {});
|
|
579
|
-
expect(json).toHaveProperty('Code');
|
|
580
|
-
});
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
## Microi 专属测试策略
|
|
584
|
-
|
|
585
|
-
1. 先用 MCP `microi_get_playwright_context` 获取当前租户的菜单路由、接口引擎、匿名状态。
|
|
586
|
-
2. 公开页面只测“能打开、关键区域可见、无横向溢出、无白屏”。
|
|
587
|
-
3. 登录态优先用接口引擎登录,再注入 `localStorage` 或 Cookie,不要在每个用例里重复点登录表单。
|
|
588
|
-
4. 业务主线只覆盖客户真正验收的动作:列表、详情、提交、状态变化、余额/库存/积分变动。
|
|
589
|
-
5. 接口引擎断言必须检查 `HTTP ok`、`Code`、`Msg` 和关键 `Data` 字段。
|
|
590
|
-
6. 涉及写库的用例必须使用专用测试账号和可重复数据,避免污染生产数据。
|
|
591
|
-
7. 截图只用于关键节点和失败场景;不要让截图成为唯一断言。
|
|
592
|
-
8. **每条业务主线 spec 必须有"图片回归检查"步骤**:在涉及商品列表、商品详情、提货卡、海报、头像、Banner 的页面,必须 `await page.screenshot({ path: 'tests/e2e/screenshots/<spec>.png', fullPage: true })`,并在测试报告生成后用 `view_image` 工具肉眼复核截图,确认:
|
|
593
|
-
- 没有出现纯渐变/首字母占位/空白图位(这通常意味着 `sanitizeAssetUrl` 等前缀工具被遗漏,或图片字段拿到了相对路径)
|
|
594
|
-
- 商品/卡片图都真实显示
|
|
595
|
-
- 价格、卖家、卡号等文案不出错位
|
|
596
|
-
- 同步参见 [microi-uniapp-frontend](../microi-uniapp-frontend/SKILL.md) 中的资源 URL 与 FileServer 前缀规范。
|
|
597
|
-
9. 用 `page.on('response', r => { if (r.url().includes('/file/') && !r.ok()) failedAssets.push(r.url()); })` 监听全部资源请求,断言 `failedAssets.length === 0`,能在断言前就抓到 404 图片。
|
|
170
|
+
<!-- /microi-progressive:chunk -->
|
|
171
|
+
## 详细参考路由(渐进披露)
|
|
598
172
|
|
|
599
|
-
|
|
173
|
+
仅在当前任务涉及对应主题时读取;下列文件合计保留了原 SKILL.md 的全部详细知识。
|
|
600
174
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
4. 一条主业务路径能跑通。
|
|
607
|
-
5. 底部 Tab、菜单或核心导航都能加载。
|
|
608
|
-
6. 退出登录能清理 Token 并回到登录页。
|
|
609
|
-
|
|
610
|
-
## 完整业务验收门槛
|
|
611
|
-
|
|
612
|
-
当用户要求“完整测试”“全面测试”“不要让我手工测出接口 null/404/权限漏洞”时,不能只生成浅冒烟。至少补齐以下测试文件:
|
|
613
|
-
|
|
614
|
-
```text
|
|
615
|
-
tests/e2e/
|
|
616
|
-
helpers/microi.js
|
|
617
|
-
smoke.spec.js # 首屏、导航、图片、布局
|
|
618
|
-
api-contract.spec.js # 所有接口引擎契约:HTTP ok、非 null、合法 JSON、DosResult.Code
|
|
619
|
-
network.spec.js # 页面运行期拦截 404/5xx、空响应、字符串 null、意外 Code=0
|
|
620
|
-
auth.spec.js # 未登录/登录/过期 Token/退出登录
|
|
621
|
-
business-flow.spec.js # 至少一条真实写操作闭环,写后再查后端状态
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
必备断言:
|
|
625
|
-
|
|
626
|
-
1. API 响应不能是空 body、字符串 `null`、非 JSON,除明确允许外不能返回 `Code=0`。
|
|
627
|
-
2. 公开接口必须可匿名调用;受保护接口未登录必须返回 `Code=1001/1002` 或跳转登录。
|
|
628
|
-
3. 写操作必须做“前置清理 → 执行动作 → 后端查询确认 → 用例清理”。
|
|
629
|
-
4. UI 点击不能只断言 toast;必须用 `page.waitForResponse()` 捕捉对应接口,并验证响应体。
|
|
630
|
-
5. 任何 FormEngine HTTP 路由必须使用 `/api/formengine/{action}-{table}`,不要生成 `/formengine/{table}/{action}`。
|
|
631
|
-
6. ApiEngine 使用稳定路径 `/apiengine/{ApiEngineKey}`,并通过唯一的 `osclient` Header 传租户;JSON/Form Body 可冗余携带 `OsClient`。普通 POST/PUT/PATCH/DELETE 禁止追加 `--OsClient--...--`。仅第三方回调或无法设置 Header/Form/Query 的 GET/HEAD 才允许特殊路径。
|
|
632
|
-
7. 页面级测试必须把 `请求失败`、`网络错误`、`null`、`待开发`、`开发中` 当成失败信号;这些文案如果出现在页面或 toast 中,说明功能未交付或接口契约错误。
|
|
633
|
-
8. 新增、保存、结算、转赠、确认、上传等按钮不能只弹“成功/待开发”toast;必须调用真实业务接口,并通过后端查询验证状态变化。
|
|
634
|
-
9. 源码守卫可作为兜底:递归扫描 `src/**/*.vue`、`src/**/*.js`,禁止残留 `待开发|开发中` 占位文案。
|
|
635
|
-
10. 新建或更新 ApiEngine 后必须用 HTTP 路径复测一次;只用 `microi_run_engine` 通过不够,因为 HTTP 调用还受 `IsEnable`、`StopHttp`、`AllowAnonymous` 和动态路由缓存影响。
|
|
636
|
-
11. 每个移动端项目都要有“接口清单驱动”的契约测试:静态扫描或维护清单覆盖所有 `callEngine('xxx')`,逐个 HTTP 调用并断言不是 404、不是空响应、不是字符串 `null`,且必须是标准 DosResult。
|
|
637
|
-
12. 写业务闭环时必须准备可重复测试数据并清理:例如抢购要“创建测试挂单 → 调用抢购 → 验证订单 → 删除测试订单/挂单/提货卡”,购物车要“加入购物车 → 结算 → 验证订单/购物车状态 → 删除测试订单”。
|
|
638
|
-
13. 图片断言必须检查真实渲染,而不是只检查元素可见。uni-app H5 的 `<image>` 会渲染成 `UNI-IMAGE`,真实图片在内部 `div.style.backgroundImage` 或子 `img` 上;不要把宿主元素的 CSS 渐变背景算作加载成功。
|
|
639
|
-
14. 网络守卫要记录 `requestfailed`,特别是图片资源的 `net::ERR_BLOCKED_BY_ORB` / CORS / 404;首页 banner、商品主图、头像等公开图片必须实际加载。
|
|
640
|
-
15. 页面出现浏览器原生 `alert`、`confirm` 或 `prompt` 直接判失败;测试应监听 `page.on('dialog')` 记录类型和文案后关闭对话框,再要求业务改用吾码 Tips、Element Plus 或品牌化可访问弹层。长弹窗需分别滚动到顶部、中部、底部触发反馈,并断言提示/确认层的 bounding box 中心接近当前 viewport 中心且未被遮挡。
|
|
641
|
-
|
|
642
|
-
移动商城/会员 H5 额外规则:
|
|
643
|
-
|
|
644
|
-
- 商城会员 Token 来自业务接口引擎(如 `mall_member_login` 或项目自定义登录引擎),不是平台 `Sys_User` Token。
|
|
645
|
-
- 移动端会员数据查询不要直连平台 FormEngine;使用租户 ApiEngine 或安全查询代理。
|
|
646
|
-
- 商品详情“加入购物车”必须登录;登录后必须写服务端购物车,再进入购物车页验证同一商品可见。
|
|
647
|
-
- 购物车、订单、资产、团队、提货、地址、收款方式等会员数据都必须按会员 Id 做后端范围过滤。
|
|
648
|
-
- 涉及多种支付/货币类型的项目(如提货卡、积分、余额等),每种支付渠道必须独立测试,不能混用或互通;项目自定义的费率、规则参数应在各自项目的测试文件中维护。
|
|
649
|
-
- 库存/商品相关接口(如库存转让、抜购窗口)必须返回标准 DosResult,禁止返回 JS `null`;成功路径必须返回订单 Id 或结果数据。
|
|
650
|
-
- 购物车“结算”必须调用业务结算接口,不能残留“功能开发中”占位文案;真实闭环:加入购物车 → 结算 → 断言 Code=1 和订单 Id → 确认购物车已清对应商品。
|
|
651
|
-
- 首页运营 banner 推荐从公告或配置表驱动;E2E 要同时断言接口返回、图片真实加载、点击进入详情页。
|
|
652
|
-
- 涉及多种支付/货币类型的项目(如提货卡、积分、余额等),每种支付渠道必须独立测试,不能混用或互通;项目自定义的费率、规则参数应在各自项目的测试文件中维护。
|
|
653
|
-
- 库存/商品相关接口(如库存转让、抢购窗口)必须返回标准 DosResult,禁止返回 JS `null`;成功路径必须返回订单 Id 或结果数据。
|
|
654
|
-
- 购物车`结算`必须调用业务结算接口,不能残留`功能开发中`占位文案;真实闭环:加入购物车 → 结算 → 断言 Code=1 和订单 Id → 确认购物车已清对应商品。
|
|
655
|
-
- 首页运营 banner 推荐从公告或配置表驱动;E2E 要同时断言接口返回、图片真实加载、点击进入详情页。
|
|
656
|
-
|
|
657
|
-
## 与 MCP 的配合
|
|
658
|
-
|
|
659
|
-
- `microi_get_db_schema`:写测试前确认表和字段。
|
|
660
|
-
- `microi_get_playwright_context`:获取可测菜单 URL、接口引擎、匿名配置。
|
|
661
|
-
- `microi_plan_playwright_e2e`:生成推荐的测试文件、环境变量和冒烟路径。
|
|
662
|
-
- `microi_run_engine`:调试单个接口引擎,不替代浏览器 E2E。
|
|
663
|
-
- `microi_set_engine_anonymous`:登录、注册、公开首页接口需要匿名访问时使用;设置后仍要验证 HTTP `/apiengine/{key}` + `osclient` Header 返回标准 DosResult。
|
|
664
|
-
|
|
665
|
-
## 与 VS Code 插件的配合
|
|
666
|
-
|
|
667
|
-
### Microi VS Code 插件
|
|
668
|
-
|
|
669
|
-
Microi VS Code 插件应提供三类能力:
|
|
670
|
-
|
|
671
|
-
- 初始化:创建 `playwright.config.js`、`tests/e2e/helpers/microi.js`、示例 `smoke.spec.js`、`.env.e2e.example`,并补齐 `package.json` 脚本。
|
|
672
|
-
- 运行:在当前前端项目目录执行 `npm run test:e2e`,并提供打开报告入口。
|
|
673
|
-
- 上下文:从后端 `GetPlaywrightContext` 拉取当前租户可测路由和接口引擎,写入 `tests/e2e/.microi-playwright-context.json`,供 AI 生成用例时参考。
|
|
674
|
-
|
|
675
|
-
### Playwright Test for VSCode(官方插件)
|
|
676
|
-
|
|
677
|
-
官方插件 `Playwright Test for VSCode` 与 Microi Playwright 规范不冲突。它只是同一套 `@playwright/test` 的 VS Code 测试视图/调试入口,读取项目里的 `playwright.config.js`、`testDir`、`projects`、`webServer`、`use` 配置;CLI 的 `npx playwright test` 与插件按钮运行的是同一批 spec。
|
|
678
|
-
|
|
679
|
-
推荐共用方式:
|
|
680
|
-
|
|
681
|
-
1. 项目内保留 `playwright.config.js` 作为唯一配置源,不为插件单独复制一份配置。
|
|
682
|
-
2. `webServer.reuseExistingServer: true`,这样插件运行时如果 H5 静态服务已启动就复用,否则按配置启动。
|
|
683
|
-
3. 本地 H5 先执行 `npm run build:h5:local`;插件再运行 `tests/e2e/*.spec.js` 时会服务 `dist/build/h5`。
|
|
684
|
-
4. Windows 本机推荐 `PW_BROWSER_CHANNEL=msedge` 或在配置中默认 `channel: 'msedge'`,避免每台机器重复下载 Chromium。
|
|
685
|
-
5. 需要自定义 `PW_API_BASE/PW_API_ENV/PW_PORT/PW_OS_CLIENT` 时,优先写入 `playwright.config.js` 的默认值或 VS Code 插件环境变量设置;CI 和一次性运行再用终端环境变量覆盖。
|
|
686
|
-
6. 插件适合单个用例调试、断点、Trace 查看;最终交付仍要跑 CLI 全量命令并查看 `tests/e2e/report`。
|
|
687
|
-
7. 插件截图/trace 与 CLI 使用同一目录;视觉回归仍必须 `view_image` 人眼复核关键 fullPage 截图。
|
|
688
|
-
|
|
689
|
-
## CI 建议
|
|
690
|
-
|
|
691
|
-
```yaml
|
|
692
|
-
name: e2e
|
|
693
|
-
on: [push, pull_request]
|
|
694
|
-
jobs:
|
|
695
|
-
playwright:
|
|
696
|
-
runs-on: ubuntu-latest
|
|
697
|
-
steps:
|
|
698
|
-
- uses: actions/checkout@v4
|
|
699
|
-
- uses: actions/setup-node@v4
|
|
700
|
-
with:
|
|
701
|
-
node-version: 20
|
|
702
|
-
- run: npm ci
|
|
703
|
-
- run: npx playwright install --with-deps chromium
|
|
704
|
-
- run: npm run test:e2e
|
|
705
|
-
env:
|
|
706
|
-
PW_BASE_URL: http://127.0.0.1:5180
|
|
707
|
-
PW_API_BASE: ${{ secrets.PW_API_BASE }}
|
|
708
|
-
PW_OS_CLIENT: ${{ secrets.PW_OS_CLIENT }}
|
|
709
|
-
PW_TEST_ACCOUNT: ${{ secrets.PW_TEST_ACCOUNT }}
|
|
710
|
-
PW_TEST_PASSWORD: ${{ secrets.PW_TEST_PASSWORD }}
|
|
711
|
-
```
|
|
712
|
-
|
|
713
|
-
## 常见问题
|
|
714
|
-
|
|
715
|
-
| 现象 | 原因 | 处理 |
|
|
716
|
-
|---|---|---|
|
|
717
|
-
| 接口返回 `Code=1001/1002` | Token 失效或未传 | 登录 fixture 注入 Token,或检查 Header |
|
|
718
|
-
| 登录接口返回 `Code=0` | 账号数据不存在或 `AllowAnonymous=0` | 准备测试账号,必要时设置匿名 |
|
|
719
|
-
| `microi_run_engine` 成功但 `/apiengine/{key}` 返回“未启用” | `IsEnable=0`、`StopHttp=1` 或保存代码时丢失接口元数据 | 设置匿名/启用后清缓存,并用 HTTP 路径复测 |
|
|
720
|
-
| 新增接口一开始 404 | 动态路由缓存尚未刷新 | HTTP 调用带 `apiengine: 1` Header 直达接口引擎,并刷新缓存/重启后端 |
|
|
721
|
-
| `microi_set_engine_anonymous` 显示已启用但 HTTP 仍提示 `sys_apiengine` 不存在 | 历史引擎 `ApiAddress` 为空或不是 `/apiengine/{key}` | 批量补齐 `ApiAddress`、`IsEnable=1`、`StopHttp=0`,并清 key/id/address 三类缓存 |
|
|
722
|
-
| 保存接口代码后 MCP 自己报 `string does not contain DosIsNullOrWhiteSpace` | 后端 C# 在动态对象路径上调用扩展方法 | 改用 `string.IsNullOrWhiteSpace`,不要在 MCP 路径新增 `DosIsNullOrWhiteSpace` 调用 |
|
|
723
|
-
| MCP `run_engine` 里 `V8.Db` 为 null | MCP 执行上下文没有注入直连 Db | 维护/测试引擎优先使用 `V8.FormEngine.GetTableData/UptFormData` |
|
|
724
|
-
| H5 静态资源 404 | `vite.config.js` 未配置相对路径 | uni-app H5 设置 `base: './'` |
|
|
725
|
-
| 本地浏览器下载失败 | Playwright 下载 Chromium 受阻 | 先用 `PW_BROWSER_CHANNEL=msedge`,没有 Edge 时从吾码 CDN 下载 Chromium 并设置 `PW_CHROMIUM_EXECUTABLE` |
|
|
726
|
-
| 用例偶发失败 | HMR 或网络请求未稳定 | CI 使用静态构建,断言明确等待关键元素 |
|
|
727
|
-
| 页面有横向滚动 | 组件撑出视口 | 对根容器和列表容器加 `max-width:100vw; overflow-x:hidden` |
|
|
728
|
-
|
|
729
|
-
## 前端微服务 E2E 必测点
|
|
730
|
-
|
|
731
|
-
测试 Vue3 MicroApp 微服务时,不能只验证 `/micro-app/{OsClient}/{appKey}/index.html` 或带 token 的临时 URL。必须先建立真实登录态,再访问用户实际使用的不带 token 菜单路由,例如 `/#/micro-app/{MsKey}/{RoutePath}`,并确认地址栏没有退回旧的 `micro-app-host` 长地址。
|
|
732
|
-
|
|
733
|
-
同一套微服务绑定多个菜单时,至少连续访问两个菜单页面,断言没有 `element head is missing`、`Failed to fetch`、`ERR_TOO_MANY_REDIRECTS`、`app name conflict` 等 micro-app 错误。
|
|
734
|
-
|
|
735
|
-
如果页面内提供 Microi SDK 调用按钮,必须点击并断言返回 `Code=1`,同时确认没有 `登录身份已过期`、`1001`、`1002`。只看到标题文本不代表鉴权链路通过。
|
|
736
|
-
|
|
737
|
-
## 动态模块按钮验收
|
|
738
|
-
|
|
739
|
-
修复或新增 `MoreBtns/FormBtns/PageBtns/PageTabs` 时,运行页看到按钮只证明“最终渲染结果”,不能证明入口确实可由模块引擎维护。至少同时保留三类证据:
|
|
740
|
-
|
|
741
|
-
1. 后端/MCP 回读目标 `sys_menu`,断言对应按钮稳定 `Id`、`Name`、位置字段、`V8CodeShow` 和 `V8Code` 均已保存,并且未覆盖其它客户按钮。
|
|
742
|
-
2. 使用真实管理员登录模块引擎设计器,打开目标模块,断言相应按钮编辑区能看到该按钮及代码。
|
|
743
|
-
3. 分别在实际列表/卡片或 PC/移动端运行态检查按钮显隐并点击到目标交互;源码回归还要确认通用模板和宽度计算中不存在按模块 Id、Url、表名写死的同名入口。
|
|
744
|
-
|
|
745
|
-
按钮通过 `V8.OpenDialog` 打开主前端定制组件时,还要断言组件已在全局注册、`ComponentName` 与注册名一致、`DataAppend` 能到达组件,并确认源码没有新增 `V8.Open<业务名>` 专用包装。按钮通过 `V8.OpenAppDialog` 打开微服务时,按 AppKey、RoutePath 和发布版本回读并验收。涉及新旧版本滚动发布时分别说明组件/应用资源尚未就绪和已就绪的预期,不得只在单一版本页面上验收。
|
|
175
|
+
- [references/progressive-01-全自动登录-免验证码-但不免密码-必读.md](references/progressive-01-全自动登录-免验证码-但不免密码-必读.md):全自动登录(免验证码,但不免密码)——必读;表单引擎卡死/递归更新全自动化诊断;移动端视觉与资源验收;测试证据必须绑定需求编号;移动端/H5 回归纪律
|
|
176
|
+
- [references/progressive-02-文字对比度与可读性自动化检查-必做.md](references/progressive-02-文字对比度与可读性自动化检查-必做.md):文字对比度与可读性自动化检查(必做);安装;playwright.config.js 模板
|
|
177
|
+
- [references/progressive-03-microi-helper-模板.md](references/progressive-03-microi-helper-模板.md):Microi helper 模板;典型用例;Microi 专属测试策略;最少冒烟集;完整业务验收门槛;与 MCP 的配合;与 VS Code 插件的配合
|
|
178
|
+
- [references/progressive-04-ci-建议.md](references/progressive-04-ci-建议.md):CI 建议;常见问题;前端微服务 E2E 必测点;动态模块按钮验收
|
|
179
|
+
<!-- microi-progressive:end -->
|