@empiricalrun/test-gen 0.1.2 → 0.1.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/CHANGELOG.md +6 -0
- package/dist/bin/index.js +22 -32
- package/dist/bin/logger/index.d.ts +13 -0
- package/dist/bin/logger/index.d.ts.map +1 -0
- package/dist/bin/logger/index.js +19 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
package/dist/bin/index.js
CHANGED
|
@@ -13,9 +13,11 @@ const prettier_1 = __importDefault(require("prettier"));
|
|
|
13
13
|
const eslint_1 = require("eslint");
|
|
14
14
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
15
15
|
const yaml_1 = require("yaml");
|
|
16
|
+
const logger_1 = require("./logger");
|
|
16
17
|
dotenv_1.default.config({
|
|
17
18
|
path: [".env.local", ".env"],
|
|
18
19
|
});
|
|
20
|
+
const logger = new logger_1.CustomLogger();
|
|
19
21
|
async function readFilesInDirectory(dir = "") {
|
|
20
22
|
let files = [];
|
|
21
23
|
const items = await fs_extra_1.default.readdir(dir);
|
|
@@ -67,7 +69,6 @@ async function getLLMResult(instruction) {
|
|
|
67
69
|
],
|
|
68
70
|
model: "gpt-4o",
|
|
69
71
|
});
|
|
70
|
-
console.log("generated completion");
|
|
71
72
|
const response = completion.choices[0]?.message.content || "";
|
|
72
73
|
return response;
|
|
73
74
|
}
|
|
@@ -83,32 +84,24 @@ function validateTypescript(filePath) {
|
|
|
83
84
|
const errors = [];
|
|
84
85
|
const syntacticDiagnostics = program.getSyntacticDiagnostics(sourceFile);
|
|
85
86
|
if (syntacticDiagnostics.length > 0) {
|
|
86
|
-
console.log("Syntactic errors:");
|
|
87
87
|
syntacticDiagnostics.forEach((diagnostic) => {
|
|
88
88
|
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
89
89
|
const message = typescript_1.default.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
|
90
|
-
|
|
90
|
+
logger.log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
|
|
91
91
|
if (typeof diagnostic.messageText === "string") {
|
|
92
92
|
errors.push(diagnostic.messageText);
|
|
93
93
|
}
|
|
94
94
|
});
|
|
95
95
|
}
|
|
96
|
-
else {
|
|
97
|
-
console.log("No syntactic errors.");
|
|
98
|
-
}
|
|
99
96
|
// Get and report any semantic errors
|
|
100
97
|
const semanticDiagnostics = program.getSemanticDiagnostics(sourceFile);
|
|
101
98
|
if (semanticDiagnostics.length > 0) {
|
|
102
|
-
console.log("Semantic errors:");
|
|
103
99
|
semanticDiagnostics.forEach((diagnostic) => {
|
|
104
|
-
|
|
105
|
-
if (typeof diagnostic.messageText == "string") {
|
|
106
|
-
errors.push(diagnostic.messageText);
|
|
107
|
-
}
|
|
100
|
+
errors.push(diagnostic.messageText.toString());
|
|
108
101
|
});
|
|
109
102
|
}
|
|
110
|
-
|
|
111
|
-
|
|
103
|
+
if (!errors.length) {
|
|
104
|
+
logger.success("Found no type issues!");
|
|
112
105
|
}
|
|
113
106
|
return errors;
|
|
114
107
|
}
|
|
@@ -120,7 +113,7 @@ async function formatCode(filePath) {
|
|
|
120
113
|
filepath: filePath,
|
|
121
114
|
});
|
|
122
115
|
fs_extra_1.default.writeFileSync(filePath, formattedContent);
|
|
123
|
-
|
|
116
|
+
logger.success("File formatted successfully!");
|
|
124
117
|
}
|
|
125
118
|
async function stripAndPrependImports(content) {
|
|
126
119
|
const imports = content.match(/import.* from.*;/g);
|
|
@@ -141,12 +134,12 @@ async function generateTest(scenarios, file) {
|
|
|
141
134
|
const pomPrompt = await generatePromptFromDirectory("./pages");
|
|
142
135
|
const testFileContent = fs_extra_1.default.readFileSync(file, "utf-8");
|
|
143
136
|
for (const i in scenarios) {
|
|
137
|
+
console.log("\n\n");
|
|
144
138
|
const scenario = scenarios[i];
|
|
145
|
-
|
|
139
|
+
logger.log("Generating test for scenario:", scenario?.name);
|
|
146
140
|
//TODO: improve this logic. its buggy
|
|
147
141
|
if (testFileContent.includes(`test("${scenario?.name}"`)) {
|
|
148
|
-
|
|
149
|
-
console.log("skipping test generation");
|
|
142
|
+
logger.success("Test already exists for this scenario");
|
|
150
143
|
continue;
|
|
151
144
|
}
|
|
152
145
|
const instruction = `
|
|
@@ -183,25 +176,27 @@ async function generateTest(scenarios, file) {
|
|
|
183
176
|
- Donot repeat steps which are already mentioned in the "test.beforeEach" block
|
|
184
177
|
- Add import statements at the beginning of the output.
|
|
185
178
|
`;
|
|
186
|
-
console.log("constructed instruction for llm");
|
|
187
179
|
let response = await getLLMResult(instruction);
|
|
180
|
+
logger.success("Test generated successfully!");
|
|
188
181
|
const contents = fs_extra_1.default.readFileSync(file, "utf-8");
|
|
189
182
|
const [prependContent, strippedContent] = await stripAndPrependImports(response);
|
|
190
183
|
await fs_extra_1.default.writeFile(file, prependContent + contents + `\n\n${strippedContent}`, "utf-8");
|
|
191
|
-
|
|
184
|
+
logger.log("Linting generated code...");
|
|
192
185
|
await lintErrors(file);
|
|
193
|
-
|
|
186
|
+
logger.log("Validating types...");
|
|
194
187
|
let errors = validateTypescript(file);
|
|
195
188
|
const maxIteration = 2;
|
|
196
189
|
let counter = 0;
|
|
197
190
|
while (errors.length > 0) {
|
|
198
|
-
console.log(errors);
|
|
199
191
|
const fileContent = fs_extra_1.default.readFileSync(file, "utf-8");
|
|
200
192
|
counter += 1;
|
|
201
193
|
if (counter > maxIteration) {
|
|
202
|
-
|
|
194
|
+
logger.error(`Unable to fix typescript errors. Please review ${file} manually and fix the typescript errors. Run the test-gen command again, once errors are fixed`);
|
|
203
195
|
break;
|
|
204
196
|
}
|
|
197
|
+
logger.warn("Found few errors while validating types:");
|
|
198
|
+
errors.forEach(e => logger.warn(e));
|
|
199
|
+
logger.log("Trying to fix above errors...");
|
|
205
200
|
const instruction = `
|
|
206
201
|
You are a software engineer who is given a task to create test basis a scenario provided to you.
|
|
207
202
|
You will be provided with current tests, fixtures and page object models for you to use and write test.
|
|
@@ -230,18 +225,16 @@ async function generateTest(scenarios, file) {
|
|
|
230
225
|
- Donot modify anything else apart from the code required to fix typescript error
|
|
231
226
|
`;
|
|
232
227
|
response = await getLLMResult(instruction);
|
|
233
|
-
console.log("fixed");
|
|
234
|
-
console.log(response);
|
|
235
|
-
errors = validateTypescript(file);
|
|
236
228
|
await fs_extra_1.default.writeFile(file, response, "utf-8");
|
|
229
|
+
await lintErrors(file);
|
|
230
|
+
errors = validateTypescript(file);
|
|
237
231
|
}
|
|
238
|
-
console.log("formatting spec file");
|
|
239
232
|
await formatCode(file);
|
|
240
233
|
}
|
|
241
234
|
}
|
|
242
235
|
(async function main() {
|
|
243
236
|
if (process.argv.length != 3) {
|
|
244
|
-
|
|
237
|
+
logger.error("Please provide path to scenarios using command:", "npx @empiricalrun/test-gen <SCENARIOS_FILE_PATH>");
|
|
245
238
|
process.exit(1);
|
|
246
239
|
}
|
|
247
240
|
else {
|
|
@@ -252,11 +245,8 @@ async function generateTest(scenarios, file) {
|
|
|
252
245
|
const scenarios = config.scenarios;
|
|
253
246
|
const fileDir = config.dir || "./tests";
|
|
254
247
|
const filePath = `${fileDir}/${fileName}.spec.ts`;
|
|
255
|
-
if (fs_extra_1.default.existsSync(filePath)) {
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
else {
|
|
259
|
-
console.log("Spec file does not exist, creating new spec file");
|
|
248
|
+
if (!fs_extra_1.default.existsSync(filePath)) {
|
|
249
|
+
logger.log(`Creating a new spec file: ${filePath}`);
|
|
260
250
|
fs_extra_1.default.createFileSync(filePath);
|
|
261
251
|
}
|
|
262
252
|
await generateTest(scenarios, filePath);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface Logger {
|
|
2
|
+
log: (message?: string, ...optionalParams: any[]) => void;
|
|
3
|
+
warn: (message?: string, ...optionalParams: any[]) => void;
|
|
4
|
+
error: (message?: string, ...optionalParams: any[]) => void;
|
|
5
|
+
success: (message?: string, ...optionalParams: any[]) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare class CustomLogger implements Logger {
|
|
8
|
+
log(message?: string, ...optionalParams: any[]): void;
|
|
9
|
+
warn(message?: string, ...optionalParams: any[]): void;
|
|
10
|
+
success(message?: string, ...optionalParams: any[]): void;
|
|
11
|
+
error(message?: string, ...optionalParams: any[]): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bin/logger/index.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC1D,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC3D,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC5D,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;CAC/D;AAED,qBAAa,YAAa,YAAW,MAAM;IACzC,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,EAAE;IAI9C,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,EAAE;IAI/C,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,EAAE;IAIlD,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,EAAE;CAGjD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CustomLogger = void 0;
|
|
4
|
+
const picocolors_1 = require("picocolors");
|
|
5
|
+
class CustomLogger {
|
|
6
|
+
log(message, ...optionalParams) {
|
|
7
|
+
console.log("🪵 ", (0, picocolors_1.cyan)(message), ...optionalParams);
|
|
8
|
+
}
|
|
9
|
+
warn(message, ...optionalParams) {
|
|
10
|
+
console.log("🟡 ", (0, picocolors_1.yellow)(message), ...optionalParams);
|
|
11
|
+
}
|
|
12
|
+
success(message, ...optionalParams) {
|
|
13
|
+
console.log("✅", (0, picocolors_1.green)(message), ...optionalParams);
|
|
14
|
+
}
|
|
15
|
+
error(message, ...optionalParams) {
|
|
16
|
+
console.log("🚨", (0, picocolors_1.red)(message), ...optionalParams);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.CustomLogger = CustomLogger;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empiricalrun/test-gen",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"eslint": "^8.57.0",
|
|
20
20
|
"fs-extra": "^11.2.0",
|
|
21
21
|
"openai": "^4.47.2",
|
|
22
|
+
"picocolors": "^1.0.1",
|
|
22
23
|
"prettier": "^3.2.5",
|
|
23
24
|
"typescript": "^5.3.3",
|
|
24
25
|
"yaml": "^2.4.2"
|