ykq-playwright-ci 0.1.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/.env.example +25 -0
- package/.nvmrc +1 -0
- package/README.md +553 -0
- package/bin/playwright-ci.mjs +116 -0
- package/cases/doctor-pc/auth/doctor-auth.setup.ts +15 -0
- package/cases/doctor-pc/prescription/submit-failure-keeps-drugs.spec.ts +10 -0
- package/cases/doctor-pc/smoke/authenticated-home.spec.ts +28 -0
- package/cases/doctor-pc/smoke/login-page.spec.ts +21 -0
- package/cases/doctor-pc/smoke/prescription-tab.spec.ts +30 -0
- package/cases/doctor-pc/test-env/doctor-master-basic.spec.ts +89 -0
- package/ci/github-actions/playwright.yml +61 -0
- package/docs/auth-runbook.md +44 -0
- package/docs/case-map.md +10 -0
- package/docs/ci.md +36 -0
- package/docs/runbook.md +39 -0
- package/docs/selector-convention.md +24 -0
- package/docs/test-data.md +23 -0
- package/eslint.config.mjs +28 -0
- package/package.json +64 -0
- package/playwright.config.ts +44 -0
- package/projects.config.json +33 -0
- package/scripts/configure-project.mjs +280 -0
- package/scripts/run-doctor-test.mjs +19 -0
- package/scripts/run-project.mjs +252 -0
- package/src/api/doctor.api.ts +25 -0
- package/src/api/test-data.api.ts +33 -0
- package/src/fixtures/auth.fixture.ts +26 -0
- package/src/fixtures/base.fixture.ts +14 -0
- package/src/fixtures/doctor.fixture.ts +39 -0
- package/src/flows/doctor-pc/chat.flow.ts +10 -0
- package/src/flows/doctor-pc/login.flow.ts +28 -0
- package/src/flows/doctor-pc/medicine.flow.ts +11 -0
- package/src/flows/doctor-pc/prescription.flow.ts +19 -0
- package/src/mocks/routes/prescription.routes.ts +25 -0
- package/src/mocks/websocket/.gitkeep +1 -0
- package/src/pages/doctor-pc/chat.page.ts +26 -0
- package/src/pages/doctor-pc/drug-dialog.page.ts +28 -0
- package/src/pages/doctor-pc/home.page.ts +30 -0
- package/src/pages/doctor-pc/login.page.ts +35 -0
- package/src/pages/doctor-pc/prescription.page.ts +29 -0
- package/src/pages/doctor-pc/worklist.page.ts +21 -0
- package/src/pages/shared/.gitkeep +1 -0
- package/src/utils/env.ts +78 -0
- package/src/utils/evidence.ts +34 -0
- package/src/utils/selectors.ts +9 -0
- package/src/utils/waiters.ts +11 -0
- package/tsconfig.json +14 -0
package/.env.example
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Target environment name used in reports.
|
|
2
|
+
TEST_ENV=test
|
|
3
|
+
|
|
4
|
+
# Deployed doctor PC base URL, for example:
|
|
5
|
+
# DOCTOR_BASE_URL=https://doctor-test.example.com
|
|
6
|
+
DOCTOR_BASE_URL=
|
|
7
|
+
|
|
8
|
+
# App paths under DOCTOR_BASE_URL.
|
|
9
|
+
DOCTOR_PUBLIC_PATH=/
|
|
10
|
+
DOCTOR_LOGIN_PATH=/login
|
|
11
|
+
|
|
12
|
+
# Local auth state generated by `npm run auth:doctor` or manual codegen.
|
|
13
|
+
DOCTOR_STORAGE_STATE=playwright/.auth/doctor.json
|
|
14
|
+
|
|
15
|
+
# Optional UI login credentials. Leave empty if auth is still manual.
|
|
16
|
+
DOCTOR_USERNAME=
|
|
17
|
+
DOCTOR_PASSWORD=
|
|
18
|
+
DOCTOR_OTP=
|
|
19
|
+
|
|
20
|
+
# Optional service endpoints for future data seeding and API assertions.
|
|
21
|
+
API_BASE_URL=
|
|
22
|
+
TEST_DATA_API_URL=
|
|
23
|
+
|
|
24
|
+
# Build metadata shown in attachments and CI artifacts.
|
|
25
|
+
BUILD_SHA=local
|
package/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
22
|
package/README.md
ADDED
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
# Playwright CI 使用说明
|
|
2
|
+
|
|
3
|
+
独立 Playwright 自动化测试工程。当前工程用于承接医生端 PC 的 E2E 自动化测试,不把 Playwright 依赖直接放进医生端 Vue2 / Node 14 业务仓。
|
|
4
|
+
|
|
5
|
+
## 适用范围
|
|
6
|
+
|
|
7
|
+
当前优先覆盖医生端测试环境的基础链路:
|
|
8
|
+
|
|
9
|
+
- 登录页是否能正常渲染。
|
|
10
|
+
- 未登录访问首页是否按路由守卫跳回登录页。
|
|
11
|
+
- 用户协议页是否允许未登录访问。
|
|
12
|
+
- 登录表单的基础校验是否符合 `doctor-master` 逻辑。
|
|
13
|
+
|
|
14
|
+
这些用例不需要真实医生账号,也不会真的登录、开方或提交处方。登录后业务链路需要先解决测试账号、验证码或登录态方案。
|
|
15
|
+
|
|
16
|
+
## 环境要求
|
|
17
|
+
|
|
18
|
+
本地使用这个 runner 前,需要准备这些环境:
|
|
19
|
+
|
|
20
|
+
| 环境 | 要求 | 说明 |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| Node.js | 建议使用 `.nvmrc` 指定的 `22` | 本工具运行在 Node 侧,不受医生端业务仓 Node 14 限制 |
|
|
23
|
+
| npm | 随 Node 安装即可 | 推荐用 `npm ci` 或 `npm install` 安装依赖 |
|
|
24
|
+
| Git | 需要可执行 `git clone`、`git fetch`、`git pull` | 用于拉取各项目的用例库 |
|
|
25
|
+
| Git 权限 | 需要能访问 `git.int.ybm100.com` | 可用本机 Git 凭据,也可临时传 `GIT_USERNAME` / `GIT_PASSWORD` |
|
|
26
|
+
| 浏览器 | Playwright Chromium | 首次运行前执行 `npx playwright install chromium` |
|
|
27
|
+
| 网络 | 需要访问 Git 仓库和目标测试环境 | 医生端默认访问 `https://ys-test.heyejk.com` |
|
|
28
|
+
|
|
29
|
+
当前基础用例不需要医生测试账号。后续如果跑登录后链路,还需要测试医生账号、验证码绕过方案,或 `playwright/.auth/doctor.json` 登录态文件。
|
|
30
|
+
|
|
31
|
+
不要把账号、密码、token、登录态写进 Git:
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
.env
|
|
35
|
+
playwright/.auth/*.json
|
|
36
|
+
GIT_PASSWORD
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 环境准备
|
|
40
|
+
|
|
41
|
+
进入工程目录:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
cd /Users/huangcongqiang/Desktop/products/playwright-ci
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
安装依赖:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
如果使用 `nvm`:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
nvm use
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
安装浏览器:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npx playwright install chromium
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
如果机器已经装过对应版本,Playwright 会复用缓存。
|
|
66
|
+
|
|
67
|
+
## 通过 npm 安装使用
|
|
68
|
+
|
|
69
|
+
npm 包名使用 `ykq-playwright-ci`。`playwright-ci` 这个包名已经被 npm 上其它作者占用,所以本工具发布时不能继续使用原仓库名。
|
|
70
|
+
|
|
71
|
+
全局安装:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npm install -g ykq-playwright-ci
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
首次在某个目录使用时,先初始化项目配置:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
mkdir playwright-runner
|
|
81
|
+
cd playwright-runner
|
|
82
|
+
playwright-ci init
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
初始化后会在当前目录生成:
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
projects.config.json
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
之后可以直接按项目运行:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
playwright-ci list
|
|
95
|
+
playwright-ci run doctor-pc
|
|
96
|
+
playwright-ci run doctor-pc --headed
|
|
97
|
+
playwright-ci run doctor-pc --debug
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
也可以使用项目配置命令:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
playwright-ci add
|
|
104
|
+
playwright-ci show doctor-pc
|
|
105
|
+
playwright-ci update doctor-pc
|
|
106
|
+
playwright-ci delete doctor-pc
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
如果不想全局安装,发布后也可以用 `npx`:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npx ykq-playwright-ci init
|
|
113
|
+
npx ykq-playwright-ci run doctor-pc
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
从 npm 安装后,Git 用例库仍然拉到当前工作目录的 `.case-repos/`,`projects.config.json` 也保存在当前工作目录,不会写到全局 `node_modules` 目录。
|
|
117
|
+
|
|
118
|
+
## 最常用命令
|
|
119
|
+
|
|
120
|
+
查看已配置的项目:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm run project:list
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
交互式新增项目配置:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npm run project:add
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
查看某个项目详情:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
npm run project:show -- doctor-pc
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
交互式更新项目配置:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
npm run project:update -- doctor-pc
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
删除项目配置:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
npm run project:delete -- doctor-pc
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
后台无头运行测试环境基础用例:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npm run doctor:test
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
打开浏览器窗口,看 Playwright 实际操作:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npm run doctor:test:headed
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
调试模式,适合逐步看定位、点击和断言:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
npm run doctor:test:debug
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
打开 Playwright UI,适合筛选、重跑、查看每一步:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
npm run doctor:test:ui
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
查看最近一次测试报告:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
npm run report
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## 命令说明
|
|
181
|
+
|
|
182
|
+
| 命令 | 用途 | 是否打开浏览器窗口 |
|
|
183
|
+
| --- | --- | --- |
|
|
184
|
+
| `npm run project:list` | 查看当前 runner 已配置的项目 | 否 |
|
|
185
|
+
| `npm run project:show -- doctor-pc` | 查看单个项目完整配置 | 否 |
|
|
186
|
+
| `npm run project:add` | 交互式新增项目配置 | 否 |
|
|
187
|
+
| `npm run project:update -- doctor-pc` | 交互式更新项目配置 | 否 |
|
|
188
|
+
| `npm run project:delete -- doctor-pc` | 删除项目配置,需要输入 `delete` 确认 | 否 |
|
|
189
|
+
| `npm run project:test -- doctor-pc` | 按项目名运行用例 | 否 |
|
|
190
|
+
| `npm run doctor:test` | 跑医生端测试环境基础用例,适合日常验证和 CI | 否 |
|
|
191
|
+
| `npm run doctor:test:headed` | 跑同一批用例,同时显示浏览器窗口 | 是 |
|
|
192
|
+
| `npm run doctor:test:debug` | 调试用例,可暂停、逐步执行 | 是 |
|
|
193
|
+
| `npm run doctor:test:ui` | 打开 Playwright UI 选择和重跑用例 | 是 |
|
|
194
|
+
| `npm run doctor:test:local` | 不拉远程仓库,直接跑当前 runner 内置医生端用例 | 否 |
|
|
195
|
+
| `npm run patient:test` | 跑患者端用例库;需要先配置 repo | 否 |
|
|
196
|
+
| `npm run admin:test` | 跑后台用例库;需要先配置 repo | 否 |
|
|
197
|
+
| `npm run report` | 打开 HTML 测试报告 | 是 |
|
|
198
|
+
| `npm run typecheck` | TypeScript 类型检查 | 否 |
|
|
199
|
+
| `npm run lint` | ESLint 检查 | 否 |
|
|
200
|
+
|
|
201
|
+
## 多项目用例库
|
|
202
|
+
|
|
203
|
+
本工程现在是一个本地 Playwright Runner。Runner 负责:
|
|
204
|
+
|
|
205
|
+
- 管理 Playwright 版本、浏览器、报告和通用命令。
|
|
206
|
+
- 按项目名读取配置。
|
|
207
|
+
- 如果项目配置了 Git 用例库,运行前自动 clone 或 `git pull --ff-only`。
|
|
208
|
+
- 根据项目配置设置测试环境变量。
|
|
209
|
+
- 调用 Playwright 执行对应用例目录。
|
|
210
|
+
|
|
211
|
+
医生端用例库:
|
|
212
|
+
|
|
213
|
+
```text
|
|
214
|
+
https://git.int.ybm100.com/ykq/doctor-pc-web-test-store
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
项目配置文件:
|
|
218
|
+
|
|
219
|
+
```text
|
|
220
|
+
projects.config.json
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
当前结构:
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"caseCacheDir": ".case-repos",
|
|
228
|
+
"projects": {
|
|
229
|
+
"doctor-pc": {
|
|
230
|
+
"repo": "https://git.int.ybm100.com/ykq/doctor-pc-web-test-store",
|
|
231
|
+
"branch": "master",
|
|
232
|
+
"caseDir": ".case-repos/doctor-pc",
|
|
233
|
+
"env": {
|
|
234
|
+
"DOCTOR_BASE_URL": "https://ys-test.heyejk.com",
|
|
235
|
+
"DOCTOR_PUBLIC_PATH": "/physician-admin/",
|
|
236
|
+
"DOCTOR_LOGIN_PATH": "/physician-admin/login"
|
|
237
|
+
},
|
|
238
|
+
"playwrightArgs": ["--project=chromium", "--no-deps"]
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
`doctor-pc` 已配置为远程用例库。首次运行会拉取到:
|
|
245
|
+
|
|
246
|
+
```text
|
|
247
|
+
.case-repos/doctor-pc
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
如果 Git 需要登录,可以用本机 Git 凭据管理,也可以临时通过环境变量传入:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
GIT_USERNAME=你的用户名 GIT_PASSWORD='你的密码或访问令牌' npm run doctor:test
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
不要把账号密码写进 `projects.config.json`、README、脚本或 Git remote URL。
|
|
257
|
+
|
|
258
|
+
远程用例库配置示例:
|
|
259
|
+
|
|
260
|
+
```json
|
|
261
|
+
{
|
|
262
|
+
"repo": "https://git.int.ybm100.com/ykq/doctor-pc-web-test-store",
|
|
263
|
+
"branch": "master",
|
|
264
|
+
"caseDir": ".case-repos/doctor-pc",
|
|
265
|
+
"env": {
|
|
266
|
+
"DOCTOR_BASE_URL": "https://ys-test.heyejk.com",
|
|
267
|
+
"DOCTOR_PUBLIC_PATH": "/physician-admin/",
|
|
268
|
+
"DOCTOR_LOGIN_PATH": "/physician-admin/login"
|
|
269
|
+
},
|
|
270
|
+
"playwrightArgs": ["--project=chromium", "--no-deps"]
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
运行时逻辑:
|
|
275
|
+
|
|
276
|
+
```text
|
|
277
|
+
npm run doctor:test
|
|
278
|
+
-> 读取 projects.config.json 的 doctor-pc
|
|
279
|
+
-> 如果 repo 不为空,clone / pull 到 .case-repos/doctor-pc
|
|
280
|
+
-> 设置 DOCTOR_BASE_URL 等环境变量
|
|
281
|
+
-> 执行 Playwright
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
`.case-repos/` 是本地缓存目录,已加入 `.gitignore`,不要提交。
|
|
285
|
+
|
|
286
|
+
如果本地用例库有未提交改动,runner 会停止自动拉取,避免覆盖你调试中的用例。确认不需要这些改动后,再自己处理对应用例库的 Git 状态。
|
|
287
|
+
|
|
288
|
+
通用运行方式:
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
npm run project:test -- doctor-pc
|
|
292
|
+
npm run project:test -- doctor-pc --headed
|
|
293
|
+
npm run project:test -- doctor-pc --debug
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
项目配置增删改查:
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
npm run project:list
|
|
300
|
+
npm run project:show -- doctor-pc
|
|
301
|
+
npm run project:add
|
|
302
|
+
npm run project:update -- doctor-pc
|
|
303
|
+
npm run project:delete -- doctor-pc
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
新增和更新会依次询问:
|
|
307
|
+
|
|
308
|
+
- 项目名
|
|
309
|
+
- 用例库 Git 地址
|
|
310
|
+
- 分支
|
|
311
|
+
- 本地用例缓存目录
|
|
312
|
+
- 项目说明
|
|
313
|
+
- Playwright 参数
|
|
314
|
+
- 环境变量
|
|
315
|
+
|
|
316
|
+
写入后会更新 `projects.config.json`。账号密码不要写进项目配置,运行时通过本机 Git 凭据或临时环境变量传入:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
GIT_USERNAME=你的用户名 GIT_PASSWORD='你的密码或访问令牌' npm run project:test -- 项目名
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
如果只想跑 runner 内置的临时本地用例,不拉远程用例库:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
npm run doctor:test:local
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## 默认测试环境
|
|
329
|
+
|
|
330
|
+
医生端测试环境命令默认使用:
|
|
331
|
+
|
|
332
|
+
```text
|
|
333
|
+
DOCTOR_BASE_URL=https://ys-test.heyejk.com
|
|
334
|
+
DOCTOR_PUBLIC_PATH=/physician-admin/
|
|
335
|
+
DOCTOR_LOGIN_PATH=/physician-admin/login
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
也就是说,基础用例会访问:
|
|
339
|
+
|
|
340
|
+
```text
|
|
341
|
+
https://ys-test.heyejk.com/physician-admin/login
|
|
342
|
+
https://ys-test.heyejk.com/physician-admin/home
|
|
343
|
+
https://ys-test.heyejk.com/physician-admin/serviceAgreement
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
如果要临时切换环境,可以在命令前覆盖变量:
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
DOCTOR_BASE_URL=https://your-test-host npm run doctor:test
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
如果路径也不同,可以一起覆盖:
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
DOCTOR_BASE_URL=https://your-test-host \
|
|
356
|
+
DOCTOR_PUBLIC_PATH=/physician-admin/ \
|
|
357
|
+
DOCTOR_LOGIN_PATH=/physician-admin/login \
|
|
358
|
+
npm run doctor:test
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## 当前测试用例
|
|
362
|
+
|
|
363
|
+
文件位置:
|
|
364
|
+
|
|
365
|
+
```text
|
|
366
|
+
cases/doctor-pc/test-env/doctor-master-basic.spec.ts
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
当前包含 4 条用例:
|
|
370
|
+
|
|
371
|
+
| 用例 ID | 验证内容 | 方式 |
|
|
372
|
+
| --- | --- | --- |
|
|
373
|
+
| `PW-TEST-001` | 登录页控件渲染:手机号、图形验证码、短信验证码、协议、登录按钮 | 直接访问登录路由 |
|
|
374
|
+
| `PW-TEST-002` | 未登录访问 `/home` 会被路由守卫跳到 `/login` | 直接访问受保护路由 |
|
|
375
|
+
| `PW-TEST-003` | `/serviceAgreement` 在白名单内,未登录可访问 | 直接访问白名单路由 |
|
|
376
|
+
| `PW-TEST-004` | 登录表单校验:必填、手机号格式、未勾协议提示 | 真实输入和点击 |
|
|
377
|
+
|
|
378
|
+
前 3 条主要验证路由和页面状态;第 4 条包含真实输入和点击。
|
|
379
|
+
|
|
380
|
+
## 如何看结果
|
|
381
|
+
|
|
382
|
+
命令行里看到类似结果表示通过:
|
|
383
|
+
|
|
384
|
+
```text
|
|
385
|
+
4 passed
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
失败时,Playwright 会在这些目录生成证据:
|
|
389
|
+
|
|
390
|
+
```text
|
|
391
|
+
test-results/
|
|
392
|
+
playwright-report/
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
常用查看方式:
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
npm run report
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
失败报告里通常包含:
|
|
402
|
+
|
|
403
|
+
- 失败截图
|
|
404
|
+
- 操作视频
|
|
405
|
+
- trace 回放
|
|
406
|
+
- 报错堆栈
|
|
407
|
+
- 失败前后的页面状态
|
|
408
|
+
|
|
409
|
+
trace 可以帮助判断到底是页面没出来、定位器没找到、跳转不符合预期,还是网络/环境问题。
|
|
410
|
+
|
|
411
|
+
## 第一次运行常见问题
|
|
412
|
+
|
|
413
|
+
### 缺少 Chromium
|
|
414
|
+
|
|
415
|
+
报错类似:
|
|
416
|
+
|
|
417
|
+
```text
|
|
418
|
+
Executable doesn't exist
|
|
419
|
+
Please run the following command to download new browsers:
|
|
420
|
+
npx playwright install
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
处理:
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
npx playwright install chromium
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### 测试环境访问慢
|
|
430
|
+
|
|
431
|
+
如果测试偶发超时,先用可视化模式看页面是否真的打开:
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
npm run doctor:test:headed
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
再打开报告看失败证据:
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
npm run report
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### 断言找到了多个元素
|
|
444
|
+
|
|
445
|
+
Playwright 默认严格模式下,一个定位器只能匹配一个元素。比如 `验证码` 可能同时匹配 `图形验证码` 和 `验证码`。这种情况需要把定位器写得更精确,例如:
|
|
446
|
+
|
|
447
|
+
```ts
|
|
448
|
+
page.getByPlaceholder('验证码', { exact: true })
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## 如何新增用例
|
|
452
|
+
|
|
453
|
+
医生端测试环境基础用例优先放在:
|
|
454
|
+
|
|
455
|
+
```text
|
|
456
|
+
cases/doctor-pc/test-env/
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
建议命名:
|
|
460
|
+
|
|
461
|
+
```text
|
|
462
|
+
模块-场景-预期.spec.ts
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
示例:
|
|
466
|
+
|
|
467
|
+
```text
|
|
468
|
+
login-form-validation.spec.ts
|
|
469
|
+
home-route-guard.spec.ts
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
每条用例建议补充 `annotateCase`,方便报告里追踪用例 ID:
|
|
473
|
+
|
|
474
|
+
```ts
|
|
475
|
+
annotateCase(testInfo, {
|
|
476
|
+
caseId: 'PW-TEST-005',
|
|
477
|
+
evidenceId: 'TEST-some-business-evidence',
|
|
478
|
+
priority: 'Smoke'
|
|
479
|
+
});
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
写用例时优先使用接近用户行为的定位方式:
|
|
483
|
+
|
|
484
|
+
```ts
|
|
485
|
+
page.getByRole('button', { name: '登录' })
|
|
486
|
+
page.getByPlaceholder('手机号')
|
|
487
|
+
page.getByText('荷叶医生')
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
不要优先依赖样式类名、DOM 层级或 `nth-child`。如果页面没有稳定语义定位,再考虑让业务仓补 `data-testid`。
|
|
491
|
+
|
|
492
|
+
## 登录后用例怎么做
|
|
493
|
+
|
|
494
|
+
当前基础用例不需要登录。后续要测登录后页面,比如首页、问诊列表、处方 tab、开方、撤回处方,需要先满足至少一种方案:
|
|
495
|
+
|
|
496
|
+
- 后端提供测试登录接口。
|
|
497
|
+
- 测试环境提供固定验证码或验证码绕过能力。
|
|
498
|
+
- 手工生成 `playwright/.auth/doctor.json` 登录态。
|
|
499
|
+
|
|
500
|
+
手工登录态方式参考:
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
npx playwright codegen --save-storage=playwright/.auth/doctor.json https://ys-test.heyejk.com/physician-admin/login
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
在打开的浏览器里完成登录后关闭窗口,后续已登录用例可复用该 storageState。
|
|
507
|
+
|
|
508
|
+
注意:`playwright/.auth/*.json` 包含登录态,已被 `.gitignore` 排除,不要提交。
|
|
509
|
+
|
|
510
|
+
## CI 或服务器运行
|
|
511
|
+
|
|
512
|
+
服务器不需要显示器,可以直接跑无头模式:
|
|
513
|
+
|
|
514
|
+
```bash
|
|
515
|
+
npm ci
|
|
516
|
+
npx playwright install --with-deps chromium
|
|
517
|
+
npm run doctor:test
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
CI 建议归档:
|
|
521
|
+
|
|
522
|
+
```text
|
|
523
|
+
playwright-report/
|
|
524
|
+
test-results/
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
不要归档或提交:
|
|
528
|
+
|
|
529
|
+
```text
|
|
530
|
+
playwright/.auth/*.json
|
|
531
|
+
.env
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
## 项目结构
|
|
535
|
+
|
|
536
|
+
```text
|
|
537
|
+
cases/doctor-pc/ # 医生端业务用例
|
|
538
|
+
src/fixtures/ # Playwright fixtures 和登录态工具
|
|
539
|
+
src/pages/doctor-pc/ # Page Object
|
|
540
|
+
src/flows/doctor-pc/ # 跨页面业务流程
|
|
541
|
+
src/api/ # API 和测试数据客户端
|
|
542
|
+
src/mocks/ # route / websocket mock
|
|
543
|
+
docs/ # 运行、登录、测试数据、选择器和 CI 说明
|
|
544
|
+
scripts/ # 命令封装脚本
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
## 维护原则
|
|
548
|
+
|
|
549
|
+
- 先用少量稳定 Smoke 验证页面和路由,再扩展登录后 P0 链路。
|
|
550
|
+
- 用例失败必须能留下截图、视频或 trace。
|
|
551
|
+
- 不在测试工程里硬编码真实账号密码。
|
|
552
|
+
- 不把 Playwright 依赖塞回医生端业务仓。
|
|
553
|
+
- 涉及处方、问诊、药品、自动关诊等业务链路时,要先确认测试数据和登录态方案。
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* global console, process */
|
|
3
|
+
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const packageRootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
10
|
+
const defaultConfigPath = path.join(packageRootDir, 'projects.config.json');
|
|
11
|
+
const userConfigPath = process.env.PROJECTS_CONFIG_PATH
|
|
12
|
+
? path.resolve(process.env.PROJECTS_CONFIG_PATH)
|
|
13
|
+
: path.resolve(process.cwd(), 'projects.config.json');
|
|
14
|
+
|
|
15
|
+
const configActions = new Set(['list', 'show', 'add', 'update', 'delete', 'remove']);
|
|
16
|
+
|
|
17
|
+
function printHelp() {
|
|
18
|
+
console.log(`Usage:
|
|
19
|
+
playwright-ci init
|
|
20
|
+
playwright-ci list
|
|
21
|
+
playwright-ci show <project>
|
|
22
|
+
playwright-ci add [project]
|
|
23
|
+
playwright-ci update <project>
|
|
24
|
+
playwright-ci delete <project>
|
|
25
|
+
playwright-ci run <project> [playwright args]
|
|
26
|
+
playwright-ci <project> [playwright args]
|
|
27
|
+
|
|
28
|
+
Examples:
|
|
29
|
+
playwright-ci init
|
|
30
|
+
playwright-ci run doctor-pc --headed
|
|
31
|
+
GIT_USERNAME=user GIT_PASSWORD=token playwright-ci run doctor-pc`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function ensureConfigExists() {
|
|
35
|
+
if (fs.existsSync(userConfigPath)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
throw new Error(`当前目录缺少 projects.config.json,请先执行:playwright-ci init\n目标路径:${userConfigPath}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function initConfig() {
|
|
43
|
+
if (fs.existsSync(userConfigPath)) {
|
|
44
|
+
console.log(`配置文件已存在:${userConfigPath}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fs.copyFileSync(defaultConfigPath, userConfigPath);
|
|
49
|
+
console.log(`已创建配置文件:${userConfigPath}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function runNodeScript(scriptName, args) {
|
|
53
|
+
const child = spawn(process.execPath, [path.join(packageRootDir, 'scripts', scriptName), ...args], {
|
|
54
|
+
cwd: process.cwd(),
|
|
55
|
+
env: {
|
|
56
|
+
...process.env,
|
|
57
|
+
PROJECTS_CONFIG_PATH: userConfigPath
|
|
58
|
+
},
|
|
59
|
+
stdio: 'inherit'
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
child.on('exit', (code, signal) => {
|
|
63
|
+
if (signal) {
|
|
64
|
+
process.kill(process.pid, signal);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
process.exit(code ?? 1);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function main() {
|
|
73
|
+
const [command = 'help', ...args] = process.argv.slice(2);
|
|
74
|
+
|
|
75
|
+
if (command === 'help' || command === '--help' || command === '-h') {
|
|
76
|
+
printHelp();
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (command === 'init') {
|
|
81
|
+
initConfig();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (command === 'run' || command === 'project:test') {
|
|
86
|
+
ensureConfigExists();
|
|
87
|
+
runNodeScript('run-project.mjs', args);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (command.startsWith('project:')) {
|
|
92
|
+
const action = command.slice('project:'.length);
|
|
93
|
+
if (!configActions.has(action)) {
|
|
94
|
+
throw new Error(`未知命令:${command}`);
|
|
95
|
+
}
|
|
96
|
+
ensureConfigExists();
|
|
97
|
+
runNodeScript('configure-project.mjs', [action, ...args]);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (configActions.has(command)) {
|
|
102
|
+
ensureConfigExists();
|
|
103
|
+
runNodeScript('configure-project.mjs', [command, ...args]);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
ensureConfigExists();
|
|
108
|
+
runNodeScript('run-project.mjs', [command, ...args]);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
main();
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error(error instanceof Error ? error.message : error);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { test } from '../../../src/fixtures/base.fixture';
|
|
2
|
+
import { saveDoctorAuthState } from '../../../src/fixtures/auth.fixture';
|
|
3
|
+
import { LoginFlow } from '../../../src/flows/doctor-pc/login.flow';
|
|
4
|
+
import { hasDoctorBaseURL, hasDoctorCredentials } from '../../../src/utils/env';
|
|
5
|
+
|
|
6
|
+
test.skip(!hasDoctorBaseURL(), 'DOCTOR_BASE_URL is required to generate doctor auth state.');
|
|
7
|
+
test.skip(
|
|
8
|
+
!hasDoctorCredentials(),
|
|
9
|
+
'DOCTOR_USERNAME and DOCTOR_PASSWORD are required unless auth is generated manually.'
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
test('PW-AUTH-SETUP generate doctor storageState @auth', async ({ page }) => {
|
|
13
|
+
await new LoginFlow(page).loginWithConfiguredCredentials();
|
|
14
|
+
await saveDoctorAuthState(page);
|
|
15
|
+
});
|