@be-link/smart-test 1.0.1-beta.20 → 1.0.1-beta.21
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/dist/bin/smart-test.js +110 -82
- package/dist/cli/commands/gen.d.ts.map +1 -1
- package/dist/cli/commands/generate-testcase.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/core/config-loader.d.ts +1 -1
- package/dist/cli/core/config-loader.d.ts.map +1 -1
- package/dist/cli/templates/smart-test.config.template.ts +31 -0
- package/dist/cli/ui/interactive.d.ts.map +1 -1
- package/dist/index.esm.mjs +24 -19
- package/dist/index.js +23 -18
- package/dist/utils/web-server-manager.d.ts +6 -1
- package/dist/utils/web-server-manager.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/cli/templates/playwright.config.template.d.ts +0 -7
- package/dist/cli/templates/playwright.config.template.d.ts.map +0 -1
- package/dist/cli/templates/smart-test.config.template.json +0 -17
package/dist/bin/smart-test.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
var fs$4 = require('node:fs/promises');
|
|
5
5
|
var path = require('node:path');
|
|
6
|
-
var prompts = require('@inquirer/prompts');
|
|
7
6
|
var jiti = require('jiti');
|
|
7
|
+
var prompts = require('@inquirer/prompts');
|
|
8
8
|
require('node:child_process');
|
|
9
9
|
var openai = require('openai');
|
|
10
10
|
var test = require('@playwright/test');
|
|
@@ -135,29 +135,33 @@ async function loadLocalEnv(cwd) {
|
|
|
135
135
|
|
|
136
136
|
/**
|
|
137
137
|
* 查找并加载配置文件
|
|
138
|
-
* 支持 smart-test.config.
|
|
138
|
+
* 支持 smart-test.config.ts/js(优先级递减)
|
|
139
139
|
*/
|
|
140
140
|
async function loadConfig$1(cwd) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
141
|
+
const testsDir = path.resolve(cwd, 'tests');
|
|
142
|
+
// 按优先级查找配置文件:.ts > .js
|
|
143
|
+
const configFiles = [path.resolve(testsDir, 'smart-test.config.ts'), path.resolve(testsDir, 'smart-test.config.js')];
|
|
144
|
+
for (const configPath of configFiles) {
|
|
145
|
+
if (await fileExists$1(configPath)) {
|
|
146
|
+
const jiti$1 = jiti.createJiti(cwd, {
|
|
147
|
+
interopDefault: true, // 自动处理 default export
|
|
148
|
+
});
|
|
149
|
+
const config = jiti$1(configPath);
|
|
150
|
+
return config;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
throw new Error('未找到配置文件 smart-test.config.{ts,js}');
|
|
147
154
|
}
|
|
148
155
|
/**
|
|
149
|
-
*
|
|
156
|
+
* 检查文件是否存在
|
|
150
157
|
*/
|
|
151
|
-
function
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
else if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
159
|
-
replaceEnvVars(obj[key]);
|
|
160
|
-
}
|
|
158
|
+
async function fileExists$1(filePath) {
|
|
159
|
+
try {
|
|
160
|
+
await fs$4.access(filePath);
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return false;
|
|
161
165
|
}
|
|
162
166
|
}
|
|
163
167
|
|
|
@@ -231,6 +235,44 @@ async function extractMockFunctionName(mockFilePath) {
|
|
|
231
235
|
}
|
|
232
236
|
}
|
|
233
237
|
|
|
238
|
+
/**
|
|
239
|
+
* 校验开发服务器状态(用于 DOM 提取前的检查)
|
|
240
|
+
* @returns PlaywrightConfigInfo 如果校验成功,否则退出进程
|
|
241
|
+
*/
|
|
242
|
+
async function validateServerForDomExtraction(cwd) {
|
|
243
|
+
console.log('\n🔍 检测开发服务器状态...\n');
|
|
244
|
+
// 读取 Playwright 配置
|
|
245
|
+
const playwrightConfig = await loadPlaywrightConfig(cwd);
|
|
246
|
+
if (!playwrightConfig || !playwrightConfig.baseURL) {
|
|
247
|
+
console.error('❌ 未找到 Playwright 配置或 baseURL!');
|
|
248
|
+
console.log('\n💡 请确保项目中存在 playwright.config.ts/js 文件,');
|
|
249
|
+
console.log(' 并配置了 use.baseURL 字段\n');
|
|
250
|
+
process.exit(1);
|
|
251
|
+
}
|
|
252
|
+
// 检测服务器是否运行
|
|
253
|
+
const serverRunning = await isServerRunning(playwrightConfig.baseURL);
|
|
254
|
+
if (!serverRunning) {
|
|
255
|
+
console.log(`⚠️ 开发服务器未运行!`);
|
|
256
|
+
console.log(` URL: ${playwrightConfig.baseURL}`);
|
|
257
|
+
console.log(`\n💡 请启动开发服务器:`);
|
|
258
|
+
if (playwrightConfig.webServer?.command) {
|
|
259
|
+
console.log(` $ ${playwrightConfig.webServer.command}`);
|
|
260
|
+
}
|
|
261
|
+
console.log(`\n⏳ 等待服务器启动中(最长等待 120 秒)...\n`);
|
|
262
|
+
// 等待服务器启动,超时时间 120 秒
|
|
263
|
+
const isReady = await waitForServer(playwrightConfig.baseURL, 120000);
|
|
264
|
+
if (!isReady) {
|
|
265
|
+
console.error(`\n❌ 服务器启动超时!`);
|
|
266
|
+
console.log(` 请确保服务器正常启动后重新运行: smart-test gen\n`);
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
269
|
+
console.log(`✅ 服务器已启动成功!\n`);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
console.log(`✅ 开发服务器正在运行 (${playwrightConfig.baseURL})\n`);
|
|
273
|
+
}
|
|
274
|
+
return playwrightConfig;
|
|
275
|
+
}
|
|
234
276
|
/**
|
|
235
277
|
* 检查服务器是否可访问
|
|
236
278
|
*/
|
|
@@ -243,12 +285,30 @@ async function isServerRunning(url) {
|
|
|
243
285
|
return false;
|
|
244
286
|
}
|
|
245
287
|
}
|
|
288
|
+
/**
|
|
289
|
+
* 等待服务器启动
|
|
290
|
+
*/
|
|
291
|
+
async function waitForServer(url, timeout) {
|
|
292
|
+
const startTime = Date.now();
|
|
293
|
+
const checkInterval = 500; // 每 500ms 检查一次
|
|
294
|
+
while (Date.now() - startTime < timeout) {
|
|
295
|
+
if (await isServerRunning(url)) {
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
299
|
+
}
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
246
302
|
|
|
247
303
|
/**
|
|
248
304
|
* 启动交互式问答
|
|
249
305
|
*/
|
|
250
306
|
async function runInteractive(config, cwd) {
|
|
251
307
|
console.log('\n👋 欢迎使用 Smart Test Generator!\n');
|
|
308
|
+
if (!config?.ai?.apiKey) {
|
|
309
|
+
console.error('缺少必需的环境变量: apiKey;请在配置文件 (smart-test.config.json) 配置');
|
|
310
|
+
process.exit(1);
|
|
311
|
+
}
|
|
252
312
|
// 阶段 1: 选择模式
|
|
253
313
|
const mode = await selectMode();
|
|
254
314
|
// 阶段 2: 根据模式询问参数
|
|
@@ -350,36 +410,27 @@ async function askMockQuestions(config) {
|
|
|
350
410
|
*/
|
|
351
411
|
async function askTestCaseQuestions(config, cwd) {
|
|
352
412
|
console.log('\n📝 测试用例配置:\n');
|
|
353
|
-
//
|
|
413
|
+
// 访问页面URL
|
|
414
|
+
const pageUrl = await prompts.input({
|
|
415
|
+
message: '页面 URL 路径:',
|
|
416
|
+
validate: (value) => value.startsWith('/') || 'URL 应以 / 开头',
|
|
417
|
+
});
|
|
418
|
+
// 询问是否提取 DOM
|
|
354
419
|
const extractDom = await prompts.confirm({
|
|
355
420
|
message: '是否启动浏览器提取页面真实结构?(推荐,生成更精确的选择器)',
|
|
356
421
|
default: true,
|
|
357
422
|
});
|
|
358
|
-
let mockFilePath;
|
|
359
423
|
// 如果需要提取 DOM,立即检测服务器
|
|
360
424
|
if (extractDom) {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
// 检测服务器是否运行
|
|
371
|
-
const serverRunning = await isServerRunning(playwrightConfig.baseURL);
|
|
372
|
-
if (!serverRunning) {
|
|
373
|
-
console.error(`❌ 开发服务器未运行!`);
|
|
374
|
-
console.log(` URL: ${playwrightConfig.baseURL}`);
|
|
375
|
-
console.log(`\n💡 请先启动开发服务器:`);
|
|
376
|
-
if (playwrightConfig.webServer?.command) {
|
|
377
|
-
console.log(` $ ${playwrightConfig.webServer.command}`);
|
|
378
|
-
}
|
|
379
|
-
console.log(`\n 然后重新运行: smart-test gen\n`);
|
|
380
|
-
process.exit(1);
|
|
381
|
-
}
|
|
382
|
-
console.log(`✅ 开发服务器正在运行 (${playwrightConfig.baseURL})\n`);
|
|
425
|
+
// 使用公共校验方法
|
|
426
|
+
await validateServerForDomExtraction(cwd);
|
|
427
|
+
}
|
|
428
|
+
const loadMockFile = await prompts.confirm({
|
|
429
|
+
message: '是否加载 Mock 文件?',
|
|
430
|
+
default: true,
|
|
431
|
+
});
|
|
432
|
+
let mockFilePath;
|
|
433
|
+
if (loadMockFile) {
|
|
383
434
|
// 询问 mock 文件路径
|
|
384
435
|
mockFilePath = await prompts.input({
|
|
385
436
|
message: 'Mock 文件路径(相对于项目根目录,留空则不加载 Mock):',
|
|
@@ -390,11 +441,6 @@ async function askTestCaseQuestions(config, cwd) {
|
|
|
390
441
|
mockFilePath = undefined;
|
|
391
442
|
}
|
|
392
443
|
}
|
|
393
|
-
// 继续询问其他参数
|
|
394
|
-
const pageUrl = await prompts.input({
|
|
395
|
-
message: '页面 URL 路径:',
|
|
396
|
-
validate: (value) => value.startsWith('/') || 'URL 应以 / 开头',
|
|
397
|
-
});
|
|
398
444
|
const scenario = await prompts.input({
|
|
399
445
|
message: '测试场景描述:',
|
|
400
446
|
validate: (value) => value.length > 0 || '场景描述不能为空',
|
|
@@ -1221,22 +1267,8 @@ async function executeGenerateTestCase(interactiveResult, apiKey, cwd) {
|
|
|
1221
1267
|
console.log(` ✅ 配置加载成功`);
|
|
1222
1268
|
console.log(` 文件: ${playwrightConfig.configPath}`);
|
|
1223
1269
|
console.log(` 地址: ${playwrightConfig.baseURL}\n`);
|
|
1224
|
-
// 2.
|
|
1225
|
-
console.log('
|
|
1226
|
-
const serverRunning = await isServerRunning(playwrightConfig.baseURL);
|
|
1227
|
-
if (!serverRunning) {
|
|
1228
|
-
console.error(`\n ❌ 开发服务器未运行!`);
|
|
1229
|
-
console.log(` URL: ${playwrightConfig.baseURL}`);
|
|
1230
|
-
console.log(`\n 💡 请先启动开发服务器:`);
|
|
1231
|
-
if (playwrightConfig.webServer?.command) {
|
|
1232
|
-
console.log(` $ ${playwrightConfig.webServer.command}`);
|
|
1233
|
-
}
|
|
1234
|
-
console.log(`\n 然后重新运行: smart-test gen\n`);
|
|
1235
|
-
process.exit(1);
|
|
1236
|
-
}
|
|
1237
|
-
console.log(' ✅ 开发服务器正在运行\n');
|
|
1238
|
-
// 3. 处理 Mock 文件
|
|
1239
|
-
console.log(' 📦 [3/6] 准备 Mock 数据...');
|
|
1270
|
+
// 2. 处理 Mock 文件
|
|
1271
|
+
console.log(' 📦 [2/5] 准备 Mock 数据...');
|
|
1240
1272
|
let mockFile = null;
|
|
1241
1273
|
let mockFunctionName = null;
|
|
1242
1274
|
if (testcaseParams.mockFilePath) {
|
|
@@ -1264,8 +1296,8 @@ async function executeGenerateTestCase(interactiveResult, apiKey, cwd) {
|
|
|
1264
1296
|
else {
|
|
1265
1297
|
console.log(' ℹ️未提供 Mock 文件(页面可能需要真实数据)\n');
|
|
1266
1298
|
}
|
|
1267
|
-
//
|
|
1268
|
-
console.log(' 🌐 [
|
|
1299
|
+
// 3. 启动浏览器
|
|
1300
|
+
console.log(' 🌐 [3/5] 启动浏览器...');
|
|
1269
1301
|
const browser = await test.chromium.launch({ headless: true });
|
|
1270
1302
|
const context = await browser.newContext({
|
|
1271
1303
|
baseURL: playwrightConfig.baseURL,
|
|
@@ -1275,9 +1307,9 @@ async function executeGenerateTestCase(interactiveResult, apiKey, cwd) {
|
|
|
1275
1307
|
const page = await context.newPage();
|
|
1276
1308
|
console.log(' ✅浏览器已启动(无头模式)\n');
|
|
1277
1309
|
try {
|
|
1278
|
-
//
|
|
1310
|
+
// 4. 加载 Mock
|
|
1279
1311
|
if (mockFile && mockFunctionName) {
|
|
1280
|
-
console.log(' 🔄 [5
|
|
1312
|
+
console.log(' 🔄 [4/5] 应用 Mock 数据...');
|
|
1281
1313
|
try {
|
|
1282
1314
|
// 使用 jiti 加载 Mock 文件(支持 TypeScript)
|
|
1283
1315
|
const jiti$1 = jiti.createJiti(cwd, {
|
|
@@ -1299,11 +1331,11 @@ async function executeGenerateTestCase(interactiveResult, apiKey, cwd) {
|
|
|
1299
1331
|
}
|
|
1300
1332
|
}
|
|
1301
1333
|
else {
|
|
1302
|
-
console.log(' ⏭️[5
|
|
1334
|
+
console.log(' ⏭️[4/5] 跳过 Mock 数据应用\n');
|
|
1303
1335
|
}
|
|
1304
|
-
//
|
|
1336
|
+
// 5. 访问页面并提取 DOM
|
|
1305
1337
|
const fullUrl = `${playwrightConfig.baseURL}${testcaseParams.pageUrl}`;
|
|
1306
|
-
console.log(' 🔗 [
|
|
1338
|
+
console.log(' 🔗 [5/5] 访问页面并提取结构...');
|
|
1307
1339
|
console.log(` URL: ${fullUrl}`);
|
|
1308
1340
|
await page.goto(testcaseParams.pageUrl);
|
|
1309
1341
|
console.log(' ⏳ 等待页面加载完成...');
|
|
@@ -1389,11 +1421,7 @@ async function executeGenCommand(args) {
|
|
|
1389
1421
|
// 启动交互式模式
|
|
1390
1422
|
const interactiveResult = await runInteractive(fileConfig, cwd);
|
|
1391
1423
|
// 从配置文件或环境变量获取 API Key
|
|
1392
|
-
const apiKey = fileConfig.ai
|
|
1393
|
-
if (!apiKey) {
|
|
1394
|
-
console.error('缺少必需的环境变量: apiKey;请在配置文件 (smart-test.config.json) 配置');
|
|
1395
|
-
process.exit(1);
|
|
1396
|
-
}
|
|
1424
|
+
const apiKey = fileConfig.ai.apiKey;
|
|
1397
1425
|
// 配置 AI(使用配置文件中的设置或默认值)
|
|
1398
1426
|
configure({
|
|
1399
1427
|
apiKey,
|
|
@@ -1433,11 +1461,11 @@ function printGenHelp() {
|
|
|
1433
1461
|
`);
|
|
1434
1462
|
}
|
|
1435
1463
|
|
|
1436
|
-
const SMART_TEST_CONFIG_FILENAME = 'smart-test.config.
|
|
1464
|
+
const SMART_TEST_CONFIG_FILENAME = 'smart-test.config.ts';
|
|
1437
1465
|
const PLAYWRIGHT_CONFIG_FILENAME = 'playwright.config.ts';
|
|
1438
1466
|
/**
|
|
1439
1467
|
* 执行 init 命令:在项目中生成配置文件
|
|
1440
|
-
* - smart-test.config.
|
|
1468
|
+
* - smart-test.config.ts 在 tests 目录
|
|
1441
1469
|
* - playwright.config.ts 在项目根目录
|
|
1442
1470
|
*/
|
|
1443
1471
|
async function executeInitCommand() {
|
|
@@ -1446,7 +1474,7 @@ async function executeInitCommand() {
|
|
|
1446
1474
|
// 配置文件路径
|
|
1447
1475
|
const smartTestConfigPath = path.resolve(testsDir, SMART_TEST_CONFIG_FILENAME);
|
|
1448
1476
|
const playwrightConfigPath = path.resolve(cwd, PLAYWRIGHT_CONFIG_FILENAME);
|
|
1449
|
-
// 检查并处理 smart-test.config.
|
|
1477
|
+
// 检查并处理 smart-test.config.ts
|
|
1450
1478
|
const smartTestExists = await checkFileExists(smartTestConfigPath);
|
|
1451
1479
|
if (smartTestExists) {
|
|
1452
1480
|
const shouldOverwrite = await prompts.confirm({
|
|
@@ -1457,12 +1485,12 @@ async function executeInitCommand() {
|
|
|
1457
1485
|
console.log('已取消创建 smart-test 配置文件');
|
|
1458
1486
|
}
|
|
1459
1487
|
else {
|
|
1460
|
-
await createConfigFile('smart-test.config.template.
|
|
1488
|
+
await createConfigFile('smart-test.config.template.ts', smartTestConfigPath, testsDir);
|
|
1461
1489
|
console.log(`✅ 配置文件已创建: tests/${SMART_TEST_CONFIG_FILENAME}`);
|
|
1462
1490
|
}
|
|
1463
1491
|
}
|
|
1464
1492
|
else {
|
|
1465
|
-
await createConfigFile('smart-test.config.template.
|
|
1493
|
+
await createConfigFile('smart-test.config.template.ts', smartTestConfigPath, testsDir);
|
|
1466
1494
|
console.log(`✅ 配置文件已创建: tests/${SMART_TEST_CONFIG_FILENAME}`);
|
|
1467
1495
|
}
|
|
1468
1496
|
// 检查并处理 playwright.config.ts
|
|
@@ -1485,7 +1513,7 @@ async function executeInitCommand() {
|
|
|
1485
1513
|
console.log(`✅ 配置文件已创建: ${PLAYWRIGHT_CONFIG_FILENAME}`);
|
|
1486
1514
|
}
|
|
1487
1515
|
console.log('\n📝 接下来你可以:');
|
|
1488
|
-
console.log(' 1. 编辑 smart-test.config.
|
|
1516
|
+
console.log(' 1. 编辑 smart-test.config.ts,设置 AI API 密钥(推荐使用环境变量)');
|
|
1489
1517
|
console.log(' 2. 根据需要调整 playwright.config.ts 中的测试配置');
|
|
1490
1518
|
console.log(' 3. 运行 smart-test gen 命令时会自动读取配置\n');
|
|
1491
1519
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gen.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/gen.ts"],"names":[],"mappings":"AAOA,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"gen.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/gen.ts"],"names":[],"mappings":"AAOA,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuCrE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-testcase.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/generate-testcase.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"generate-testcase.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/generate-testcase.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAK3D;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,iBAAiB,EAAE,iBAAiB,EACpC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAsKf"}
|
|
@@ -63,7 +63,7 @@ export interface SmartTestConfig {
|
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
65
|
* 查找并加载配置文件
|
|
66
|
-
* 支持 smart-test.config.
|
|
66
|
+
* 支持 smart-test.config.ts/js(优先级递减)
|
|
67
67
|
*/
|
|
68
68
|
export declare function loadConfig(cwd: string): Promise<SmartTestConfig>;
|
|
69
69
|
//# sourceMappingURL=config-loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../../src/cli/core/config-loader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../../src/cli/core/config-loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,UAAU,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,EAAE,CAAC,EAAE,QAAQ,CAAC;IAEd;;OAEG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAElB;;OAEG;IACH,QAAQ,CAAC,EAAE,cAAc,CAAC;IAE1B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC;CACpD;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAiBtE"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import type { SmartTestConfig } from '@be-link/smart-test';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Smart Test 配置文件
|
|
6
|
+
*
|
|
7
|
+
* 💡 提示:
|
|
8
|
+
* 1. 可以使用 process.env 读取环境变量,避免硬编码敏感信息
|
|
9
|
+
* 2. 例如:apiKey: process.env.VITE_AI_API_KEY || ''
|
|
10
|
+
* 3. 此文件在用户项目中使用时,需要先安装 @be-link/smart-test 包
|
|
11
|
+
*/
|
|
12
|
+
const config: SmartTestConfig = {
|
|
13
|
+
ai: {
|
|
14
|
+
// 从环境变量读取 API Key(推荐)
|
|
15
|
+
// 例如:在 .env 文件中设置 VITE_AI_API_KEY=your_api_key
|
|
16
|
+
apiKey: process.env.VITE_AI_API_KEY || '',
|
|
17
|
+
baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
|
|
18
|
+
visionModel: 'qwen3-vl-plus',
|
|
19
|
+
codeModel: 'qwen3-coder-plus',
|
|
20
|
+
},
|
|
21
|
+
mock: {
|
|
22
|
+
mockDir: 'tests/mocks',
|
|
23
|
+
typeFile: '',
|
|
24
|
+
},
|
|
25
|
+
testCase: {
|
|
26
|
+
caseDir: 'tests/e2e',
|
|
27
|
+
mockDir: 'tests/mocks',
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default config;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../../src/cli/ui/interactive.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../../src/cli/ui/interactive.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG7E;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,CAAC,EAAE;QACL,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA0BrG"}
|
package/dist/index.esm.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { OpenAI } from 'openai';
|
|
2
|
-
import { readFile as readFile$1, mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { access, readFile as readFile$1, mkdir, writeFile } from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { createJiti } from 'jiti';
|
|
4
5
|
import { createRequire, builtinModules } from 'module';
|
|
5
6
|
import * as url from 'url';
|
|
6
7
|
import url__default, { fileURLToPath, pathToFileURL, URL as URL$1 } from 'url';
|
|
@@ -16,29 +17,33 @@ import { format, inspect } from 'util';
|
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* 查找并加载配置文件
|
|
19
|
-
* 支持 smart-test.config.
|
|
20
|
+
* 支持 smart-test.config.ts/js(优先级递减)
|
|
20
21
|
*/
|
|
21
22
|
async function loadConfig$1(cwd) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
const testsDir = path.resolve(cwd, 'tests');
|
|
24
|
+
// 按优先级查找配置文件:.ts > .js
|
|
25
|
+
const configFiles = [path.resolve(testsDir, 'smart-test.config.ts'), path.resolve(testsDir, 'smart-test.config.js')];
|
|
26
|
+
for (const configPath of configFiles) {
|
|
27
|
+
if (await fileExists$1(configPath)) {
|
|
28
|
+
const jiti = createJiti(cwd, {
|
|
29
|
+
interopDefault: true, // 自动处理 default export
|
|
30
|
+
});
|
|
31
|
+
const config = jiti(configPath);
|
|
32
|
+
return config;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
throw new Error('未找到配置文件 smart-test.config.{ts,js}');
|
|
28
36
|
}
|
|
29
37
|
/**
|
|
30
|
-
*
|
|
38
|
+
* 检查文件是否存在
|
|
31
39
|
*/
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
else if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
40
|
-
replaceEnvVars(obj[key]);
|
|
41
|
-
}
|
|
40
|
+
async function fileExists$1(filePath) {
|
|
41
|
+
try {
|
|
42
|
+
await access(filePath);
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return false;
|
|
42
47
|
}
|
|
43
48
|
}
|
|
44
49
|
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var openai = require('openai');
|
|
4
4
|
var promises = require('node:fs/promises');
|
|
5
5
|
var path = require('node:path');
|
|
6
|
+
var jiti = require('jiti');
|
|
6
7
|
var module$1 = require('module');
|
|
7
8
|
var url = require('url');
|
|
8
9
|
var path10 = require('path');
|
|
@@ -37,29 +38,33 @@ var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs$4);
|
|
|
37
38
|
|
|
38
39
|
/**
|
|
39
40
|
* 查找并加载配置文件
|
|
40
|
-
* 支持 smart-test.config.
|
|
41
|
+
* 支持 smart-test.config.ts/js(优先级递减)
|
|
41
42
|
*/
|
|
42
43
|
async function loadConfig$1(cwd) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
const testsDir = path.resolve(cwd, 'tests');
|
|
45
|
+
// 按优先级查找配置文件:.ts > .js
|
|
46
|
+
const configFiles = [path.resolve(testsDir, 'smart-test.config.ts'), path.resolve(testsDir, 'smart-test.config.js')];
|
|
47
|
+
for (const configPath of configFiles) {
|
|
48
|
+
if (await fileExists$1(configPath)) {
|
|
49
|
+
const jiti$1 = jiti.createJiti(cwd, {
|
|
50
|
+
interopDefault: true, // 自动处理 default export
|
|
51
|
+
});
|
|
52
|
+
const config = jiti$1(configPath);
|
|
53
|
+
return config;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
throw new Error('未找到配置文件 smart-test.config.{ts,js}');
|
|
49
57
|
}
|
|
50
58
|
/**
|
|
51
|
-
*
|
|
59
|
+
* 检查文件是否存在
|
|
52
60
|
*/
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
else if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
61
|
-
replaceEnvVars(obj[key]);
|
|
62
|
-
}
|
|
61
|
+
async function fileExists$1(filePath) {
|
|
62
|
+
try {
|
|
63
|
+
await promises.access(filePath);
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return false;
|
|
63
68
|
}
|
|
64
69
|
}
|
|
65
70
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { ChildProcess } from 'node:child_process';
|
|
2
|
-
import type { WebServerConfig } from './playwright-config-loader';
|
|
2
|
+
import type { WebServerConfig, PlaywrightConfigInfo } from './playwright-config-loader';
|
|
3
|
+
/**
|
|
4
|
+
* 校验开发服务器状态(用于 DOM 提取前的检查)
|
|
5
|
+
* @returns PlaywrightConfigInfo 如果校验成功,否则退出进程
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateServerForDomExtraction(cwd: string): Promise<PlaywrightConfigInfo>;
|
|
3
8
|
/**
|
|
4
9
|
* 检查服务器是否可访问
|
|
5
10
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-server-manager.d.ts","sourceRoot":"","sources":["../../src/utils/web-server-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"web-server-manager.d.ts","sourceRoot":"","sources":["../../src/utils/web-server-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAGxF;;;GAGG;AACH,wBAAsB,8BAA8B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAuC/F;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAYlF;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,eAAe,EACvB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAAE,CAAC,CAkDvE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,aAAa,EAAE,YAAY,GAAG,IAAI,GAAG,IAAI,CAMtE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@be-link/smart-test",
|
|
3
|
-
"version": "1.0.1-beta.
|
|
3
|
+
"version": "1.0.1-beta.21",
|
|
4
4
|
"description": "AI-powered visual testing for Playwright - 基于 AI 视觉模型的 Playwright 测试工具",
|
|
5
5
|
"homepage": "https://github.com/snowmountain-top/be-link",
|
|
6
6
|
"author": "shian",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"clean": "rimraf ./dist && rimraf .rollup.cache",
|
|
56
56
|
"build:js": "rollup --config rollup.config.ts --configPlugin typescript",
|
|
57
57
|
"build:types": "tsc --project tsconfig.json",
|
|
58
|
-
"build:copy-templates": "mkdir -p dist/cli/templates && cp src/cli/templates/*.
|
|
58
|
+
"build:copy-templates": "mkdir -p dist/cli/templates && cp src/cli/templates/*.ts dist/cli/templates/",
|
|
59
59
|
"build": "pnpm clean && pnpm build:js && pnpm build:types && pnpm build:copy-templates",
|
|
60
60
|
"lint": "eslint src --ext .ts --fix"
|
|
61
61
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"playwright.config.template.d.ts","sourceRoot":"","sources":["../../../src/cli/templates/playwright.config.template.ts"],"names":[],"mappings":"AAEA;;;GAGG;;AACH,wBAwCG"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"ai": {
|
|
3
|
-
"apiKey": "",
|
|
4
|
-
"baseURL": "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
|
5
|
-
"visionModel": "qwen3-vl-plus",
|
|
6
|
-
"codeModel": "qwen3-coder-plus"
|
|
7
|
-
},
|
|
8
|
-
"mock": {
|
|
9
|
-
"mockDir": "tests/mocks",
|
|
10
|
-
"typeFile": "",
|
|
11
|
-
"types": []
|
|
12
|
-
},
|
|
13
|
-
"testCase": {
|
|
14
|
-
"caseDir": "tests/e2e",
|
|
15
|
-
"mockDir": "tests/mocks"
|
|
16
|
-
}
|
|
17
|
-
}
|