@empiricalrun/test-gen 0.38.36 → 0.38.38
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 +15 -0
- package/dist/agent/codegen/create-test-block.d.ts.map +1 -1
- package/dist/agent/codegen/create-test-block.js +0 -1
- package/dist/agent/codegen/repo-edit.d.ts +6 -0
- package/dist/agent/codegen/repo-edit.d.ts.map +1 -0
- package/dist/agent/codegen/repo-edit.js +169 -0
- package/dist/agent/codegen/run.js +1 -1
- package/dist/agent/codegen/update-flow.d.ts +1 -4
- package/dist/agent/codegen/update-flow.d.ts.map +1 -1
- package/dist/agent/codegen/update-flow.js +5 -93
- package/dist/agent/codegen/utils.d.ts +21 -0
- package/dist/agent/codegen/utils.d.ts.map +1 -1
- package/dist/agent/codegen/utils.js +104 -1
- package/dist/bin/index.js +20 -12
- package/dist/bin/utils/context.d.ts +3 -0
- package/dist/bin/utils/context.d.ts.map +1 -1
- package/dist/bin/utils/context.js +15 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/reporter/index.d.ts +0 -2
- package/dist/reporter/index.d.ts.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @empiricalrun/test-gen
|
|
2
2
|
|
|
3
|
+
## 0.38.38
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- ea74baf: feat: add support for repo editor agent
|
|
8
|
+
- Updated dependencies [ea74baf]
|
|
9
|
+
- @empiricalrun/reporter@0.21.5
|
|
10
|
+
|
|
11
|
+
## 0.38.37
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- e9daf03: chore: log line when update flow output is dropped
|
|
16
|
+
- a552a6e: fix: convert trace url into hyperlink for coding agent
|
|
17
|
+
|
|
3
18
|
## 0.38.36
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-test-block.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/create-test-block.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAY3B,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAE7D,wBAAsB,wBAAwB,CAAC,EAC7C,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,KAAK,GACN,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,+
|
|
1
|
+
{"version":3,"file":"create-test-block.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/create-test-block.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAY3B,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAE7D,wBAAsB,wBAAwB,CAAC,EAC7C,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,KAAK,GACN,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,+BAyDA"}
|
|
@@ -57,7 +57,6 @@ async function createEmptyTestCaseBlock({ testCase, file, options, trace, }) {
|
|
|
57
57
|
scenarioName: testCase.name,
|
|
58
58
|
content: response,
|
|
59
59
|
});
|
|
60
|
-
console.log(`trace: ${trace?.getTraceUrl()}`);
|
|
61
60
|
return testBlock;
|
|
62
61
|
}
|
|
63
62
|
exports.createEmptyTestCaseBlock = createEmptyTestCaseBlock;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo-edit.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/repo-edit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAiBrE,wBAAsB,aAAa,CAAC,EAClC,KAAK,EACL,IAAI,GACL,EAAE;IACD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,iBA4IA"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.repoEditAgent = void 0;
|
|
30
|
+
const llm_1 = require("@empiricalrun/llm");
|
|
31
|
+
const fsSync = __importStar(require("fs"));
|
|
32
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
33
|
+
const path_1 = require("path");
|
|
34
|
+
const context_1 = require("../../bin/utils/context");
|
|
35
|
+
const web_1 = require("../../bin/utils/platform/web");
|
|
36
|
+
const constants_1 = require("../../constants");
|
|
37
|
+
const reporter_1 = require("../../reporter");
|
|
38
|
+
const utils_1 = require("./utils");
|
|
39
|
+
async function repoEditAgent({ trace, task, }) {
|
|
40
|
+
const testgenUpdatesReporter = new reporter_1.TestGenUpdatesReporter();
|
|
41
|
+
void testgenUpdatesReporter.sendMessage(`Updating test code as per the task. \n View [trace](${trace?.getTraceUrl()})`);
|
|
42
|
+
const repoEditSpan = trace?.span({
|
|
43
|
+
name: "repo-edit",
|
|
44
|
+
input: { task },
|
|
45
|
+
});
|
|
46
|
+
// TODO: add support for playwright config and other files
|
|
47
|
+
const { prompt: repoPrompt } = await (0, context_1.generateTxtForRepository)();
|
|
48
|
+
const prompt = [
|
|
49
|
+
{
|
|
50
|
+
role: "system",
|
|
51
|
+
content: `
|
|
52
|
+
You are a software test engineer who is given a task to update code in a Playwright repository.
|
|
53
|
+
You will be provided with current test files, fixtures and page object models for you to use and update code as per the task provided to you.
|
|
54
|
+
You need to respond with file path and updated code block inside the file.
|
|
55
|
+
|
|
56
|
+
Directory structure for the repository:
|
|
57
|
+
└── /
|
|
58
|
+
├── tests/
|
|
59
|
+
├── test-data/
|
|
60
|
+
│ └── index.ts
|
|
61
|
+
├── pages/
|
|
62
|
+
├── playwright.config.ts
|
|
63
|
+
├── app.md
|
|
64
|
+
├── .eslintrc.js
|
|
65
|
+
├── package.json
|
|
66
|
+
└── tsconfig.json
|
|
67
|
+
|
|
68
|
+
Explanation of repository structure:
|
|
69
|
+
- tests: this is a directory where all tests and fixtures are kept. all spec files here end with ".spec.ts" as naming convention. There is an expection for Playwright fixtures file. Fixtures file is named as "fixtures.ts"
|
|
70
|
+
- test-data: this is a directory where all the test data are kept.
|
|
71
|
+
- pages: this is a directory where all page object models are kept. the page object models are written in a pure functional convention. this is also a directory where all the utility methods are kept which can be executed independent of the Playwright tests.
|
|
72
|
+
|
|
73
|
+
Coding principles and guidelines:
|
|
74
|
+
|
|
75
|
+
## Code Style and Structure
|
|
76
|
+
- Write concise, maintainable, and technically accurate TypeScript code with relevant examples.
|
|
77
|
+
- Use functional and declarative programming patterns; avoid classes.
|
|
78
|
+
- Use types to describe the shape of data and the behavior of functions.
|
|
79
|
+
- Favour iteration and modularisation to adhere to DRY principles and avoid code duplication.
|
|
80
|
+
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
|
|
81
|
+
- Organise files systematically: each file should contain only related content, such as exported components, subcomponents, helpers, static content, and types.
|
|
82
|
+
- Page object models are pure functions and are stateless.
|
|
83
|
+
|
|
84
|
+
## Naming Conventions
|
|
85
|
+
- Use lowercase with dashes for directories (e.g., components/auth-wizard).
|
|
86
|
+
- Favour named exports for functions.
|
|
87
|
+
|
|
88
|
+
## TypeScript Usage
|
|
89
|
+
- Use TypeScript for all code; prefer interfaces over types for their extendability and ability to merge.
|
|
90
|
+
- Avoid enums; use maps instead for better type safety and flexibility.
|
|
91
|
+
- Use functional components with TypeScript interfaces.
|
|
92
|
+
|
|
93
|
+
## Syntax and Formatting
|
|
94
|
+
- Use the "function" keyword for pure functions to benefit from hoisting and clarity.
|
|
95
|
+
|
|
96
|
+
Here is the list of files:
|
|
97
|
+
${repoPrompt}
|
|
98
|
+
`,
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
role: "user",
|
|
102
|
+
content: `
|
|
103
|
+
Task: ${task}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
Follow these instructions before responding with output:
|
|
107
|
+
- Read the code line by line and ensure that achieve the task provided to you
|
|
108
|
+
- Read the dependencies of the code block by scanning through file paths and file provided to you. refer the same file path while responding with output.
|
|
109
|
+
- Focus only on the test case provided and associated JS methods called from the test case.
|
|
110
|
+
- Since the response will be used to search and replace blocks, always respond with output which includes the full lexical scope surrounding the modified code.
|
|
111
|
+
- If there are any updates inside test code block, ensure responding with full test block with unchanged code as well
|
|
112
|
+
- Each code block should contain edits to only one code block in file path
|
|
113
|
+
- DO NOT respond with any backticks or markdown syntax
|
|
114
|
+
- Respond only with file path where the code block to be updated is present, old code block, new code block and a one liner reason for the change
|
|
115
|
+
- Respond with <file_path></file_path>, <old_code_block></old_code_block>, <new_code_block></new_code_block> and <change></change> as xml tags
|
|
116
|
+
- The reason for change should adhere to coding principles provided and review if the updated code is present in the file path mentioned
|
|
117
|
+
- The code change should belong to the right file path
|
|
118
|
+
- The response must start with <file_path>
|
|
119
|
+
`,
|
|
120
|
+
},
|
|
121
|
+
];
|
|
122
|
+
const llm = new llm_1.LLM({
|
|
123
|
+
trace: repoEditSpan,
|
|
124
|
+
provider: "anthropic",
|
|
125
|
+
defaultModel: "claude-3-5-sonnet-20240620",
|
|
126
|
+
providerApiKey: constants_1.MODEL_API_KEYS[constants_1.DEFAULT_MODEL_PROVIDER],
|
|
127
|
+
});
|
|
128
|
+
const updatedUsageExampleMessage = await llm.createChatCompletion({
|
|
129
|
+
messages: prompt,
|
|
130
|
+
trace: repoEditSpan,
|
|
131
|
+
traceName: "repo-edit-agent-llm",
|
|
132
|
+
modelParameters: {
|
|
133
|
+
...constants_1.DEFAULT_MODEL_PARAMETERS,
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
const updates = (0, utils_1.extractTestUpdates)(updatedUsageExampleMessage?.content);
|
|
137
|
+
repoEditSpan?.end({
|
|
138
|
+
output: { updates },
|
|
139
|
+
input: {
|
|
140
|
+
task,
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
// TODO: remove this
|
|
144
|
+
await (0, llm_1.flushAllTraces)();
|
|
145
|
+
await (0, utils_1.applyFileChanges)({
|
|
146
|
+
validateTypes: false,
|
|
147
|
+
trace,
|
|
148
|
+
testCase: {},
|
|
149
|
+
fileChanges: updates,
|
|
150
|
+
});
|
|
151
|
+
// TODO: identify new file updates
|
|
152
|
+
const newFileUpdates = updates.filter((f) => !fsSync.existsSync(f.filePath));
|
|
153
|
+
await Promise.all(newFileUpdates.map((f) => {
|
|
154
|
+
return (async () => {
|
|
155
|
+
await promises_1.default.mkdir((0, path_1.dirname)(f.filePath), { recursive: true });
|
|
156
|
+
await promises_1.default.writeFile(f.filePath, f.newCode, "utf-8");
|
|
157
|
+
})();
|
|
158
|
+
}));
|
|
159
|
+
await Promise.all(updates.map((f) => {
|
|
160
|
+
return (async () => {
|
|
161
|
+
if (fsSync.existsSync(f.filePath)) {
|
|
162
|
+
await (0, web_1.formatCode)(f.filePath);
|
|
163
|
+
await (0, web_1.lintErrors)(f.filePath);
|
|
164
|
+
}
|
|
165
|
+
})();
|
|
166
|
+
}));
|
|
167
|
+
await testgenUpdatesReporter.sendMessage(`Successfully generated code for the given task. \n View [trace](${trace?.getTraceUrl()})`);
|
|
168
|
+
}
|
|
169
|
+
exports.repoEditAgent = repoEditAgent;
|
|
@@ -94,7 +94,7 @@ async function generateTest(testCase, file, options, trace) {
|
|
|
94
94
|
await (0, web_1.lintErrors)(file);
|
|
95
95
|
await (0, fix_ts_errors_1.validateAndFixTypescriptErrors)({
|
|
96
96
|
trace,
|
|
97
|
-
logger,
|
|
97
|
+
logger: new logger_1.CustomLogger({ useReporter: false }),
|
|
98
98
|
file,
|
|
99
99
|
pomCode: pomPrompt,
|
|
100
100
|
nonSpecFileCode: nonSpecFilePrompt,
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { TraceClient } from "@empiricalrun/llm";
|
|
2
2
|
import { TestCase, TestGenConfigOptions } from "../../types";
|
|
3
|
-
|
|
4
|
-
updatedFiles: string[];
|
|
5
|
-
};
|
|
3
|
+
import { UpdatedTestCase } from "./utils";
|
|
6
4
|
export declare function getUpdateTestCodeCompletion({ testCase, testFileContent, testFiles, pageFiles, testFilePath, trace, options, }: {
|
|
7
5
|
testCase: TestCase;
|
|
8
6
|
testFiles: string;
|
|
@@ -33,5 +31,4 @@ export declare function appendCreateTestBlock({ testCase, file, options, trace,
|
|
|
33
31
|
trace?: TraceClient;
|
|
34
32
|
validateTypes?: boolean;
|
|
35
33
|
}): Promise<UpdatedTestCase[]>;
|
|
36
|
-
export {};
|
|
37
34
|
//# sourceMappingURL=update-flow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-flow.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/update-flow.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,WAAW,EACZ,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"update-flow.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/update-flow.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAc3B,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAIL,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB,wBAAsB,2BAA2B,CAAC,EAChD,QAAQ,EACR,eAAe,EACf,SAAS,EACT,SAAS,EACT,YAAY,EACZ,KAAK,EACL,OAAO,GACR,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC,GAAG,OAAO,CACT;IACE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B,EAAE,CACJ,CA+CA;AAED,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,GAAG,SAAS,EACzC,OAAO,GAAE,OAAc,EACvB,QAAQ,GAAE,OAAc,EACxB,KAAK,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,eAAe,EAAE,CAAC,CA6D5B;AAED,wBAAsB,kCAAkC,CAAC,EACvD,SAAS,EACT,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,KAAK,GACN,EAAE;IACD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;CACtB,mBAuGA;AAED,wBAAsB,qBAAqB,CAAC,EAC1C,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,KAAK,EACL,aAAoB,GACrB,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CA4C7B"}
|
|
@@ -7,102 +7,13 @@ exports.appendCreateTestBlock = exports.getAppendCreateTestBlockCompletion = exp
|
|
|
7
7
|
const llm_1 = require("@empiricalrun/llm");
|
|
8
8
|
const crypto_1 = __importDefault(require("crypto"));
|
|
9
9
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
-
const ts_morph_1 = require("ts-morph");
|
|
11
10
|
const logger_1 = require("../../bin/logger");
|
|
12
11
|
const context_1 = require("../../bin/utils/context");
|
|
13
12
|
const fs_1 = require("../../bin/utils/fs");
|
|
14
13
|
const web_1 = require("../../bin/utils/platform/web");
|
|
15
14
|
const constants_1 = require("../../constants");
|
|
16
15
|
const session_1 = require("../../session");
|
|
17
|
-
const fix_ts_errors_1 = require("./fix-ts-errors");
|
|
18
16
|
const utils_1 = require("./utils");
|
|
19
|
-
async function applyFileChanges({ validateTypes = true, trace, testCase, fileChanges, logger, testGenOptions, pomPrompt, nonSpecFilePrompt, }) {
|
|
20
|
-
await Promise.allSettled(fileChanges.map(async (fileChange) => {
|
|
21
|
-
if (!fileChange.filePath) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
const { testBlock: testBlockUpdate } = (0, web_1.getTypescriptTestBlock)({
|
|
25
|
-
scenarioName: testCase?.name || "",
|
|
26
|
-
content: fileChange.newCode || "",
|
|
27
|
-
suites: [], // suites should be empty here since we ask LLM to send immediate parent AST node for the code update. so there won't be any nesting here, just the test block
|
|
28
|
-
});
|
|
29
|
-
if (testBlockUpdate) {
|
|
30
|
-
// assuming the test case getting updated
|
|
31
|
-
// maintaining the previous accuracy of the test case update
|
|
32
|
-
const readWriteFileSpan = trace?.span({ name: "write-to-file" });
|
|
33
|
-
let contents = await fs_extra_1.default.readFile(fileChange.filePath, "utf-8");
|
|
34
|
-
const [prependContent, strippedContent] = await (0, web_1.stripAndPrependImports)(fileChange.newCode, testCase?.name);
|
|
35
|
-
let updatedContent = prependContent + contents + `\n\n${strippedContent}`;
|
|
36
|
-
const { testBlock } = (0, web_1.getTypescriptTestBlock)({
|
|
37
|
-
scenarioName: testCase?.name,
|
|
38
|
-
content: contents,
|
|
39
|
-
suites: testCase?.suites,
|
|
40
|
-
});
|
|
41
|
-
contents = contents.replace(testBlock, `\n\n${strippedContent}`);
|
|
42
|
-
updatedContent = prependContent + contents;
|
|
43
|
-
await fs_extra_1.default.writeFile(fileChange.filePath, updatedContent, "utf-8");
|
|
44
|
-
readWriteFileSpan?.end({ output: { updatedContent } });
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
const readWriteFileSpan = trace?.span({ name: "write-to-file" });
|
|
48
|
-
let contents = await fs_extra_1.default.readFile(fileChange.filePath, "utf-8");
|
|
49
|
-
const project = new ts_morph_1.Project();
|
|
50
|
-
const sourceFile = project.createSourceFile("updated-code.ts", fileChange.newCode);
|
|
51
|
-
const functions = sourceFile.getFunctions();
|
|
52
|
-
const checkForMethodSrc = project.createSourceFile("check-method.ts", `class A {
|
|
53
|
-
${fileChange.newCode}
|
|
54
|
-
}`);
|
|
55
|
-
const methods = checkForMethodSrc.getDescendantsOfKind(ts_morph_1.SyntaxKind.MethodDeclaration);
|
|
56
|
-
const originalSource = project.createSourceFile("current-code.ts", contents);
|
|
57
|
-
// if there is a single function update in the file
|
|
58
|
-
if (functions.length === 1 &&
|
|
59
|
-
functions[0]?.getText() === fileChange.newCode) {
|
|
60
|
-
const updatedCodeFuncNames = functions.map((f) => f.getName());
|
|
61
|
-
const funcName = updatedCodeFuncNames[0];
|
|
62
|
-
const matchingNodes = originalSource
|
|
63
|
-
.getDescendantsOfKind(ts_morph_1.SyntaxKind.FunctionDeclaration)
|
|
64
|
-
.filter((node) => node.getName() === funcName);
|
|
65
|
-
matchingNodes[0]?.replaceWithText(functions[0]?.getText());
|
|
66
|
-
contents = originalSource.getFullText();
|
|
67
|
-
}
|
|
68
|
-
else if (
|
|
69
|
-
// if there is a update in method of a class in the file
|
|
70
|
-
methods.length === 1 &&
|
|
71
|
-
methods[0]?.getText() === fileChange.newCode) {
|
|
72
|
-
const method = methods[0];
|
|
73
|
-
const funcName = method?.getName();
|
|
74
|
-
const matchingNodes = originalSource
|
|
75
|
-
.getDescendantsOfKind(ts_morph_1.SyntaxKind.MethodDeclaration)
|
|
76
|
-
.filter((node) => node.getName() === funcName);
|
|
77
|
-
matchingNodes[0]?.replaceWithText(method?.getText());
|
|
78
|
-
contents = originalSource.getFullText();
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
// since we dont know what is getting updated,
|
|
82
|
-
// we believe that the patch is correct and contains few before and after lines
|
|
83
|
-
// to make the change unique for search & replace
|
|
84
|
-
contents = contents.replace(fileChange.oldCode, `\n\n${fileChange.newCode}`);
|
|
85
|
-
}
|
|
86
|
-
await fs_extra_1.default.writeFile(fileChange.filePath, contents, "utf-8");
|
|
87
|
-
readWriteFileSpan?.end({ output: { contents } });
|
|
88
|
-
}
|
|
89
|
-
// format and validate file change
|
|
90
|
-
if (validateTypes) {
|
|
91
|
-
await (0, fix_ts_errors_1.validateAndFixTypescriptErrors)({
|
|
92
|
-
trace,
|
|
93
|
-
logger,
|
|
94
|
-
file: fileChange.filePath,
|
|
95
|
-
pomCode: pomPrompt,
|
|
96
|
-
nonSpecFileCode: nonSpecFilePrompt,
|
|
97
|
-
testCase: testCase,
|
|
98
|
-
options: testGenOptions,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
trace?.event({ name: "format-file" });
|
|
102
|
-
await (0, web_1.formatCode)(fileChange.filePath);
|
|
103
|
-
logger.success(`${fileChange.filePath} file formatted successfully!`);
|
|
104
|
-
}));
|
|
105
|
-
}
|
|
106
17
|
async function getUpdateTestCodeCompletion({ testCase, testFileContent, testFiles, pageFiles, testFilePath, trace, options, }) {
|
|
107
18
|
const promptSpan = trace?.span({
|
|
108
19
|
name: "update-scenario-prompt",
|
|
@@ -182,8 +93,9 @@ async function updateTest(testCase, file, options, logging = true, validate = tr
|
|
|
182
93
|
...request,
|
|
183
94
|
trace: updateTestSpan,
|
|
184
95
|
});
|
|
96
|
+
console.log(`fileChanges ${testCase.steps.join("")}`, fileChanges);
|
|
185
97
|
logger.success("Test generated successfully!");
|
|
186
|
-
await applyFileChanges({
|
|
98
|
+
await (0, utils_1.applyFileChanges)({
|
|
187
99
|
validateTypes: validate,
|
|
188
100
|
trace: updateTestSpan,
|
|
189
101
|
testCase,
|
|
@@ -194,7 +106,7 @@ async function updateTest(testCase, file, options, logging = true, validate = tr
|
|
|
194
106
|
nonSpecFilePrompt: nonSpecFilePrompt,
|
|
195
107
|
});
|
|
196
108
|
if (trace) {
|
|
197
|
-
logger.log(`
|
|
109
|
+
logger.log(`View [trace](${trace.getTraceUrl()})`);
|
|
198
110
|
}
|
|
199
111
|
generatedTestCases.push({
|
|
200
112
|
...testCase,
|
|
@@ -321,7 +233,7 @@ async function appendCreateTestBlock({ testCase, file, options, trace, validateT
|
|
|
321
233
|
};
|
|
322
234
|
const appendCreateTestResp = await getAppendCreateTestBlockCompletion(appendCreateTestParams);
|
|
323
235
|
const fileChanges = (0, utils_1.extractAppendTestUpdates)(appendCreateTestResp);
|
|
324
|
-
await applyFileChanges({
|
|
236
|
+
await (0, utils_1.applyFileChanges)({
|
|
325
237
|
trace,
|
|
326
238
|
testCase,
|
|
327
239
|
fileChanges,
|
|
@@ -332,7 +244,7 @@ async function appendCreateTestBlock({ testCase, file, options, trace, validateT
|
|
|
332
244
|
validateTypes,
|
|
333
245
|
});
|
|
334
246
|
if (trace) {
|
|
335
|
-
logger.log(`
|
|
247
|
+
logger.log(`View [trace](${trace.getTraceUrl()})`);
|
|
336
248
|
}
|
|
337
249
|
generatedTestCases.push({
|
|
338
250
|
...testCase,
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { TraceClient } from "@empiricalrun/llm";
|
|
2
|
+
import { CustomLogger } from "../../bin/logger";
|
|
3
|
+
import { TestCase, TestGenConfigOptions } from "../../types";
|
|
1
4
|
/**
|
|
2
5
|
*
|
|
3
6
|
* method to extract file path and code updates for the LLM response of update flow
|
|
@@ -45,4 +48,22 @@ export declare function extractTestStepsSuggestions(input: string): {
|
|
|
45
48
|
reason: string;
|
|
46
49
|
methodName: string;
|
|
47
50
|
}[];
|
|
51
|
+
export type UpdatedTestCase = TestCase & {
|
|
52
|
+
updatedFiles: string[];
|
|
53
|
+
};
|
|
54
|
+
export declare function applyFileChanges({ validateTypes, trace, testCase, fileChanges, logger, testGenOptions, pomPrompt, nonSpecFilePrompt, }: {
|
|
55
|
+
validateTypes?: boolean;
|
|
56
|
+
trace?: TraceClient;
|
|
57
|
+
testCase: TestCase;
|
|
58
|
+
fileChanges: {
|
|
59
|
+
filePath: string | undefined;
|
|
60
|
+
oldCode: string | undefined;
|
|
61
|
+
newCode: string | undefined;
|
|
62
|
+
reason: string | undefined;
|
|
63
|
+
}[];
|
|
64
|
+
logger?: CustomLogger;
|
|
65
|
+
testGenOptions?: TestGenConfigOptions;
|
|
66
|
+
pomPrompt?: string;
|
|
67
|
+
nonSpecFilePrompt?: string;
|
|
68
|
+
}): Promise<void>;
|
|
48
69
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG;IACjD,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B,EAAE,CAiBF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG;IACvD,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B,EAAE,CA8BF;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,EAAE,CAgBF"}
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIhD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAMhD,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAG7D;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG;IACjD,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B,EAAE,CAiBF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG;IACvD,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B,EAAE,CA8BF;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,EAAE,CAgBF;AAED,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG;IACvC,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAEF,wBAAsB,gBAAgB,CAAC,EACrC,aAAoB,EACpB,KAAK,EACL,QAAQ,EACR,WAAW,EACX,MAAM,EACN,cAAc,EACd,SAAS,EACT,iBAAiB,GAClB,EAAE;IACD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE;QACX,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;QAC7B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;KAC5B,EAAE,CAAC;IACJ,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,iBAmHA"}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.extractTestStepsSuggestions = exports.extractAppendTestUpdates = exports.extractTestUpdates = void 0;
|
|
6
|
+
exports.applyFileChanges = exports.extractTestStepsSuggestions = exports.extractAppendTestUpdates = exports.extractTestUpdates = void 0;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const ts_morph_1 = require("ts-morph");
|
|
9
|
+
const web_1 = require("../../bin/utils/platform/web");
|
|
10
|
+
const fix_ts_errors_1 = require("./fix-ts-errors");
|
|
4
11
|
/**
|
|
5
12
|
*
|
|
6
13
|
* method to extract file path and code updates for the LLM response of update flow
|
|
@@ -81,3 +88,99 @@ function extractTestStepsSuggestions(input) {
|
|
|
81
88
|
return result.filter((r) => !!r.filePath && !!r.usageExample);
|
|
82
89
|
}
|
|
83
90
|
exports.extractTestStepsSuggestions = extractTestStepsSuggestions;
|
|
91
|
+
async function applyFileChanges({ validateTypes = true, trace, testCase, fileChanges, logger, testGenOptions, pomPrompt, nonSpecFilePrompt, }) {
|
|
92
|
+
await Promise.allSettled(fileChanges.map(async (fileChange) => {
|
|
93
|
+
if (!fileChange.filePath) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const { testBlock: testBlockUpdate } = (0, web_1.getTypescriptTestBlock)({
|
|
97
|
+
scenarioName: testCase?.name || "",
|
|
98
|
+
content: fileChange.newCode || "",
|
|
99
|
+
suites: [], // suites should be empty here since we ask LLM to send immediate parent AST node for the code update. so there won't be any nesting here, just the test block
|
|
100
|
+
});
|
|
101
|
+
if (testBlockUpdate) {
|
|
102
|
+
// assuming the test case getting updated
|
|
103
|
+
// maintaining the previous accuracy of the test case update
|
|
104
|
+
const readWriteFileSpan = trace?.span({ name: "write-to-file" });
|
|
105
|
+
let contents = await fs_extra_1.default.readFile(fileChange.filePath, "utf-8");
|
|
106
|
+
const [prependContent, strippedContent] = await (0, web_1.stripAndPrependImports)(fileChange.newCode, testCase?.name);
|
|
107
|
+
let updatedContent = prependContent + contents + `\n\n${strippedContent}`;
|
|
108
|
+
const { testBlock } = (0, web_1.getTypescriptTestBlock)({
|
|
109
|
+
scenarioName: testCase?.name,
|
|
110
|
+
content: contents,
|
|
111
|
+
suites: testCase?.suites,
|
|
112
|
+
});
|
|
113
|
+
contents = contents.replace(testBlock, `\n\n${strippedContent}`);
|
|
114
|
+
updatedContent = prependContent + contents;
|
|
115
|
+
await fs_extra_1.default.writeFile(fileChange.filePath, updatedContent, "utf-8");
|
|
116
|
+
readWriteFileSpan?.end({ output: { updatedContent } });
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
const readWriteFileSpan = trace?.span({ name: "write-to-file" });
|
|
120
|
+
let contents = await fs_extra_1.default.readFile(fileChange.filePath, "utf-8");
|
|
121
|
+
const project = new ts_morph_1.Project();
|
|
122
|
+
const sourceFile = project.createSourceFile("updated-code.ts", fileChange.newCode);
|
|
123
|
+
const functions = sourceFile.getFunctions();
|
|
124
|
+
const checkForMethodSrc = project.createSourceFile("check-method.ts", `class A {
|
|
125
|
+
${fileChange.newCode}
|
|
126
|
+
}`);
|
|
127
|
+
const methods = checkForMethodSrc.getDescendantsOfKind(ts_morph_1.SyntaxKind.MethodDeclaration);
|
|
128
|
+
const originalSource = project.createSourceFile("current-code.ts", contents);
|
|
129
|
+
// if there is a single function update in the file
|
|
130
|
+
if (functions.length === 1 &&
|
|
131
|
+
functions[0]?.getText() === fileChange.newCode) {
|
|
132
|
+
const updatedCodeFuncNames = functions.map((f) => f.getName());
|
|
133
|
+
const funcName = updatedCodeFuncNames[0];
|
|
134
|
+
const matchingNodes = originalSource
|
|
135
|
+
.getDescendantsOfKind(ts_morph_1.SyntaxKind.FunctionDeclaration)
|
|
136
|
+
.filter((node) => node.getName() === funcName);
|
|
137
|
+
matchingNodes[0]?.replaceWithText(functions[0]?.getText());
|
|
138
|
+
contents = originalSource.getFullText();
|
|
139
|
+
}
|
|
140
|
+
else if (
|
|
141
|
+
// if there is a update in method of a class in the file
|
|
142
|
+
methods.length === 1 &&
|
|
143
|
+
methods[0]?.getText() === fileChange.newCode) {
|
|
144
|
+
const method = methods[0];
|
|
145
|
+
const funcName = method?.getName();
|
|
146
|
+
const matchingNodes = originalSource
|
|
147
|
+
.getDescendantsOfKind(ts_morph_1.SyntaxKind.MethodDeclaration)
|
|
148
|
+
.filter((node) => node.getName() === funcName);
|
|
149
|
+
matchingNodes[0]?.replaceWithText(method?.getText());
|
|
150
|
+
contents = originalSource.getFullText();
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// since we dont know what is getting updated,
|
|
154
|
+
// we believe that the patch is correct and contains few before and after lines
|
|
155
|
+
// to make the change unique for search & replace
|
|
156
|
+
// since we dont know what is getting updated,
|
|
157
|
+
// we believe that the patch is correct and contains few before and after lines
|
|
158
|
+
// to make the change unique for search & replace
|
|
159
|
+
if (contents.includes(fileChange.oldCode)) {
|
|
160
|
+
contents = contents.replace(fileChange.oldCode, `\n\n${fileChange.newCode}`);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
logger?.error(`Unable to find the code to update in ${fileChange.filePath}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
await fs_extra_1.default.writeFile(fileChange.filePath, contents, "utf-8");
|
|
167
|
+
readWriteFileSpan?.end({ output: { contents } });
|
|
168
|
+
}
|
|
169
|
+
// format and validate file change
|
|
170
|
+
if (validateTypes) {
|
|
171
|
+
await (0, fix_ts_errors_1.validateAndFixTypescriptErrors)({
|
|
172
|
+
trace,
|
|
173
|
+
logger,
|
|
174
|
+
file: fileChange.filePath,
|
|
175
|
+
pomCode: pomPrompt,
|
|
176
|
+
nonSpecFileCode: nonSpecFilePrompt,
|
|
177
|
+
testCase: testCase,
|
|
178
|
+
options: testGenOptions,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
trace?.event({ name: "format-file" });
|
|
182
|
+
await (0, web_1.formatCode)(fileChange.filePath);
|
|
183
|
+
logger?.success(`${fileChange.filePath} file formatted successfully!`);
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
186
|
+
exports.applyFileChanges = applyFileChanges;
|
package/dist/bin/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const llm_1 = require("@empiricalrun/llm");
|
|
|
8
8
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
9
9
|
const run_1 = require("../agent/browsing/run");
|
|
10
10
|
const utils_1 = require("../agent/browsing/utils");
|
|
11
|
+
const repo_edit_1 = require("../agent/codegen/repo-edit");
|
|
11
12
|
const run_2 = require("../agent/codegen/run");
|
|
12
13
|
const infer_agent_1 = require("../agent/infer-agent");
|
|
13
14
|
const run_3 = require("../agent/planner/run");
|
|
@@ -41,10 +42,6 @@ async function runAgent(testGenConfig) {
|
|
|
41
42
|
console.warn("Failed to send log url to test gen update", e);
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
|
-
if (await (0, session_1.shouldStopSession)()) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
let agent = testGenConfig.options?.agent;
|
|
48
45
|
const session = (0, session_1.getSessionDetails)();
|
|
49
46
|
const trace = llm_1.langfuseInstance?.trace({
|
|
50
47
|
name: "generate-test",
|
|
@@ -55,6 +52,10 @@ async function runAgent(testGenConfig) {
|
|
|
55
52
|
testGenConfig.options?.metadata.environment || "",
|
|
56
53
|
].filter((s) => !!s),
|
|
57
54
|
});
|
|
55
|
+
if (await (0, session_1.shouldStopSession)()) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
let agent = testGenConfig.options?.agent;
|
|
58
59
|
trace?.update({
|
|
59
60
|
metadata: {
|
|
60
61
|
generationId: session.generationId,
|
|
@@ -70,6 +71,15 @@ async function runAgent(testGenConfig) {
|
|
|
70
71
|
console.warn("Failed to send trace url as test gen update", e);
|
|
71
72
|
}
|
|
72
73
|
}
|
|
74
|
+
// assuming if there is no test case specific test name, we need to update the test case name
|
|
75
|
+
if (!testCase.name) {
|
|
76
|
+
logger.success(`Generating code for the provided task. ${process.env.LOG_URL ? `[view log](${process.env.LOG_URL})` : ""}`);
|
|
77
|
+
await (0, repo_edit_1.repoEditAgent)({
|
|
78
|
+
trace,
|
|
79
|
+
task: testGenConfig.testCase.steps.join("\n"),
|
|
80
|
+
});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
73
83
|
if (!agent || agent === "auto") {
|
|
74
84
|
agent = await resolveAgentUsingTask({
|
|
75
85
|
testCase,
|
|
@@ -86,9 +96,11 @@ async function runAgent(testGenConfig) {
|
|
|
86
96
|
});
|
|
87
97
|
new logger_1.CustomLogger({ useReporter: false }).log("Generated Plan:", plan);
|
|
88
98
|
await new reporter_1.TestGenUpdatesReporter().sendMessage(plan);
|
|
89
|
-
return;
|
|
90
99
|
}
|
|
91
|
-
if (agent
|
|
100
|
+
else if (agent === "code") {
|
|
101
|
+
await (0, run_2.generateTest)(testCase, specPath, testGenConfig.options, trace);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
92
104
|
// this assumes we have only one scenario in test config
|
|
93
105
|
const filePathToUpdate = await (0, utils_1.prepareFileForMasterAgent)(testGenConfig, trace);
|
|
94
106
|
await (0, run_1.generateTestsUsingMasterAgent)({
|
|
@@ -97,9 +109,6 @@ async function runAgent(testGenConfig) {
|
|
|
97
109
|
pwProjectsFilter: testGenConfig.environment?.playwrightProjects,
|
|
98
110
|
});
|
|
99
111
|
}
|
|
100
|
-
else {
|
|
101
|
-
await (0, run_2.generateTest)(testCase, specPath, testGenConfig.options, trace);
|
|
102
|
-
}
|
|
103
112
|
}
|
|
104
113
|
(async function main() {
|
|
105
114
|
// this is where test gen starts executing on giving the command from ci
|
|
@@ -110,8 +119,6 @@ async function runAgent(testGenConfig) {
|
|
|
110
119
|
}
|
|
111
120
|
const { testGenConfig } = await (0, utils_2.parseCliArgs)();
|
|
112
121
|
(0, reporter_1.setReporterConfig)({
|
|
113
|
-
testCaseId: testGenConfig.testCase.id,
|
|
114
|
-
testCaseName: testGenConfig.testCase.name,
|
|
115
122
|
projectRepoName: testGenConfig.options?.metadata.projectRepoName,
|
|
116
123
|
testSessionId: testGenConfig.options?.metadata.testSessionId,
|
|
117
124
|
generationId: testGenConfig.options?.metadata.generationId,
|
|
@@ -133,7 +140,8 @@ async function runAgent(testGenConfig) {
|
|
|
133
140
|
new logger_1.CustomLogger().error(`Failed to generate test for the scenario. ${process.env.LOG_URL ? `[view log](${process.env.LOG_URL})` : ""}`, e?.message, e?.stack);
|
|
134
141
|
}
|
|
135
142
|
if (testGenConfig.options?.agent !== "code" &&
|
|
136
|
-
testGenConfig.options?.agent !== "plan"
|
|
143
|
+
testGenConfig.options?.agent !== "plan" &&
|
|
144
|
+
testGenConfig.testCase.name) {
|
|
137
145
|
await new reporter_1.TestGenUpdatesReporter().reportGenAssets({
|
|
138
146
|
projectRepoName: testGenConfig.options.metadata.projectRepoName,
|
|
139
147
|
testName: testGenConfig.testCase.name,
|
|
@@ -5,5 +5,8 @@ export declare function contextForGeneration(file?: string): Promise<{
|
|
|
5
5
|
nonSpecFilePrompt: string | undefined;
|
|
6
6
|
testFileContent: string;
|
|
7
7
|
}>;
|
|
8
|
+
export declare function generateTxtForRepository(): Promise<{
|
|
9
|
+
prompt: string | undefined;
|
|
10
|
+
}>;
|
|
8
11
|
export declare function fetchAppKnowledge(): Promise<string>;
|
|
9
12
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/bin/utils/context.ts"],"names":[],"mappings":"AAQA,wBAAsB,yBAAyB,
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/bin/utils/context.ts"],"names":[],"mappings":"AAQA,wBAAsB,yBAAyB,2CAe9C;AAED,wBAAsB,oBAAoB,CAAC,IAAI,CAAC,EAAE,MAAM;;;;;GAQvD;AAED,wBAAsB,wBAAwB;;GAK7C;AAED,wBAAsB,iBAAiB,oBAYtC"}
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.fetchAppKnowledge = exports.contextForGeneration = exports.createGitIgnoreFileFilter = void 0;
|
|
6
|
+
exports.fetchAppKnowledge = exports.generateTxtForRepository = exports.contextForGeneration = exports.createGitIgnoreFileFilter = void 0;
|
|
7
7
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
8
|
const ignore_1 = __importDefault(require("ignore"));
|
|
9
9
|
const fs_1 = require("./fs");
|
|
@@ -11,7 +11,13 @@ async function createGitIgnoreFileFilter() {
|
|
|
11
11
|
const ignoreFn = (0, ignore_1.default)();
|
|
12
12
|
if (fs_extra_1.default.existsSync(".gitignore")) {
|
|
13
13
|
// Not checking for nested gitignore
|
|
14
|
-
|
|
14
|
+
let gitignore = (await fs_extra_1.default.readFile(".gitignore")).toString();
|
|
15
|
+
gitignore = `
|
|
16
|
+
${gitignore}
|
|
17
|
+
.git/
|
|
18
|
+
.github/
|
|
19
|
+
package-lock.json
|
|
20
|
+
`;
|
|
15
21
|
ignoreFn.add(gitignore);
|
|
16
22
|
}
|
|
17
23
|
const filter = ignoreFn.createFilter();
|
|
@@ -28,6 +34,13 @@ async function contextForGeneration(file) {
|
|
|
28
34
|
};
|
|
29
35
|
}
|
|
30
36
|
exports.contextForGeneration = contextForGeneration;
|
|
37
|
+
async function generateTxtForRepository() {
|
|
38
|
+
const filter = await createGitIgnoreFileFilter();
|
|
39
|
+
return {
|
|
40
|
+
prompt: await (0, fs_1.generatePromptFromDirectory)(".", filter),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
exports.generateTxtForRepository = generateTxtForRepository;
|
|
31
44
|
async function fetchAppKnowledge() {
|
|
32
45
|
let fileExists = true;
|
|
33
46
|
const appKnowledgePath = "./app_knowledge.md";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAQlC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAOpC,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAQlC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAOpC,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,SAAS,iBAqC3E"}
|
package/dist/index.js
CHANGED
|
@@ -20,8 +20,6 @@ async function createTest(task, page, scope) {
|
|
|
20
20
|
const testConfigArg = process.env.TEST_GEN_TOKEN;
|
|
21
21
|
const { testGenConfig } = await (0, utils_1.parseCliArgs)(testConfigArg);
|
|
22
22
|
(0, reporter_1.setReporterConfig)({
|
|
23
|
-
testCaseId: testGenConfig.testCase.id,
|
|
24
|
-
testCaseName: testGenConfig.testCase.name,
|
|
25
23
|
projectRepoName: testGenConfig.options?.metadata.projectRepoName,
|
|
26
24
|
testSessionId: testGenConfig.options?.metadata.testSessionId,
|
|
27
25
|
generationId: testGenConfig.options?.metadata.generationId,
|
package/dist/reporter/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reporter/index.ts"],"names":[],"mappings":"AACA,OAAO,EAA4B,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAa5E,KAAK,kBAAkB,GAAG;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reporter/index.ts"],"names":[],"mappings":"AACA,OAAO,EAA4B,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAa5E,KAAK,kBAAkB,GAAG;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAKF,wBAAgB,WAAW,IAAI,QAAQ,GAAG,SAAS,CAUlD;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAGlE;AAED,qBAAa,sBAAsB;;IAE3B,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK1C,eAAe,CAAC,EACpB,eAAe,EACf,QAAQ,GACT,EAAE;QACD,eAAe,EAAE,MAAM,CAAC;QACxB,QAAQ,EAAE,MAAM,CAAC;KAClB;IAgDK,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA2C9C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY3C,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY1C,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAWxD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empiricalrun/test-gen",
|
|
3
|
-
"version": "0.38.
|
|
3
|
+
"version": "0.38.38",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"typescript": "^5.3.3",
|
|
74
74
|
"@empiricalrun/llm": "^0.9.28",
|
|
75
75
|
"@empiricalrun/r2-uploader": "^0.3.7",
|
|
76
|
-
"@empiricalrun/reporter": "^0.21.
|
|
76
|
+
"@empiricalrun/reporter": "^0.21.5"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@types/detect-port": "^1.3.5",
|