bk-press 0.0.5 → 0.0.6
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 +109 -6
- package/lib/command/fixture.js +5 -0
- package/lib/command/index.js +1 -0
- package/lib/command/init.js +22 -4
- package/lib/command/record.js +39 -0
- package/lib/index.js +6 -1
- package/lib/util/common.js +16 -0
- package/lib/util/index.js +1 -0
- package/package.json +2 -2
- package/src/command/fixture.ts +3 -0
- package/src/command/index.ts +1 -0
- package/src/command/init.ts +30 -7
- package/src/command/record.ts +40 -0
- package/src/index.ts +9 -2
- package/src/util/common.ts +11 -0
- package/src/util/index.ts +1 -0
package/README.md
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# bk-press
|
|
2
2
|
|
|
3
|
-
一个用于 Cypress 自动化测试的 CLI
|
|
3
|
+
一个用于 Cypress 自动化测试的 CLI 工具,帮助快速初始化测试环境、并行运行自动化测试,并支持从浏览器录制产物生成 **Fixture 拦截数据** 与 **Cypress 测试脚本**。
|
|
4
4
|
|
|
5
5
|
## 📋 目录
|
|
6
6
|
|
|
7
7
|
- [安装](#安装)
|
|
8
8
|
- [快速开始](#快速开始)
|
|
9
|
+
- [CLI 命令一览](#cli-命令一览)
|
|
10
|
+
- [从网络日志生成 Fixture(fixture)](#从网络日志生成-fixturefixture)
|
|
11
|
+
- [从 Chrome Recorder 生成测试脚本(record)](#从-chrome-recorder-生成测试脚本record)
|
|
9
12
|
- [配置文件](#配置文件)
|
|
10
13
|
- [项目结构](#项目结构)
|
|
11
14
|
- [使用示例](#使用示例)
|
|
@@ -48,7 +51,8 @@ pnpm add bk-press
|
|
|
48
51
|
{
|
|
49
52
|
"DEV_URL": "https://your-dev-domain.com",
|
|
50
53
|
"LOCAL_URL": "http://localhost:8080",
|
|
51
|
-
"
|
|
54
|
+
"COOKIE_DOMAIN_A": "your-domain.com",
|
|
55
|
+
"COOKIE_DOMAIN_B": "your-domain.com"
|
|
52
56
|
}
|
|
53
57
|
```
|
|
54
58
|
|
|
@@ -63,6 +67,62 @@ pnpm add bk-press
|
|
|
63
67
|
bkpress run
|
|
64
68
|
```
|
|
65
69
|
|
|
70
|
+
## CLI 命令一览
|
|
71
|
+
|
|
72
|
+
| 命令 | 说明 |
|
|
73
|
+
|------|------|
|
|
74
|
+
| `bkpress init` | 初始化 Cypress 测试环境(模板、配置、脚本等) |
|
|
75
|
+
| `bkpress login` | 打开浏览器登录并写入 `cypress.env.json` 中的 Cookie |
|
|
76
|
+
| `bkpress run` | 并行运行 E2E 自动化测试 |
|
|
77
|
+
| `bkpress fixture` | 从项目根目录的 `web-interaction-log.json` 生成 `cypress_fixtures/` 下的响应 JSON |
|
|
78
|
+
| `bkpress record <paths...>` | 根据 Cypress Chrome Recorder 导出的一个或多个 JSON,生成一个或多个 Cypress 测试脚本 |
|
|
79
|
+
|
|
80
|
+
查看子命令与参数:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
bkpress --help
|
|
84
|
+
bkpress record --help
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 从网络日志生成 Fixture(fixture)
|
|
88
|
+
|
|
89
|
+
适用于:在真实页面上操作一遍后,把 **XHR / Fetch 的响应体** 落成静态 JSON,供 `cy.intercept` 等场景做桩数据。
|
|
90
|
+
|
|
91
|
+
**前置条件**
|
|
92
|
+
|
|
93
|
+
1. 在 Chrome 应用商店安装 **Web Interaction Logger** 插件,在目标站点录制并导出 **`web-interaction-log.json`**。
|
|
94
|
+
2. 将该文件放在**当前项目根目录**(与执行 `bkpress fixture` 时的 `cwd` 一致)。
|
|
95
|
+
|
|
96
|
+
**用法**
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
bkpress fixture
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**行为说明**
|
|
103
|
+
|
|
104
|
+
- 读取根目录下的 `web-interaction-log.json`;若不存在会提示先安装插件并导出文件。
|
|
105
|
+
- 仅处理满足以下条件的条目:`type` 为 `network`、`subtype` 为 `response-body`,且 `url` 为以 `/` 开头的相对路径(站点内接口)。
|
|
106
|
+
- 在根目录创建或使用 **`cypress_fixtures/`** 目录,按请求方法与 URL 路径写入多个 `.json` 文件(内容为对应条目的 `responseBody`)。
|
|
107
|
+
|
|
108
|
+
生成后可在 Cypress 中把上述路径配进 `cy.fixture` / `cy.intercept` 的 `fixture` 或 `body`,与项目内约定保持一致即可。
|
|
109
|
+
|
|
110
|
+
## 从 Chrome Recorder 生成测试脚本(record)
|
|
111
|
+
|
|
112
|
+
适用于:使用 **Cypress Chrome Recorder** 插件导出录制的json后,一键生成 Cypress 测试用例代码。
|
|
113
|
+
|
|
114
|
+
**用法**
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# 单个文件
|
|
118
|
+
bkpress record ./recordings/flow.json
|
|
119
|
+
|
|
120
|
+
# 多个文件依次转换
|
|
121
|
+
bkpress record ./a.json ./b.json
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
路径为相对于当前工作目录的相对路径,或可使用绝对路径。
|
|
125
|
+
|
|
66
126
|
## 配置文件
|
|
67
127
|
|
|
68
128
|
### cypress.env.json
|
|
@@ -75,7 +135,8 @@ pnpm add bk-press
|
|
|
75
135
|
{
|
|
76
136
|
"DEV_URL": "https://your-dev-domain.com",
|
|
77
137
|
"LOCAL_URL": "http://localhost:8080",
|
|
78
|
-
"
|
|
138
|
+
"COOKIE_DOMAIN_A": "your-domain.com",
|
|
139
|
+
"COOKIE_DOMAIN_B": "your-domain.com",
|
|
79
140
|
}
|
|
80
141
|
```
|
|
81
142
|
|
|
@@ -86,7 +147,8 @@ pnpm add bk-press
|
|
|
86
147
|
{
|
|
87
148
|
"DEV_URL": "https://your-dev-domain.com",
|
|
88
149
|
"LOCAL_URL": "http://localhost:8080",
|
|
89
|
-
"
|
|
150
|
+
"COOKIE_DOMAIN_A": "your-domain.com",
|
|
151
|
+
"COOKIE_DOMAIN_B": "your-domain.com",
|
|
90
152
|
"sessionId": "xxx",
|
|
91
153
|
"token": "xxx"
|
|
92
154
|
// ... 其他 Cookie
|
|
@@ -97,7 +159,7 @@ pnpm add bk-press
|
|
|
97
159
|
|
|
98
160
|
- `DEV_URL`: 开发环境 URL,用于登录获取 Cookie
|
|
99
161
|
- `LOCAL_URL`: 本地开发服务器 URL,用于运行测试
|
|
100
|
-
- `
|
|
162
|
+
- `COOKIE_DOMAIN_A`: Cookie 的域名,用于设置 Cookie 的作用域,可能有多个,自行命名
|
|
101
163
|
|
|
102
164
|
### cypress.config.ts
|
|
103
165
|
|
|
@@ -123,12 +185,14 @@ export default defineConfig({
|
|
|
123
185
|
your-project/
|
|
124
186
|
├── cypress/
|
|
125
187
|
│ ├── e2e/ # 端到端测试用例
|
|
126
|
-
│ ├── fixtures/ #
|
|
188
|
+
│ ├── fixtures/ # 测试数据(Cypress 默认 fixtures)
|
|
127
189
|
│ ├── support/ # 支持文件
|
|
128
190
|
│ │ ├── commands.ts # 自定义命令
|
|
129
191
|
│ │ ├── e2e.ts # E2E 测试支持
|
|
130
192
|
│ │ └── login.ts # 登录命令(由 login 命令生成)
|
|
131
193
|
│ └── ...
|
|
194
|
+
├── cypress_fixtures/ # fixture 命令由网络日志生成的响应 JSON(可选,运行 fixture 后出现)
|
|
195
|
+
├── web-interaction-log.json # Web Interaction Logger 导出文件(可选,供 fixture 使用)
|
|
132
196
|
├── cypress.config.ts # Cypress 配置文件
|
|
133
197
|
├── cypress.env.json # 环境变量配置(包含 Cookie)
|
|
134
198
|
└── package.json # 包含测试脚本
|
|
@@ -157,6 +221,18 @@ bkpress login
|
|
|
157
221
|
bkpress run
|
|
158
222
|
```
|
|
159
223
|
|
|
224
|
+
### 从网络日志生成接口 Fixture
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
bkpress fixture
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### 从 Recorder JSON 生成 Cypress 脚本
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
bkpress record ./my-flow.json
|
|
234
|
+
```
|
|
235
|
+
|
|
160
236
|
### 在测试用例中使用登录
|
|
161
237
|
|
|
162
238
|
```typescript
|
|
@@ -242,3 +318,30 @@ npm run component-test
|
|
|
242
318
|
- 检查 `cypress.env.json` 文件是否包含 Cookie
|
|
243
319
|
- 检查 `cypress/support/login.ts` 文件是否正确生成
|
|
244
320
|
- 确保 `cypress/support/e2e.ts` 中导入了 `./login`
|
|
321
|
+
|
|
322
|
+
### 6. fixture 报错:web-interaction-log.json 不存在
|
|
323
|
+
|
|
324
|
+
**问题:** 运行 `bkpress fixture` 时提示找不到 `web-interaction-log.json`
|
|
325
|
+
|
|
326
|
+
**解决方案:**
|
|
327
|
+
|
|
328
|
+
- 确认文件位于**项目根目录**,且文件名为 `web-interaction-log.json`
|
|
329
|
+
- 在 Chrome 中安装 **Web Interaction Logger**,完成录制后使用插件的导出功能保存到上述路径
|
|
330
|
+
|
|
331
|
+
### 7. fixture 未生成预期文件
|
|
332
|
+
|
|
333
|
+
**问题:** 命令成功但 `cypress_fixtures/` 里文件很少或为空
|
|
334
|
+
|
|
335
|
+
**解决方案:**
|
|
336
|
+
|
|
337
|
+
- 当前逻辑只收录 **相对路径** 接口(`url` 以 `/` 开头);完整 URL(`https://...`)会被过滤掉
|
|
338
|
+
- 只处理 **`response-body`** 类型的网络日志,请确认导出内容里包含响应体
|
|
339
|
+
- 若条目缺少 `responseBody`,对应文件不会写入
|
|
340
|
+
|
|
341
|
+
### 8. record 命令失败
|
|
342
|
+
|
|
343
|
+
**问题:** `bkpress record` 退出码非 0 或 `npx` 报错
|
|
344
|
+
|
|
345
|
+
**解决方案:**
|
|
346
|
+
|
|
347
|
+
- 确认已传入至少一个 JSON 路径:`bkpress record ./your.json`
|
package/lib/command/fixture.js
CHANGED
|
@@ -23,8 +23,13 @@ async function fixture() {
|
|
|
23
23
|
await (0, util_1.createFolder)(commonPath);
|
|
24
24
|
console.log(`创建 fixtures 文件夹: ${commonPath}`);
|
|
25
25
|
}
|
|
26
|
+
console.log("validLogList>>>", validLogList);
|
|
26
27
|
validLogList.forEach(async (log) => {
|
|
27
28
|
const jsonContent = log.responseBody;
|
|
29
|
+
if (!jsonContent) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// console.log("jsonContent>>>", jsonContent);
|
|
28
33
|
const jsonString = JSON.stringify(jsonContent, null, 2);
|
|
29
34
|
const isExistQuery = log.url.includes("?");
|
|
30
35
|
let fileName = "";
|
package/lib/command/index.js
CHANGED
package/lib/command/init.js
CHANGED
|
@@ -5,13 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.init = init;
|
|
7
7
|
const child_process_1 = require("child_process");
|
|
8
|
-
const which_pm_runs_1 = __importDefault(require("which-pm-runs"));
|
|
9
8
|
const path_1 = __importDefault(require("path"));
|
|
10
9
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
11
10
|
const util_1 = require("../util");
|
|
12
11
|
async function init() {
|
|
13
12
|
console.log("开始初始化Cypress自动化测试环境...");
|
|
14
|
-
console.log("
|
|
13
|
+
console.log("全局安装 Chrome Recorder...");
|
|
14
|
+
await installChromeRecorderGlobal();
|
|
15
|
+
console.log("安装 Cypress 相关依赖...");
|
|
15
16
|
await installDependencies();
|
|
16
17
|
console.log("添加类型到 tsconfig.json 文件...");
|
|
17
18
|
await addCypressTypesToTsconfigJsonFile();
|
|
@@ -25,12 +26,13 @@ async function init() {
|
|
|
25
26
|
await addCypressEnvJsonFile();
|
|
26
27
|
console.log("添加忽略文件到 .gitignore 文件...");
|
|
27
28
|
await addIgnoreToGitignoreFile();
|
|
28
|
-
console.log("Cypress
|
|
29
|
+
console.log("Cypress自动化测试环境初始化完成!");
|
|
29
30
|
}
|
|
30
31
|
// 安装自动化测试相关依赖
|
|
31
32
|
function installDependencies() {
|
|
32
33
|
return new Promise((resolve, reject) => {
|
|
33
|
-
const pkgTool = (0,
|
|
34
|
+
const pkgTool = (0, util_1.getPkgTool)();
|
|
35
|
+
console.log("pkgTool>>>", pkgTool);
|
|
34
36
|
const installPrefix = pkgTool === "npm" ? `${pkgTool} install -D` : `${pkgTool} add -D`;
|
|
35
37
|
(0, child_process_1.exec)(`${installPrefix} cypress cypress-parallel cypress-multi-reporters start-server-and-test`, {
|
|
36
38
|
cwd: process.cwd(),
|
|
@@ -45,6 +47,22 @@ function installDependencies() {
|
|
|
45
47
|
});
|
|
46
48
|
});
|
|
47
49
|
}
|
|
50
|
+
// 安装 Chrome Recorder 全局依赖
|
|
51
|
+
function installChromeRecorderGlobal() {
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
(0, child_process_1.exec)("npm install -g @cypress/chrome-recorder", {
|
|
54
|
+
cwd: process.cwd(),
|
|
55
|
+
}, (error, stdout, stderr) => {
|
|
56
|
+
if (error) {
|
|
57
|
+
console.error("Chrome Recorder 安装失败:", error);
|
|
58
|
+
reject(error);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
console.log("Chrome Recorder 安装成功!");
|
|
62
|
+
resolve(stdout);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
48
66
|
// 添加脚本到 package.json
|
|
49
67
|
async function addScriptsToPackageJson() {
|
|
50
68
|
const packageJsonFile = path_1.default.join(process.cwd(), "package.json");
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.record = record;
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
async function record(filePaths) {
|
|
10
|
+
if (!filePaths.length) {
|
|
11
|
+
throw new Error("请提供 Cypress Chrome Recorder 录制的 json 文件路径");
|
|
12
|
+
}
|
|
13
|
+
for (const filePath of filePaths) {
|
|
14
|
+
await createCypressScript(filePath);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function createCypressScript(filePath) {
|
|
18
|
+
const targetPath = path_1.default.resolve(process.cwd(), filePath);
|
|
19
|
+
console.log(`开始生成 Cypress 测试脚本: ${targetPath}`);
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
const child = (0, child_process_1.spawn)("npx", ["@cypress/chrome-recorder", targetPath], {
|
|
22
|
+
cwd: process.cwd(),
|
|
23
|
+
stdio: "inherit",
|
|
24
|
+
shell: process.platform === "win32",
|
|
25
|
+
});
|
|
26
|
+
child.on("error", (error) => {
|
|
27
|
+
console.error("生成 Cypress 测试脚本失败:", error);
|
|
28
|
+
reject(error);
|
|
29
|
+
});
|
|
30
|
+
child.on("close", (code) => {
|
|
31
|
+
if (code !== 0) {
|
|
32
|
+
reject(new Error(`生成 Cypress 测试脚本失败,退出码: ${code}`));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
console.log("生成 Cypress 测试脚本完成!");
|
|
36
|
+
resolve();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -6,7 +6,7 @@ const command_1 = require("./command");
|
|
|
6
6
|
const program = new commander_1.Command();
|
|
7
7
|
program
|
|
8
8
|
.name("bk-press")
|
|
9
|
-
.description("一个用于 Cypress 自动化测试的 CLI
|
|
9
|
+
.description("一个用于 Cypress 自动化测试的 CLI 工具,提供了快速初始化测试环境、并行运行自动化测试、生成 fixture 拦截数据、生成 Cypress 测试脚本等强大功能。")
|
|
10
10
|
.version("0.0.5");
|
|
11
11
|
program
|
|
12
12
|
.command("init")
|
|
@@ -22,4 +22,9 @@ program
|
|
|
22
22
|
.command("fixture")
|
|
23
23
|
.description("根据 Chrome 插件 Web Interaction Logger 导出的 web-interaction-log.json 生成 fixture 拦截数据")
|
|
24
24
|
.action(command_1.fixture);
|
|
25
|
+
program
|
|
26
|
+
.command("record")
|
|
27
|
+
.description("根据 Cypress Chrome Recorder 录制的 json 文件生成 Cypress 测试脚本")
|
|
28
|
+
.argument("<paths...>", "目标文件路径,支持传入多个")
|
|
29
|
+
.action(command_1.record);
|
|
25
30
|
program.parse(process.argv);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getPkgTool = getPkgTool;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const which_pm_runs_1 = __importDefault(require("which-pm-runs"));
|
|
10
|
+
// npx 等场景下 UA 常为 npm;若存在 pnpm-lock.yaml 则按 pnpm 安装。
|
|
11
|
+
function getPkgTool() {
|
|
12
|
+
if (fs_1.default.existsSync(path_1.default.join(process.cwd(), "pnpm-lock.yaml"))) {
|
|
13
|
+
return "pnpm";
|
|
14
|
+
}
|
|
15
|
+
return (0, which_pm_runs_1.default)()?.name || "npm";
|
|
16
|
+
}
|
package/lib/util/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bk-press",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "一个用于 Cypress 自动化测试的 CLI
|
|
3
|
+
"version": "0.0.6",
|
|
4
|
+
"description": "一个用于 Cypress 自动化测试的 CLI 工具,提供了快速初始化测试环境、并行运行自动化测试、生成 fixture 拦截数据、生成 Cypress 测试脚本等强大功能。",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"bkpress": "./lib/index.js"
|
package/src/command/fixture.ts
CHANGED
|
@@ -42,6 +42,9 @@ export async function fixture() {
|
|
|
42
42
|
}
|
|
43
43
|
validLogList.forEach(async (log) => {
|
|
44
44
|
const jsonContent = log.responseBody;
|
|
45
|
+
if (!jsonContent) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
45
48
|
const jsonString = JSON.stringify(jsonContent, null, 2);
|
|
46
49
|
const isExistQuery = log.url.includes("?");
|
|
47
50
|
let fileName = "";
|
package/src/command/index.ts
CHANGED
package/src/command/init.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { exec } from "child_process";
|
|
2
|
-
import whichPMRuns from "which-pm-runs";
|
|
3
2
|
import path from "path";
|
|
4
3
|
import fs from "fs-extra";
|
|
5
4
|
import {
|
|
@@ -8,11 +7,14 @@ import {
|
|
|
8
7
|
createFolder,
|
|
9
8
|
deleteFolder,
|
|
10
9
|
isFileOrFolderExist,
|
|
10
|
+
getPkgTool,
|
|
11
11
|
} from "../util";
|
|
12
12
|
|
|
13
13
|
export async function init() {
|
|
14
14
|
console.log("开始初始化Cypress自动化测试环境...");
|
|
15
|
-
console.log("
|
|
15
|
+
console.log("全局安装 Chrome Recorder...");
|
|
16
|
+
await installChromeRecorderGlobal();
|
|
17
|
+
console.log("安装 Cypress 相关依赖...");
|
|
16
18
|
await installDependencies();
|
|
17
19
|
console.log("添加类型到 tsconfig.json 文件...");
|
|
18
20
|
await addCypressTypesToTsconfigJsonFile();
|
|
@@ -26,13 +28,13 @@ export async function init() {
|
|
|
26
28
|
await addCypressEnvJsonFile();
|
|
27
29
|
console.log("添加忽略文件到 .gitignore 文件...");
|
|
28
30
|
await addIgnoreToGitignoreFile();
|
|
29
|
-
console.log("Cypress
|
|
31
|
+
console.log("Cypress自动化测试环境初始化完成!");
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
// 安装自动化测试相关依赖
|
|
33
35
|
function installDependencies() {
|
|
34
36
|
return new Promise((resolve, reject) => {
|
|
35
|
-
const pkgTool =
|
|
37
|
+
const pkgTool = getPkgTool();
|
|
36
38
|
|
|
37
39
|
const installPrefix =
|
|
38
40
|
pkgTool === "npm" ? `${pkgTool} install -D` : `${pkgTool} add -D`;
|
|
@@ -50,7 +52,28 @@ function installDependencies() {
|
|
|
50
52
|
}
|
|
51
53
|
console.log("依赖安装成功!");
|
|
52
54
|
resolve(stdout);
|
|
53
|
-
}
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 安装 Chrome Recorder 全局依赖
|
|
61
|
+
function installChromeRecorderGlobal() {
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
exec(
|
|
64
|
+
"npm install -g @cypress/chrome-recorder",
|
|
65
|
+
{
|
|
66
|
+
cwd: process.cwd(),
|
|
67
|
+
},
|
|
68
|
+
(error, stdout, stderr) => {
|
|
69
|
+
if (error) {
|
|
70
|
+
console.error("Chrome Recorder 安装失败:", error);
|
|
71
|
+
reject(error);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
console.log("Chrome Recorder 安装成功!");
|
|
75
|
+
resolve(stdout);
|
|
76
|
+
},
|
|
54
77
|
);
|
|
55
78
|
});
|
|
56
79
|
}
|
|
@@ -69,7 +92,7 @@ async function addScriptsToPackageJson() {
|
|
|
69
92
|
// 创建 cypress 文件夹并拉取模板文件
|
|
70
93
|
async function addTemplateFiles() {
|
|
71
94
|
const isCypressExist = await isFileOrFolderExist(
|
|
72
|
-
path.join(process.cwd(), "cypress")
|
|
95
|
+
path.join(process.cwd(), "cypress"),
|
|
73
96
|
);
|
|
74
97
|
if (isCypressExist) {
|
|
75
98
|
console.log("cypress 文件夹已存在,跳过拉取模板文件");
|
|
@@ -116,7 +139,7 @@ function cloneTemplateFiles(isTsProject = true) {
|
|
|
116
139
|
return;
|
|
117
140
|
}
|
|
118
141
|
resolve(stdout);
|
|
119
|
-
}
|
|
142
|
+
},
|
|
120
143
|
);
|
|
121
144
|
});
|
|
122
145
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
export async function record(filePaths: string[]) {
|
|
5
|
+
if (!filePaths.length) {
|
|
6
|
+
throw new Error("请提供 Cypress Chrome Recorder 录制的 json 文件路径");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
for (const filePath of filePaths) {
|
|
10
|
+
await createCypressScript(filePath);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function createCypressScript(filePath: string) {
|
|
15
|
+
const targetPath = path.resolve(process.cwd(), filePath);
|
|
16
|
+
console.log(`开始生成 Cypress 测试脚本: ${targetPath}`);
|
|
17
|
+
|
|
18
|
+
return new Promise<void>((resolve, reject) => {
|
|
19
|
+
const child = spawn("npx", ["@cypress/chrome-recorder", targetPath], {
|
|
20
|
+
cwd: process.cwd(),
|
|
21
|
+
stdio: "inherit",
|
|
22
|
+
shell: process.platform === "win32",
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
child.on("error", (error) => {
|
|
26
|
+
console.error("生成 Cypress 测试脚本失败:", error);
|
|
27
|
+
reject(error);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
child.on("close", (code) => {
|
|
31
|
+
if (code !== 0) {
|
|
32
|
+
reject(new Error(`生成 Cypress 测试脚本失败,退出码: ${code}`));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log("生成 Cypress 测试脚本完成!");
|
|
37
|
+
resolve();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { Command } from "commander";
|
|
4
|
-
import { login, init, run, fixture } from "./command";
|
|
4
|
+
import { login, init, run, fixture, record } from "./command";
|
|
5
5
|
|
|
6
6
|
const program = new Command();
|
|
7
7
|
|
|
8
8
|
program
|
|
9
9
|
.name("bk-press")
|
|
10
10
|
.description(
|
|
11
|
-
"一个用于 Cypress 自动化测试的 CLI
|
|
11
|
+
"一个用于 Cypress 自动化测试的 CLI 工具,提供了快速初始化测试环境、并行运行自动化测试、生成 fixture 拦截数据、生成 Cypress 测试脚本等强大功能。",
|
|
12
12
|
)
|
|
13
13
|
.version("0.0.5");
|
|
14
14
|
|
|
@@ -28,4 +28,11 @@ program
|
|
|
28
28
|
"根据 Chrome 插件 Web Interaction Logger 导出的 web-interaction-log.json 生成 fixture 拦截数据",
|
|
29
29
|
)
|
|
30
30
|
.action(fixture);
|
|
31
|
+
program
|
|
32
|
+
.command("record")
|
|
33
|
+
.description(
|
|
34
|
+
"根据 Cypress Chrome Recorder 录制的 json 文件生成 Cypress 测试脚本",
|
|
35
|
+
)
|
|
36
|
+
.argument("<paths...>", "目标文件路径,支持传入多个")
|
|
37
|
+
.action(record);
|
|
31
38
|
program.parse(process.argv);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import whichPMRuns from "which-pm-runs";
|
|
4
|
+
|
|
5
|
+
// npx 等场景下 UA 常为 npm;若存在 pnpm-lock.yaml 则按 pnpm 安装。
|
|
6
|
+
export function getPkgTool() {
|
|
7
|
+
if (fs.existsSync(path.join(process.cwd(), "pnpm-lock.yaml"))) {
|
|
8
|
+
return "pnpm";
|
|
9
|
+
}
|
|
10
|
+
return whichPMRuns()?.name || "npm";
|
|
11
|
+
}
|
package/src/util/index.ts
CHANGED