qat-cli 0.3.2 → 0.3.3
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 +1 -1
- package/dist/cli.js +85 -12
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +80 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +128 -120
- package/dist/index.d.ts +128 -120
- package/dist/index.js +80 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
**Quick Auto Testing — 面向 Vue 项目,集成 Vitest & Playwright,AI 驱动覆盖测试全流程**
|
|
6
6
|
|
|
7
|
-
[](https://www.npmjs.com/package/qat-cli)
|
|
8
8
|
[](https://nodejs.org/)
|
|
9
9
|
[](https://opensource.org/licenses/MIT)
|
|
10
10
|
[](https://www.typescriptlang.org/)
|
package/dist/cli.js
CHANGED
|
@@ -1017,8 +1017,13 @@ ${error.actual ? `\u5B9E\u9645\u503C: ${error.actual}` : ""}`;
|
|
|
1017
1017
|
6. \u5982\u679C\u6709 props/emits \u4FE1\u606F\uFF0C\u52A1\u5FC5\u9488\u5BF9\u6BCF\u4E2A prop \u548C emit \u751F\u6210\u6D4B\u8BD5`;
|
|
1018
1018
|
}
|
|
1019
1019
|
buildGenerateTestUserPrompt(req) {
|
|
1020
|
+
const importPath = this.computeTestImportPath(req.type, req.target);
|
|
1020
1021
|
let prompt = `\u8BF7\u4E3A\u4EE5\u4E0B\u6587\u4EF6\u751F\u6210${req.type}\u6D4B\u8BD5\u4EE3\u7801:
|
|
1021
1022
|
\u76EE\u6807\u6587\u4EF6: ${req.target}
|
|
1023
|
+
\u6D4B\u8BD5\u6587\u4EF6\u5C06\u653E\u5728: ${this.getTestOutputDir(req.type)}/
|
|
1024
|
+
\u6B63\u786E\u7684 import \u8DEF\u5F84: ${importPath}
|
|
1025
|
+
|
|
1026
|
+
\u91CD\u8981\uFF1Aimport \u8BED\u53E5\u4E2D\u5FC5\u987B\u4F7F\u7528\u4E0A\u8FF0\u6B63\u786E\u7684\u76F8\u5BF9\u8DEF\u5F84 ${importPath}\uFF0C\u4E0D\u8981\u4F7F\u7528 ${req.target} \u6216\u5176\u4ED6\u8DEF\u5F84\uFF01
|
|
1022
1027
|
`;
|
|
1023
1028
|
if (req.analysis) {
|
|
1024
1029
|
prompt += "\n\u6E90\u7801\u5206\u6790\u7ED3\u679C:\n";
|
|
@@ -1068,6 +1073,46 @@ ${req.context}
|
|
|
1068
1073
|
}
|
|
1069
1074
|
return prompt;
|
|
1070
1075
|
}
|
|
1076
|
+
/**
|
|
1077
|
+
* 根据测试类型和源文件路径,计算从测试文件到源文件的正确相对导入路径
|
|
1078
|
+
*/
|
|
1079
|
+
computeTestImportPath(testType, targetPath) {
|
|
1080
|
+
if (!targetPath) return targetPath;
|
|
1081
|
+
const testDirMap = {
|
|
1082
|
+
unit: "tests/unit",
|
|
1083
|
+
component: "tests/component",
|
|
1084
|
+
e2e: "tests/e2e",
|
|
1085
|
+
api: "tests/api",
|
|
1086
|
+
visual: "tests/visual",
|
|
1087
|
+
performance: "tests/e2e"
|
|
1088
|
+
};
|
|
1089
|
+
const testDir = testDirMap[testType];
|
|
1090
|
+
if (!testDir) return targetPath;
|
|
1091
|
+
if (targetPath.startsWith("../") || targetPath.startsWith("./../")) {
|
|
1092
|
+
return targetPath;
|
|
1093
|
+
}
|
|
1094
|
+
const depth = testDir.split("/").length;
|
|
1095
|
+
const prefix = "../".repeat(depth);
|
|
1096
|
+
let cleanPath = targetPath.replace(/^\.\//, "");
|
|
1097
|
+
if (!cleanPath.endsWith(".vue")) {
|
|
1098
|
+
cleanPath = cleanPath.replace(/\.(ts|js|tsx|jsx)$/, "");
|
|
1099
|
+
}
|
|
1100
|
+
return `${prefix}${cleanPath}`;
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* 获取测试输出目录
|
|
1104
|
+
*/
|
|
1105
|
+
getTestOutputDir(testType) {
|
|
1106
|
+
const dirMap = {
|
|
1107
|
+
unit: "tests/unit",
|
|
1108
|
+
component: "tests/component",
|
|
1109
|
+
e2e: "tests/e2e",
|
|
1110
|
+
api: "tests/api",
|
|
1111
|
+
visual: "tests/visual",
|
|
1112
|
+
performance: "tests/e2e"
|
|
1113
|
+
};
|
|
1114
|
+
return dirMap[testType] || "tests/unit";
|
|
1115
|
+
}
|
|
1071
1116
|
parseGenerateTestResponse(content) {
|
|
1072
1117
|
const codeBlockMatch = content.match(/```(?:typescript|ts|javascript|js)?\s*\n([\s\S]*?)```/);
|
|
1073
1118
|
const code = codeBlockMatch ? codeBlockMatch[1].trim() : content.replace(/^(?:```[\s\S]*?\n)?/, "").replace(/\n?```$/, "").trim();
|
|
@@ -1096,10 +1141,12 @@ ISSUES: \u95EE\u9898\u5217\u8868\uFF08\u6BCF\u884C\u4E00\u4E2A\uFF0C\u683C\u5F0F
|
|
|
1096
1141
|
SUGGESTIONS: \u6539\u8FDB\u5EFA\u8BAE\u5217\u8868\uFF08\u6BCF\u884C\u4E00\u4E2A\uFF0C\u683C\u5F0F "- \u5EFA\u8BAE\u63CF\u8FF0"\uFF09`;
|
|
1097
1142
|
}
|
|
1098
1143
|
buildReviewTestUserPrompt(req) {
|
|
1144
|
+
const importPath = this.computeTestImportPath(req.testType, req.target);
|
|
1099
1145
|
let prompt = `\u8BF7\u5BA1\u67E5\u4EE5\u4E0B\u6D4B\u8BD5\u7528\u4F8B\u662F\u5426\u4E0E\u6E90\u7801\u8D34\u5207\u4E14\u51C6\u786E\u3002
|
|
1100
1146
|
|
|
1101
1147
|
\u88AB\u6D4B\u6587\u4EF6: ${req.target}
|
|
1102
1148
|
\u6D4B\u8BD5\u7C7B\u578B: ${req.testType}
|
|
1149
|
+
\u6B63\u786E\u7684 import \u8DEF\u5F84\u5E94\u4E3A: ${importPath}\uFF08\u6D4B\u8BD5\u6587\u4EF6\u4F4D\u4E8E ${this.getTestOutputDir(req.testType)}/\uFF09
|
|
1103
1150
|
|
|
1104
1151
|
--- \u6E90\u7801\u5185\u5BB9 ---
|
|
1105
1152
|
\`\`\`typescript
|
|
@@ -2082,9 +2129,33 @@ Handlebars.registerHelper("propTestValue", (prop) => {
|
|
|
2082
2129
|
};
|
|
2083
2130
|
return map[prop.type] || "'test-value'";
|
|
2084
2131
|
});
|
|
2132
|
+
function resolveImportPath(testType, targetPath) {
|
|
2133
|
+
if (!targetPath) return targetPath;
|
|
2134
|
+
const testDirMap = {
|
|
2135
|
+
unit: "tests/unit",
|
|
2136
|
+
component: "tests/component",
|
|
2137
|
+
e2e: "tests/e2e",
|
|
2138
|
+
api: "tests/api",
|
|
2139
|
+
visual: "tests/visual",
|
|
2140
|
+
performance: "tests/e2e"
|
|
2141
|
+
};
|
|
2142
|
+
const testDir = testDirMap[testType];
|
|
2143
|
+
if (!testDir) return targetPath;
|
|
2144
|
+
if (targetPath.startsWith("../") || targetPath.startsWith("./../")) {
|
|
2145
|
+
return targetPath;
|
|
2146
|
+
}
|
|
2147
|
+
const depth = testDir.split("/").length;
|
|
2148
|
+
const prefix = "../".repeat(depth);
|
|
2149
|
+
let cleanPath = targetPath.replace(/^\.\//, "");
|
|
2150
|
+
if (!cleanPath.endsWith(".vue")) {
|
|
2151
|
+
cleanPath = cleanPath.replace(/\.(ts|js|tsx|jsx)$/, "");
|
|
2152
|
+
}
|
|
2153
|
+
return `${prefix}${cleanPath}`;
|
|
2154
|
+
}
|
|
2085
2155
|
function renderTemplate(type, context) {
|
|
2086
2156
|
const templateContent = loadTemplate(type);
|
|
2087
2157
|
const template = Handlebars.compile(templateContent);
|
|
2158
|
+
const resolvedTarget = resolveImportPath(type, context.target);
|
|
2088
2159
|
const fullContext = {
|
|
2089
2160
|
vueVersion: 3,
|
|
2090
2161
|
typescript: true,
|
|
@@ -2105,6 +2176,8 @@ function renderTemplate(type, context) {
|
|
|
2105
2176
|
requiredProps: [],
|
|
2106
2177
|
optionalProps: [],
|
|
2107
2178
|
...context,
|
|
2179
|
+
// 使用计算后的正确路径
|
|
2180
|
+
target: resolvedTarget,
|
|
2108
2181
|
framework: context.framework || "vue",
|
|
2109
2182
|
camelName: context.camelName || toCamelCase(context.name),
|
|
2110
2183
|
pascalName: context.pascalName || toPascalCase(context.name)
|
|
@@ -2959,14 +3032,14 @@ function buildVitestArgs(options) {
|
|
|
2959
3032
|
if (options.files && options.files.length > 0) {
|
|
2960
3033
|
args.push(...options.files);
|
|
2961
3034
|
} else {
|
|
2962
|
-
const
|
|
2963
|
-
unit:
|
|
2964
|
-
component:
|
|
2965
|
-
api:
|
|
3035
|
+
const pathMap = {
|
|
3036
|
+
unit: "tests/unit/**/*.test.ts",
|
|
3037
|
+
component: "tests/component/**/*.test.ts",
|
|
3038
|
+
api: "tests/api/**/*.test.ts"
|
|
2966
3039
|
};
|
|
2967
|
-
const
|
|
2968
|
-
if (
|
|
2969
|
-
args.push(
|
|
3040
|
+
const testPattern = pathMap[options.type];
|
|
3041
|
+
if (testPattern) {
|
|
3042
|
+
args.push(testPattern);
|
|
2970
3043
|
}
|
|
2971
3044
|
}
|
|
2972
3045
|
if (options.coverage) {
|
|
@@ -3990,7 +4063,7 @@ function registerRunCommand(program2) {
|
|
|
3990
4063
|
});
|
|
3991
4064
|
}
|
|
3992
4065
|
async function executeRun(options) {
|
|
3993
|
-
const { type, file,
|
|
4066
|
+
const { type, file, watch, parallel } = options;
|
|
3994
4067
|
const config = await loadConfig(options.config);
|
|
3995
4068
|
const globalAI = loadGlobalAIConfig();
|
|
3996
4069
|
if (globalAI) {
|
|
@@ -4192,7 +4265,7 @@ function printDryRunCommands(types, options, config) {
|
|
|
4192
4265
|
api: "tests/api"
|
|
4193
4266
|
};
|
|
4194
4267
|
const dir = dirMap[testType];
|
|
4195
|
-
if (dir) cmd += `
|
|
4268
|
+
if (dir) cmd += ` '${dir}/**/*.test.ts'`;
|
|
4196
4269
|
if (config.vitest.coverage) cmd += " --coverage";
|
|
4197
4270
|
}
|
|
4198
4271
|
break;
|
|
@@ -4306,7 +4379,7 @@ async function runTestType(testType, config, options) {
|
|
|
4306
4379
|
throw new Error(`\u672A\u77E5\u7684\u8FD0\u884C\u5668: ${runner}`);
|
|
4307
4380
|
}
|
|
4308
4381
|
}
|
|
4309
|
-
async function runWatchMode(
|
|
4382
|
+
async function runWatchMode(_config, options) {
|
|
4310
4383
|
console.log(chalk5.cyan(" \u76D1\u542C\u6A21\u5F0F\u5DF2\u542F\u52A8 (Ctrl+C \u9000\u51FA)\n"));
|
|
4311
4384
|
const { spawn } = await import("child_process");
|
|
4312
4385
|
const args = ["vitest", "--watch"];
|
|
@@ -4322,7 +4395,7 @@ async function runWatchMode(config, options) {
|
|
|
4322
4395
|
};
|
|
4323
4396
|
const dirs = types.map((t) => dirMap[t]).filter(Boolean);
|
|
4324
4397
|
if (dirs.length > 0) {
|
|
4325
|
-
args.push(
|
|
4398
|
+
args.push(...dirs.map((d) => `${d}/**/*.test.ts`));
|
|
4326
4399
|
}
|
|
4327
4400
|
}
|
|
4328
4401
|
const child = spawn("npx", args, {
|
|
@@ -5660,7 +5733,7 @@ async function executeChange(_options) {
|
|
|
5660
5733
|
}
|
|
5661
5734
|
|
|
5662
5735
|
// src/cli.ts
|
|
5663
|
-
var VERSION = "0.3.
|
|
5736
|
+
var VERSION = "0.3.03";
|
|
5664
5737
|
function printLogo() {
|
|
5665
5738
|
const logo = `
|
|
5666
5739
|
${chalk12.bold.cyan(" ___ _ _ _ _ _____ _ _ ")}
|