@be-link/smart-test 1.0.1-beta.7 → 1.0.1-beta.8
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 +32 -271
- package/dist/core/ai-assistant.d.ts.map +1 -1
- package/dist/core/config.d.ts +1 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/types.d.ts +10 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.esm.js +36 -3
- package/dist/index.js +56 -3
- package/dist/utils/screenshot.d.ts +9 -0
- package/dist/utils/screenshot.d.ts.map +1 -1
- package/package.json +3 -20
- package/bin/smart-test.js +0 -15
- package/dist/analyzer/code-analyzer.d.ts +0 -32
- package/dist/analyzer/code-analyzer.d.ts.map +0 -1
- package/dist/analyzer/index.d.ts +0 -7
- package/dist/analyzer/index.d.ts.map +0 -1
- package/dist/analyzer/mock-generator.d.ts +0 -53
- package/dist/analyzer/mock-generator.d.ts.map +0 -1
- package/dist/analyzer/react-analyzer.d.ts +0 -62
- package/dist/analyzer/react-analyzer.d.ts.map +0 -1
- package/dist/analyzer/test-generator.d.ts +0 -38
- package/dist/analyzer/test-generator.d.ts.map +0 -1
- package/dist/analyzer/type-analyzer.d.ts +0 -50
- package/dist/analyzer/type-analyzer.d.ts.map +0 -1
- package/dist/analyzer/types.d.ts +0 -170
- package/dist/analyzer/types.d.ts.map +0 -1
- package/dist/cli/commands/generate.d.ts +0 -22
- package/dist/cli/commands/generate.d.ts.map +0 -1
- package/dist/cli/commands/init.d.ts +0 -5
- package/dist/cli/commands/init.d.ts.map +0 -1
- package/dist/cli/index.d.ts +0 -10
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js +0 -2117
- package/dist/config/config-loader.d.ts +0 -35
- package/dist/config/config-loader.d.ts.map +0 -1
- package/dist/config/config-schema.d.ts +0 -85
- package/dist/config/config-schema.d.ts.map +0 -1
- package/dist/utils/error-handler.d.ts +0 -41
- package/dist/utils/error-handler.d.ts.map +0 -1
- package/dist/utils/logger.d.ts +0 -88
- package/dist/utils/logger.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -6,36 +6,17 @@
|
|
|
6
6
|
|
|
7
7
|
## ✨ 特性
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
### 🎯 零代码测试生成(开发中)
|
|
16
|
-
|
|
17
|
-
- **CLI 工具**:一条命令自动生成测试代码
|
|
18
|
-
- **录制模式**:访问页面自动录制接口和交互
|
|
19
|
-
- **代码分析**:扫描项目代码自动生成 Mock 数据
|
|
20
|
-
- **AI 生成**:基于自然语言描述生成完整测试
|
|
21
|
-
|
|
22
|
-
### 🔧 灵活易用
|
|
23
|
-
|
|
24
|
-
- 与 Playwright 无缝集成,零侵入设计
|
|
25
|
-
- 支持全局配置和单次调用配置
|
|
26
|
-
- 优雅降级:无 API Key 时自动跳过
|
|
27
|
-
- 完整的 TypeScript 类型支持
|
|
28
|
-
|
|
29
|
-
### 📸 自动化
|
|
30
|
-
|
|
31
|
-
- 自动截图并保存
|
|
32
|
-
- 自动生成 Mock 数据
|
|
33
|
-
- 自动生成测试用例
|
|
9
|
+
- 🤖 **AI 视觉检查**:基于通义千问等视觉模型,智能检查页面是否符合预期
|
|
10
|
+
- 🎯 **零侵入设计**:与 Playwright 无缝集成,无需修改现有测试代码
|
|
11
|
+
- 🔧 **灵活配置**:支持全局配置和单次调用配置
|
|
12
|
+
- 📸 **自动截图**:自动保存测试截图,方便排查问题
|
|
13
|
+
- 🚫 **优雅降级**:无 API Key 时自动跳过,不影响其他测试
|
|
14
|
+
- 📦 **TypeScript**:完整的类型定义支持
|
|
34
15
|
|
|
35
16
|
## 📦 安装
|
|
36
17
|
|
|
37
18
|
```bash
|
|
38
|
-
# 使用 pnpm
|
|
19
|
+
# 使用 pnpm
|
|
39
20
|
pnpm add -D @be-link/smart-test
|
|
40
21
|
|
|
41
22
|
# 使用 npm
|
|
@@ -47,56 +28,7 @@ yarn add -D @be-link/smart-test
|
|
|
47
28
|
|
|
48
29
|
## 🚀 快速开始
|
|
49
30
|
|
|
50
|
-
###
|
|
51
|
-
|
|
52
|
-
#### 1. 初始化配置
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
npx smart-test init
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
交互式配置向导会引导你完成设置:
|
|
59
|
-
|
|
60
|
-
```
|
|
61
|
-
━━━ 初始化 Smart Test 配置 ━━━
|
|
62
|
-
|
|
63
|
-
? 请输入 AI API Key: sk-xxxxx
|
|
64
|
-
? 选择 AI 模型: 通义千问 (qwen3-vl-plus)
|
|
65
|
-
? 测试文件目录: ./tests/e2e
|
|
66
|
-
? Helpers 目录: ./tests/helpers
|
|
67
|
-
? Playwright Base URL: http://localhost:8080
|
|
68
|
-
? 文件命名风格: kebab-case
|
|
69
|
-
|
|
70
|
-
✓ 配置文件已创建: .smarttestrc.json
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
#### 2. 生成测试代码(开发中)
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
# 录制模式 - 访问页面自动录制
|
|
77
|
-
npx smart-test record --url http://localhost:8080/coupon
|
|
78
|
-
|
|
79
|
-
# 代码分析模式 - 扫描页面代码
|
|
80
|
-
npx smart-test generate --page src/pages/coupon/index.tsx
|
|
81
|
-
|
|
82
|
-
# 描述生成模式 - 基于自然语言
|
|
83
|
-
npx smart-test generate --desc "优惠券列表页,有可用券和已用券两个 tab"
|
|
84
|
-
|
|
85
|
-
# 交互式模式 - 引导式生成
|
|
86
|
-
npx smart-test generate --interactive
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
#### 3. 运行测试
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
npx playwright test
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
### 方式二:手动编程
|
|
98
|
-
|
|
99
|
-
#### 1. 配置 API Key
|
|
31
|
+
### 1. 配置 API Key
|
|
100
32
|
|
|
101
33
|
在项目根目录创建 `.env` 文件:
|
|
102
34
|
|
|
@@ -104,7 +36,7 @@ npx playwright test
|
|
|
104
36
|
AI_API_KEY=sk-your-api-key-here
|
|
105
37
|
```
|
|
106
38
|
|
|
107
|
-
|
|
39
|
+
### 2. 初始化配置
|
|
108
40
|
|
|
109
41
|
在 `playwright.config.ts` 中配置:
|
|
110
42
|
|
|
@@ -123,7 +55,7 @@ export default defineConfig({
|
|
|
123
55
|
});
|
|
124
56
|
```
|
|
125
57
|
|
|
126
|
-
|
|
58
|
+
### 3. 在测试中使用
|
|
127
59
|
|
|
128
60
|
```typescript
|
|
129
61
|
import { test, expect } from '@playwright/test';
|
|
@@ -146,95 +78,7 @@ test.describe('优惠券页面', () => {
|
|
|
146
78
|
});
|
|
147
79
|
```
|
|
148
80
|
|
|
149
|
-
## 📖
|
|
150
|
-
|
|
151
|
-
### `smart-test init`
|
|
152
|
-
|
|
153
|
-
初始化配置文件,交互式设置 AI API Key、模型、输出目录等。
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
smart-test init
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### `smart-test generate` (开发中)
|
|
160
|
-
|
|
161
|
-
生成测试代码。
|
|
162
|
-
|
|
163
|
-
```bash
|
|
164
|
-
# 基础用法
|
|
165
|
-
smart-test generate
|
|
166
|
-
|
|
167
|
-
# 指定页面(代码分析模式)
|
|
168
|
-
smart-test generate --page <path>
|
|
169
|
-
|
|
170
|
-
# 指定 URL(录制模式)
|
|
171
|
-
smart-test generate --url <url>
|
|
172
|
-
|
|
173
|
-
# 基于描述(自然语言模式)
|
|
174
|
-
smart-test generate --desc <description>
|
|
175
|
-
|
|
176
|
-
# 交互式模式
|
|
177
|
-
smart-test generate --interactive
|
|
178
|
-
|
|
179
|
-
# 指定输出目录
|
|
180
|
-
smart-test generate --page <path> --output tests/custom
|
|
181
|
-
|
|
182
|
-
# 预览模式(不写入文件)
|
|
183
|
-
smart-test generate --page <path> --dry-run
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
**选项:**
|
|
187
|
-
|
|
188
|
-
| 选项 | 简写 | 说明 |
|
|
189
|
-
| ---------------------- | ---- | ---------------------------- |
|
|
190
|
-
| `--page <path>` | `-p` | 页面文件路径(代码分析模式) |
|
|
191
|
-
| `--url <url>` | `-u` | 页面 URL(录制模式) |
|
|
192
|
-
| `--desc <description>` | `-d` | 页面描述(自然语言模式) |
|
|
193
|
-
| `--output <dir>` | `-o` | 输出目录 |
|
|
194
|
-
| `--interactive` | `-i` | 交互式模式 |
|
|
195
|
-
| `--dry-run` | | 预览模式,不写入文件 |
|
|
196
|
-
|
|
197
|
-
### `smart-test record` (开发中)
|
|
198
|
-
|
|
199
|
-
录制模式的快捷命令(`generate --url` 的别名)。
|
|
200
|
-
|
|
201
|
-
```bash
|
|
202
|
-
# 基础录制
|
|
203
|
-
smart-test record --url http://localhost:8080/coupon
|
|
204
|
-
|
|
205
|
-
# 手动操作模式
|
|
206
|
-
smart-test record --url http://localhost:8080/coupon --manual
|
|
207
|
-
|
|
208
|
-
# 交互式引导
|
|
209
|
-
smart-test record --url http://localhost:8080/coupon --interactive
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
**选项:**
|
|
213
|
-
|
|
214
|
-
| 选项 | 简写 | 说明 |
|
|
215
|
-
| ---------------- | ---- | ------------------------ |
|
|
216
|
-
| `--url <url>` | `-u` | 要录制的页面 URL(必需) |
|
|
217
|
-
| `--output <dir>` | `-o` | 输出目录 |
|
|
218
|
-
| `--manual` | | 手动操作模式 |
|
|
219
|
-
| `--interactive` | | 交互式引导 |
|
|
220
|
-
|
|
221
|
-
### `smart-test config`
|
|
222
|
-
|
|
223
|
-
查看当前配置。
|
|
224
|
-
|
|
225
|
-
```bash
|
|
226
|
-
smart-test config
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### 全局选项
|
|
230
|
-
|
|
231
|
-
| 选项 | 简写 | 说明 |
|
|
232
|
-
| ----------- | ---- | -------------------- |
|
|
233
|
-
| `--version` | `-V` | 显示版本号 |
|
|
234
|
-
| `--verbose` | `-v` | 详细输出(调试模式) |
|
|
235
|
-
| `--help` | `-h` | 显示帮助信息 |
|
|
236
|
-
|
|
237
|
-
## 📖 编程 API 文档
|
|
81
|
+
## 📖 API 文档
|
|
238
82
|
|
|
239
83
|
### `configure(config)`
|
|
240
84
|
|
|
@@ -247,6 +91,8 @@ configure({
|
|
|
247
91
|
apiKey: 'sk-xxx', // AI API 密钥
|
|
248
92
|
baseURL: 'https://...', // AI 服务地址(可选)
|
|
249
93
|
model: 'qwen3-vl-plus', // AI 模型(可选)
|
|
94
|
+
screenshotDir: './screenshots', // 截图保存目录(可选)
|
|
95
|
+
saveScreenshots: true, // 是否保存截图(可选)
|
|
250
96
|
timeout: 30000, // 超时时间(可选)
|
|
251
97
|
});
|
|
252
98
|
```
|
|
@@ -335,48 +181,26 @@ test.describe('商品页面测试', () => {
|
|
|
335
181
|
});
|
|
336
182
|
```
|
|
337
183
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
{
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
"testsDir": "./tests/e2e",
|
|
355
|
-
"helpersDir": "./tests/helpers",
|
|
356
|
-
"naming": "kebab-case"
|
|
357
|
-
},
|
|
358
|
-
"templates": {
|
|
359
|
-
"mock": "default",
|
|
360
|
-
"test": "default"
|
|
361
|
-
},
|
|
362
|
-
"playwright": {
|
|
363
|
-
"baseURL": "http://localhost:8080",
|
|
364
|
-
"viewport": {
|
|
365
|
-
"width": 375,
|
|
366
|
-
"height": 667
|
|
367
|
-
},
|
|
368
|
-
"browser": "chromium"
|
|
184
|
+
### 批量检查多个元素
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
test('检查多个区域', async ({ page }) => {
|
|
188
|
+
const checks = [
|
|
189
|
+
{ selector: '.header', expected: '顶部导航栏应显示 logo 和菜单' },
|
|
190
|
+
{ selector: '.main-content', expected: '主内容区应显示文章列表' },
|
|
191
|
+
{ selector: '.sidebar', expected: '侧边栏应显示热门标签' },
|
|
192
|
+
];
|
|
193
|
+
|
|
194
|
+
for (const check of checks) {
|
|
195
|
+
const element = await page.locator(check.selector);
|
|
196
|
+
const screenshot = await element.screenshot();
|
|
197
|
+
|
|
198
|
+
// 这里可以扩展为单独检查某个元素的功能
|
|
199
|
+
// 当前版本检查整页,后续可以增强
|
|
369
200
|
}
|
|
370
|
-
}
|
|
201
|
+
});
|
|
371
202
|
```
|
|
372
203
|
|
|
373
|
-
### 支持的配置格式
|
|
374
|
-
|
|
375
|
-
- `.smarttestrc.json`
|
|
376
|
-
- `.smarttestrc.js`
|
|
377
|
-
- `smarttest.config.js`
|
|
378
|
-
- `package.json` 中的 `smarttest` 字段
|
|
379
|
-
|
|
380
204
|
## 🔧 高级配置
|
|
381
205
|
|
|
382
206
|
### 支持多种 AI 模型
|
|
@@ -408,8 +232,6 @@ configure({
|
|
|
408
232
|
// 单次调用自定义
|
|
409
233
|
const result = await aiReviewScreenshot(page, {
|
|
410
234
|
expected: '...',
|
|
411
|
-
screenshotPrefix: 'my-feature',
|
|
412
|
-
screenshotDir: './feature-screenshots',
|
|
413
235
|
});
|
|
414
236
|
```
|
|
415
237
|
|
|
@@ -437,17 +259,9 @@ A: 理论上支持所有兼容 OpenAI Chat Completions API 的视觉模型,包
|
|
|
437
259
|
- OpenAI GPT-4 Vision
|
|
438
260
|
- 其他兼容的模型服务
|
|
439
261
|
|
|
440
|
-
### Q:
|
|
441
|
-
|
|
442
|
-
A: 生成的代码是可以直接运行的,但建议根据实际需求进行调整。AI 会尽量生成合理的测试用例,但可能无法覆盖所有业务场景。
|
|
443
|
-
|
|
444
|
-
### Q: 录制模式如何处理需要点击才能触发的接口?
|
|
445
|
-
|
|
446
|
-
A: 录制模式支持三种方式:
|
|
262
|
+
### Q: 截图保存在哪里?
|
|
447
263
|
|
|
448
|
-
|
|
449
|
-
2. **交互式引导**:`--interactive` 参数,AI 引导用户操作
|
|
450
|
-
3. **脚本引导**:`--actions` 参数,提供操作脚本自动执行
|
|
264
|
+
A: 默认保存在 `./test-results/ai-screenshots/` 目录,可以通过 `screenshotDir` 配置修改。
|
|
451
265
|
|
|
452
266
|
### Q: 如何查看 AI 的原始响应?
|
|
453
267
|
|
|
@@ -458,55 +272,6 @@ const result = await aiReviewScreenshot(page, '...');
|
|
|
458
272
|
console.log('AI 原始响应:', result.rawResponse);
|
|
459
273
|
```
|
|
460
274
|
|
|
461
|
-
### Q: 生成的代码文件如何组织?
|
|
462
|
-
|
|
463
|
-
A: 默认按页面分组:
|
|
464
|
-
|
|
465
|
-
- `tests/helpers/mock-{页面名}.ts` - Mock 数据
|
|
466
|
-
- `tests/e2e/{页面名}.spec.ts` - 测试用例
|
|
467
|
-
|
|
468
|
-
可以通过 `--output` 参数自定义输出目录。
|
|
469
|
-
|
|
470
|
-
## 🗺️ 开发路线图
|
|
471
|
-
|
|
472
|
-
### ✅ 已完成
|
|
473
|
-
|
|
474
|
-
- [x] AI 视觉检查核心功能
|
|
475
|
-
- [x] CLI 基础架构
|
|
476
|
-
- [x] 配置系统
|
|
477
|
-
- [x] 交互式初始化
|
|
478
|
-
|
|
479
|
-
### 🚧 开发中
|
|
480
|
-
|
|
481
|
-
- [ ] 录制模式(Phase 2)
|
|
482
|
-
- [ ] 网络请求录制
|
|
483
|
-
- [ ] HAR 文件解析
|
|
484
|
-
- [ ] AI 生成 Mock 代码
|
|
485
|
-
- [ ] 交互操作录制
|
|
486
|
-
|
|
487
|
-
### 📅 计划中
|
|
488
|
-
|
|
489
|
-
- [ ] 代码分析模式(Phase 3)
|
|
490
|
-
- [ ] TypeScript AST 解析
|
|
491
|
-
- [ ] API 调用提取
|
|
492
|
-
- [ ] 类型定义分析
|
|
493
|
-
|
|
494
|
-
- [ ] 描述生成模式(Phase 4)
|
|
495
|
-
- [ ] 自然语言理解
|
|
496
|
-
- [ ] 交互式问答
|
|
497
|
-
- [ ] 代码生成
|
|
498
|
-
|
|
499
|
-
- [ ] 增强功能(Phase 5+)
|
|
500
|
-
- [ ] 增量更新
|
|
501
|
-
- [ ] 自定义模板
|
|
502
|
-
- [ ] 测试覆盖率分析
|
|
503
|
-
- [ ] VS Code 插件
|
|
504
|
-
|
|
505
|
-
## 📄 文档
|
|
506
|
-
|
|
507
|
-
- [CLI 设计文档](./docs/CLI_DESIGN.md) - 完整的 CLI 工具设计方案
|
|
508
|
-
- [使用示例](./examples/) - 更多使用示例
|
|
509
|
-
|
|
510
275
|
## 📝 License
|
|
511
276
|
|
|
512
277
|
MIT
|
|
@@ -518,7 +283,3 @@ MIT
|
|
|
518
283
|
## 📮 联系方式
|
|
519
284
|
|
|
520
285
|
如有问题,请在 [GitHub Issues](https://github.com/snowmountain-top/be-link/issues) 中提出。
|
|
521
|
-
|
|
522
|
-
---
|
|
523
|
-
|
|
524
|
-
**版本**:v1.0.0 | **最后更新**:2025-12-30
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-assistant.d.ts","sourceRoot":"","sources":["../../src/core/ai-assistant.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAkB,MAAM,SAAS,CAAC;AAI7E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"ai-assistant.d.ts","sourceRoot":"","sources":["../../src/core/ai-assistant.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAkB,MAAM,SAAS,CAAC;AAI7E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CA2E7G"}
|
package/dist/core/config.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAmB9C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAK/D;AAED;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,QAAQ,CAAC,cAAc,CAAC,CAEpD;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,WAAW,GAAE,OAAO,CAAC,cAAc,CAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,CAK/F"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -16,6 +16,16 @@ export interface AiVisionConfig {
|
|
|
16
16
|
* @default 'qwen3-vl-plus'
|
|
17
17
|
*/
|
|
18
18
|
model?: string;
|
|
19
|
+
/**
|
|
20
|
+
* 截图保存目录
|
|
21
|
+
* @default './test-results/ai-screenshots'
|
|
22
|
+
*/
|
|
23
|
+
screenshotDir?: string;
|
|
24
|
+
/**
|
|
25
|
+
* 是否保存截图到文件
|
|
26
|
+
* @default true
|
|
27
|
+
*/
|
|
28
|
+
saveScreenshots?: boolean;
|
|
19
29
|
/**
|
|
20
30
|
* AI 请求超时时间(毫秒)
|
|
21
31
|
* @default 30000
|
package/dist/core/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,EAAE,EAAE,OAAO,CAAC;IAEZ;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,OAAO,CAAC,cAAc,CAAC;IAC7D;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,EAAE,EAAE,OAAO,CAAC;IAEZ;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,OAAO,CAAC,cAAc,CAAC;IAC7D;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB"}
|
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { OpenAI } from 'openai';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* 默认配置
|
|
@@ -7,6 +9,8 @@ const DEFAULT_CONFIG = {
|
|
|
7
9
|
apiKey: '',
|
|
8
10
|
baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
|
|
9
11
|
model: 'qwen3-vl-plus',
|
|
12
|
+
screenshotDir: './test-results/ai-screenshots',
|
|
13
|
+
saveScreenshots: true,
|
|
10
14
|
timeout: 30000,
|
|
11
15
|
};
|
|
12
16
|
/**
|
|
@@ -25,6 +29,7 @@ let globalConfig = { ...DEFAULT_CONFIG };
|
|
|
25
29
|
* configure({
|
|
26
30
|
* apiKey: process.env.AI_API_KEY,
|
|
27
31
|
* model: 'qwen3-vl-plus',
|
|
32
|
+
* screenshotDir: './screenshots',
|
|
28
33
|
* });
|
|
29
34
|
* ```
|
|
30
35
|
*/
|
|
@@ -61,6 +66,25 @@ function mergeConfig(localConfig = {}) {
|
|
|
61
66
|
};
|
|
62
67
|
}
|
|
63
68
|
|
|
69
|
+
/**
|
|
70
|
+
* 保存截图到文件
|
|
71
|
+
*
|
|
72
|
+
* @param screenshot - 截图 Buffer
|
|
73
|
+
* @param dir - 保存目录
|
|
74
|
+
* @param prefix - 文件名前缀
|
|
75
|
+
* @returns 截图文件的绝对路径
|
|
76
|
+
*/
|
|
77
|
+
async function saveScreenshot(screenshot, dir, prefix = 'ai-review') {
|
|
78
|
+
// 确保目录存在
|
|
79
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
80
|
+
// 生成文件名(使用时间戳避免冲突)
|
|
81
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
82
|
+
const filename = `${prefix}-${timestamp}.png`;
|
|
83
|
+
const screenshotPath = path.resolve(dir, filename);
|
|
84
|
+
// 写入文件
|
|
85
|
+
await fs.promises.writeFile(screenshotPath, screenshot);
|
|
86
|
+
return screenshotPath;
|
|
87
|
+
}
|
|
64
88
|
/**
|
|
65
89
|
* 将截图转换为 base64 编码
|
|
66
90
|
*
|
|
@@ -114,6 +138,12 @@ async function aiReviewScreenshot(page, options) {
|
|
|
114
138
|
const screenshot = await page.screenshot({
|
|
115
139
|
fullPage: opts.fullPage !== false,
|
|
116
140
|
});
|
|
141
|
+
// 保存截图(如果启用)
|
|
142
|
+
let screenshotPath;
|
|
143
|
+
if (config.saveScreenshots) {
|
|
144
|
+
screenshotPath = await saveScreenshot(screenshot, config.screenshotDir);
|
|
145
|
+
console.log(`[smart-test] 截图已保存: ${screenshotPath}`);
|
|
146
|
+
}
|
|
117
147
|
// 构建 AI 请求
|
|
118
148
|
const prompt = buildPrompt(opts.expected);
|
|
119
149
|
const openai = new OpenAI({
|
|
@@ -144,15 +174,18 @@ async function aiReviewScreenshot(page, options) {
|
|
|
144
174
|
// 解析 AI 响应
|
|
145
175
|
const content = completion?.choices[0]?.message?.content || '';
|
|
146
176
|
const result = parseAiResponse(content);
|
|
147
|
-
|
|
148
|
-
|
|
177
|
+
return {
|
|
178
|
+
...result,
|
|
179
|
+
screenshotPath,
|
|
180
|
+
rawResponse: content,
|
|
181
|
+
};
|
|
149
182
|
}
|
|
150
183
|
catch (error) {
|
|
151
184
|
console.error('[smart-test] AI 检查失败:', error);
|
|
152
185
|
return {
|
|
153
186
|
ok: true,
|
|
154
187
|
skipped: true,
|
|
155
|
-
reason: `
|
|
188
|
+
reason: `AI 检查失败: ${error instanceof Error ? error.message : String(error)}`,
|
|
156
189
|
};
|
|
157
190
|
}
|
|
158
191
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var openai = require('openai');
|
|
4
|
+
var fs = require('fs');
|
|
5
|
+
var path = require('path');
|
|
6
|
+
|
|
7
|
+
function _interopNamespaceDefault(e) {
|
|
8
|
+
var n = Object.create(null);
|
|
9
|
+
if (e) {
|
|
10
|
+
Object.keys(e).forEach(function (k) {
|
|
11
|
+
if (k !== 'default') {
|
|
12
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
13
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () { return e[k]; }
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
n.default = e;
|
|
21
|
+
return Object.freeze(n);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
|
|
25
|
+
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
4
26
|
|
|
5
27
|
/**
|
|
6
28
|
* 默认配置
|
|
@@ -9,6 +31,8 @@ const DEFAULT_CONFIG = {
|
|
|
9
31
|
apiKey: '',
|
|
10
32
|
baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
|
|
11
33
|
model: 'qwen3-vl-plus',
|
|
34
|
+
screenshotDir: './test-results/ai-screenshots',
|
|
35
|
+
saveScreenshots: true,
|
|
12
36
|
timeout: 30000,
|
|
13
37
|
};
|
|
14
38
|
/**
|
|
@@ -27,6 +51,7 @@ let globalConfig = { ...DEFAULT_CONFIG };
|
|
|
27
51
|
* configure({
|
|
28
52
|
* apiKey: process.env.AI_API_KEY,
|
|
29
53
|
* model: 'qwen3-vl-plus',
|
|
54
|
+
* screenshotDir: './screenshots',
|
|
30
55
|
* });
|
|
31
56
|
* ```
|
|
32
57
|
*/
|
|
@@ -63,6 +88,25 @@ function mergeConfig(localConfig = {}) {
|
|
|
63
88
|
};
|
|
64
89
|
}
|
|
65
90
|
|
|
91
|
+
/**
|
|
92
|
+
* 保存截图到文件
|
|
93
|
+
*
|
|
94
|
+
* @param screenshot - 截图 Buffer
|
|
95
|
+
* @param dir - 保存目录
|
|
96
|
+
* @param prefix - 文件名前缀
|
|
97
|
+
* @returns 截图文件的绝对路径
|
|
98
|
+
*/
|
|
99
|
+
async function saveScreenshot(screenshot, dir, prefix = 'ai-review') {
|
|
100
|
+
// 确保目录存在
|
|
101
|
+
await fs__namespace.promises.mkdir(dir, { recursive: true });
|
|
102
|
+
// 生成文件名(使用时间戳避免冲突)
|
|
103
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
104
|
+
const filename = `${prefix}-${timestamp}.png`;
|
|
105
|
+
const screenshotPath = path__namespace.resolve(dir, filename);
|
|
106
|
+
// 写入文件
|
|
107
|
+
await fs__namespace.promises.writeFile(screenshotPath, screenshot);
|
|
108
|
+
return screenshotPath;
|
|
109
|
+
}
|
|
66
110
|
/**
|
|
67
111
|
* 将截图转换为 base64 编码
|
|
68
112
|
*
|
|
@@ -116,6 +160,12 @@ async function aiReviewScreenshot(page, options) {
|
|
|
116
160
|
const screenshot = await page.screenshot({
|
|
117
161
|
fullPage: opts.fullPage !== false,
|
|
118
162
|
});
|
|
163
|
+
// 保存截图(如果启用)
|
|
164
|
+
let screenshotPath;
|
|
165
|
+
if (config.saveScreenshots) {
|
|
166
|
+
screenshotPath = await saveScreenshot(screenshot, config.screenshotDir);
|
|
167
|
+
console.log(`[smart-test] 截图已保存: ${screenshotPath}`);
|
|
168
|
+
}
|
|
119
169
|
// 构建 AI 请求
|
|
120
170
|
const prompt = buildPrompt(opts.expected);
|
|
121
171
|
const openai$1 = new openai.OpenAI({
|
|
@@ -146,15 +196,18 @@ async function aiReviewScreenshot(page, options) {
|
|
|
146
196
|
// 解析 AI 响应
|
|
147
197
|
const content = completion?.choices[0]?.message?.content || '';
|
|
148
198
|
const result = parseAiResponse(content);
|
|
149
|
-
|
|
150
|
-
|
|
199
|
+
return {
|
|
200
|
+
...result,
|
|
201
|
+
screenshotPath,
|
|
202
|
+
rawResponse: content,
|
|
203
|
+
};
|
|
151
204
|
}
|
|
152
205
|
catch (error) {
|
|
153
206
|
console.error('[smart-test] AI 检查失败:', error);
|
|
154
207
|
return {
|
|
155
208
|
ok: true,
|
|
156
209
|
skipped: true,
|
|
157
|
-
reason: `
|
|
210
|
+
reason: `AI 检查失败: ${error instanceof Error ? error.message : String(error)}`,
|
|
158
211
|
};
|
|
159
212
|
}
|
|
160
213
|
}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 保存截图到文件
|
|
3
|
+
*
|
|
4
|
+
* @param screenshot - 截图 Buffer
|
|
5
|
+
* @param dir - 保存目录
|
|
6
|
+
* @param prefix - 文件名前缀
|
|
7
|
+
* @returns 截图文件的绝对路径
|
|
8
|
+
*/
|
|
9
|
+
export declare function saveScreenshot(screenshot: Buffer, dir: string, prefix?: string): Promise<string>;
|
|
1
10
|
/**
|
|
2
11
|
* 将截图转换为 base64 编码
|
|
3
12
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/utils/screenshot.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/utils/screenshot.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAanH;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE7D"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@be-link/smart-test",
|
|
3
|
-
"version": "1.0.1-beta.
|
|
4
|
-
"type": "module",
|
|
3
|
+
"version": "1.0.1-beta.8",
|
|
5
4
|
"description": "AI-powered visual testing for Playwright - 基于 AI 视觉模型的 Playwright 测试工具",
|
|
6
5
|
"homepage": "https://github.com/snowmountain-top/be-link",
|
|
7
6
|
"author": "shian",
|
|
@@ -9,9 +8,6 @@
|
|
|
9
8
|
"main": "dist/index.js",
|
|
10
9
|
"module": "dist/index.esm.js",
|
|
11
10
|
"types": "dist/index.d.ts",
|
|
12
|
-
"bin": {
|
|
13
|
-
"smart-test": "./bin/smart-test.js"
|
|
14
|
-
},
|
|
15
11
|
"exports": {
|
|
16
12
|
".": {
|
|
17
13
|
"types": "./dist/index.d.ts",
|
|
@@ -23,29 +19,16 @@
|
|
|
23
19
|
},
|
|
24
20
|
"files": [
|
|
25
21
|
"dist",
|
|
26
|
-
"bin",
|
|
27
|
-
"templates",
|
|
28
22
|
"README.md"
|
|
29
23
|
],
|
|
30
24
|
"dependencies": {
|
|
31
|
-
"
|
|
32
|
-
"chalk": "^5.3.0",
|
|
33
|
-
"commander": "^12.0.0",
|
|
34
|
-
"cosmiconfig": "^9.0.0",
|
|
35
|
-
"handlebars": "^4.7.8",
|
|
36
|
-
"inquirer": "^9.2.0",
|
|
37
|
-
"openai": "^6.15.0",
|
|
38
|
-
"ora": "^7.0.0",
|
|
39
|
-
"prettier": "^3.0.0",
|
|
40
|
-
"typescript": "^5.9.3"
|
|
25
|
+
"openai": "^6.15.0"
|
|
41
26
|
},
|
|
42
27
|
"peerDependencies": {
|
|
43
28
|
"@playwright/test": "^1.40.0"
|
|
44
29
|
},
|
|
45
30
|
"devDependencies": {
|
|
46
|
-
"@playwright/test": "^1.50.0"
|
|
47
|
-
"@types/inquirer": "^9.0.0",
|
|
48
|
-
"@types/node": "^20.0.0"
|
|
31
|
+
"@playwright/test": "^1.50.0"
|
|
49
32
|
},
|
|
50
33
|
"publishConfig": {
|
|
51
34
|
"access": "public"
|