@empiricalrun/test-gen 0.22.11 → 0.23.0
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 +12 -0
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +4 -1
- package/dist/agent/browsing/index.d.ts.map +1 -1
- package/dist/agent/browsing/index.js +9 -2
- package/dist/agent/browsing/run.d.ts.map +1 -1
- package/dist/agent/browsing/run.js +3 -1
- package/dist/agent/browsing/utils.js +1 -1
- package/dist/agent/master/run.d.ts.map +1 -1
- package/dist/agent/master/run.js +7 -0
- package/dist/bin/index.js +1 -1
- package/dist/bin/utils/platform/web/index.d.ts.map +1 -1
- package/dist/bin/utils/platform/web/index.js +17 -3
- package/dist/reporter/index.d.ts +10 -4
- package/dist/reporter/index.d.ts.map +1 -1
- package/dist/reporter/index.js +71 -29
- package/dist/uploader/index.d.ts +6 -1
- package/dist/uploader/index.d.ts.map +1 -1
- package/dist/uploader/index.js +20 -13
- package/dist/uploader/r2.d.ts.map +1 -1
- package/dist/uploader/r2.js +8 -2
- package/dist/utils/exec.d.ts.map +1 -1
- package/dist/utils/exec.js +6 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @empiricalrun/test-gen
|
|
2
2
|
|
|
3
|
+
## 0.23.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3b4b2f3: feat: update the dashboard ux with updated messages between dashboard and test-gen
|
|
8
|
+
|
|
9
|
+
## 0.22.12
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- bfd6724: fix: avoid duplicate fixture imports
|
|
14
|
+
|
|
3
15
|
## 0.22.11
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/actions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/actions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIlC,OAAO,EAAU,YAAY,EAAE,MAAM,UAAU,CAAC;AAQhD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,eAAe,CAAmC;gBAC9C,IAAI,EAAE,IAAI;IAYhB,aAAa,CAAC,IAAI,oBAAa,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAuBhE,gBAAgB,IAAI,YAAY,EAAE;IAIlC,YAAY;IAIZ,UAAU;CASX"}
|
package/dist/actions/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PlaywrightActions = void 0;
|
|
4
4
|
const logger_1 = require("../bin/logger");
|
|
5
|
+
const reporter_1 = require("../reporter");
|
|
5
6
|
const assert_1 = require("./assert");
|
|
6
7
|
const click_1 = require("./click");
|
|
7
8
|
const done_1 = require("./done");
|
|
@@ -27,7 +28,8 @@ class PlaywrightActions {
|
|
|
27
28
|
if (!action) {
|
|
28
29
|
throw Error(`No action registered for action: ${name}`);
|
|
29
30
|
}
|
|
30
|
-
const logger = new logger_1.CustomLogger();
|
|
31
|
+
const logger = new logger_1.CustomLogger({ useReporter: false });
|
|
32
|
+
const testgenUpdatesReporter = new reporter_1.TestGenUpdatesReporter();
|
|
31
33
|
logger.logEmptyLine();
|
|
32
34
|
try {
|
|
33
35
|
const templateOptions = (await action.execute(args)) || { locator: "" };
|
|
@@ -36,6 +38,7 @@ class PlaywrightActions {
|
|
|
36
38
|
this.recordedActions.push({ name, code });
|
|
37
39
|
if (code) {
|
|
38
40
|
logger.log(`action: ${name} \ncode: ${code} \nreason: ${args.reason}`);
|
|
41
|
+
void testgenUpdatesReporter.sendMessage("```ts\n" + code + "\n```");
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
catch (e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAYlC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAMnD,KAAK,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,GAAG;IAC1D,YAAY,CAAC,EAAE;QACb,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;KAC9B,CAAC;CACH,CAAC;AAEF,wBAAsB,6BAA6B,CACjD,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,oBAAoB,mBA2K9B;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,oBAAoB,mBAqG9B"}
|
|
@@ -5,13 +5,15 @@ const llm_1 = require("@empiricalrun/llm");
|
|
|
5
5
|
const actions_1 = require("../../actions");
|
|
6
6
|
const logger_1 = require("../../bin/logger");
|
|
7
7
|
const constants_1 = require("../../constants");
|
|
8
|
+
const reporter_1 = require("../../reporter");
|
|
8
9
|
const session_1 = require("../../session");
|
|
9
10
|
const html_1 = require("../../utils/html");
|
|
10
11
|
const run_1 = require("../master/run");
|
|
11
12
|
const verification_1 = require("../verification");
|
|
12
13
|
const utils_1 = require("./utils");
|
|
13
14
|
async function browsingAgentUsingMasterAgent(task, page, options) {
|
|
14
|
-
const logger = new logger_1.CustomLogger();
|
|
15
|
+
const logger = new logger_1.CustomLogger({ useReporter: false });
|
|
16
|
+
const testgenUpdatesReporter = new reporter_1.TestGenUpdatesReporter();
|
|
15
17
|
const trace = llm_1.langfuseInstance.trace({
|
|
16
18
|
name: "test-generator",
|
|
17
19
|
...(0, session_1.getSessionDetails)(),
|
|
@@ -44,12 +46,15 @@ async function browsingAgentUsingMasterAgent(task, page, options) {
|
|
|
44
46
|
});
|
|
45
47
|
isGivenTaskDone = verificationAgentResp.isDone;
|
|
46
48
|
if (isGivenTaskDone) {
|
|
47
|
-
|
|
49
|
+
await testgenUpdatesReporter.sendMessage(`${verificationAgentResp.reason} Marking the task as done.`);
|
|
48
50
|
break;
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
const { action, reason } = await (0, run_1.masterAgent)(task, page, masterAgentActions, masterAgentSpan, llm, options);
|
|
52
54
|
logger.log(`Next action: ${action} \n reason: ${reason}`);
|
|
55
|
+
if (!action) {
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
53
58
|
if (isGivenTaskDone) {
|
|
54
59
|
break;
|
|
55
60
|
}
|
|
@@ -129,6 +134,7 @@ async function browsingAgentUsingMasterAgent(task, page, options) {
|
|
|
129
134
|
?.reason,
|
|
130
135
|
});
|
|
131
136
|
lastActionExecTrace = e.message;
|
|
137
|
+
void testgenUpdatesReporter.sendMessage(e.message);
|
|
132
138
|
logger.error(lastActionExecTrace, e);
|
|
133
139
|
}
|
|
134
140
|
}
|
|
@@ -152,6 +158,7 @@ async function browsingAgentUsingMasterAgent(task, page, options) {
|
|
|
152
158
|
const code = actions.generateCode();
|
|
153
159
|
trace.update({ input: { task }, output: { code } });
|
|
154
160
|
logger.success("Successfully generated code for the given task");
|
|
161
|
+
await testgenUpdatesReporter.sendMessage(`Successfully generated code for the given task. \n View [trace](${trace.getTraceUrl()})`);
|
|
155
162
|
logger.log(`Trace: ${trace.getTraceUrl()}`);
|
|
156
163
|
return code;
|
|
157
164
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/run.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/run.ts"],"names":[],"mappings":"AAcA,wBAAsB,+BAA+B,CAAC,YAAY,EAAE,MAAM,iBA6BzE"}
|
|
@@ -9,10 +9,11 @@ const logger_1 = require("../../bin/logger");
|
|
|
9
9
|
const utils_1 = require("../../bin/utils");
|
|
10
10
|
const web_1 = require("../../bin/utils/platform/web");
|
|
11
11
|
const server_1 = require("../../file/server");
|
|
12
|
+
const reporter_1 = require("../../reporter");
|
|
12
13
|
const exec_1 = require("../../utils/exec");
|
|
13
14
|
const utils_2 = require("./utils");
|
|
14
15
|
async function generateTestsUsingBrowsingAgent(testFilePath) {
|
|
15
|
-
const logger = new logger_1.CustomLogger();
|
|
16
|
+
const logger = new logger_1.CustomLogger({ useReporter: false });
|
|
16
17
|
(0, utils_2.canRunBrowsingAgent)(testFilePath);
|
|
17
18
|
const port = await (0, detect_port_1.default)(3030);
|
|
18
19
|
const fileService = new server_1.FileService({ port });
|
|
@@ -37,6 +38,7 @@ async function generateTestsUsingBrowsingAgent(testFilePath) {
|
|
|
37
38
|
}
|
|
38
39
|
catch (e) {
|
|
39
40
|
logger.error(e);
|
|
41
|
+
await new reporter_1.TestGenUpdatesReporter().sendMessage(e);
|
|
40
42
|
process.exit(1);
|
|
41
43
|
}
|
|
42
44
|
await (0, web_1.removeTestOnly)(testFilePath);
|
|
@@ -25,7 +25,7 @@ exports.prepareBrowsingAgentTask = prepareBrowsingAgentTask;
|
|
|
25
25
|
async function prepareFileForBrowsingAgent(genConfig) {
|
|
26
26
|
const { specPath, testCase } = genConfig;
|
|
27
27
|
const { name, steps } = testCase;
|
|
28
|
-
const logger = new logger_1.CustomLogger();
|
|
28
|
+
const logger = new logger_1.CustomLogger({ useReporter: false });
|
|
29
29
|
if (!fs_extra_1.default.existsSync(specPath)) {
|
|
30
30
|
await fs_extra_1.default.createFile(specPath);
|
|
31
31
|
const fileContentWithImports = (0, web_1.addNewImport)("", ["test", "expect"], (0, web_1.getFixtureImportPath)(specPath));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/master/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,GAAG,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/master/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,GAAG,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAMlC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD,KAAK,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAE1D,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,IAAI,EACV,eAAe,EAAE,MAAM,EAAE,EACzB,KAAK,EAAE,WAAW,EAClB,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,oBAAoB,gBAsE9B"}
|
package/dist/agent/master/run.js
CHANGED
|
@@ -5,10 +5,13 @@ const llm_1 = require("@empiricalrun/llm");
|
|
|
5
5
|
const done_1 = require("../../actions/done");
|
|
6
6
|
const next_task_1 = require("../../actions/next-task");
|
|
7
7
|
const constants_1 = require("../../constants");
|
|
8
|
+
const reporter_1 = require("../../reporter");
|
|
8
9
|
async function masterAgent(task, page, executedActions, trace, llm, options) {
|
|
9
10
|
trace.update({ input: { task } });
|
|
10
11
|
const promptSpan = trace.span({ name: "page-prompt" });
|
|
11
12
|
const buffer = await page.screenshot({ fullPage: true });
|
|
13
|
+
const testGenReporter = new reporter_1.TestGenUpdatesReporter();
|
|
14
|
+
const testGenSnapshotUpdatePromise = testGenReporter.sendCurrentView(buffer);
|
|
12
15
|
const pageScreenshot = `data:image/png;base64,${buffer.toString("base64")}`;
|
|
13
16
|
const promptMessages = await (0, llm_1.getPrompt)("test-gen", {
|
|
14
17
|
task,
|
|
@@ -66,6 +69,10 @@ async function masterAgent(task, page, executedActions, trace, llm, options) {
|
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
trace.update({ input: { task }, output: { output } });
|
|
72
|
+
if (output.action) {
|
|
73
|
+
await testGenReporter.sendMessage(output.action);
|
|
74
|
+
}
|
|
75
|
+
await testGenSnapshotUpdatePromise;
|
|
69
76
|
return output;
|
|
70
77
|
}
|
|
71
78
|
exports.masterAgent = masterAgent;
|
package/dist/bin/index.js
CHANGED
|
@@ -28,7 +28,7 @@ async function runAgent(sourceFile, testGenConfig) {
|
|
|
28
28
|
logger.success(`Generating test using ${testGenConfig.options?.agent} agent`);
|
|
29
29
|
await (0, utils_1.prepareFileForBrowsingAgent)(testGenConfig);
|
|
30
30
|
await (0, run_1.generateTestsUsingBrowsingAgent)(specPath);
|
|
31
|
-
await
|
|
31
|
+
await new reporter_1.TestGenUpdatesReporter().reportGenAssets({
|
|
32
32
|
projectRepoName: testGenConfig.options.metadata.projectRepoName,
|
|
33
33
|
testName: testCase.name,
|
|
34
34
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/bin/utils/platform/web/index.ts"],"names":[],"mappings":"AAMA,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;EAwB3E;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAG5E;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAwD7D;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,mCAUjB;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,iBAShD;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,iBAQhD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,UAE5E;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,iBAMpD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,UAcpD;AAED,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/bin/utils/platform/web/index.ts"],"names":[],"mappings":"AAMA,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;EAwB3E;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAG5E;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAwD7D;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,mCAUjB;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,iBAShD;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,iBAQhD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,UAE5E;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,iBAMpD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,UAcpD;AAED,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,UA0CtB"}
|
|
@@ -143,13 +143,27 @@ function replaceCreateTestWithNewCode(filePath, contents, generatedCode) {
|
|
|
143
143
|
const sourceFile = project.createSourceFile("test.ts", contents);
|
|
144
144
|
const createTestNode = sourceFile.getFirstDescendant((node) => !!(node.isKind(ts_morph_1.SyntaxKind.CallExpression) &&
|
|
145
145
|
node.getExpression().getText() === "createTest"));
|
|
146
|
-
const
|
|
146
|
+
const createTestWithAwait = `await ${createTestNode?.getText()}`;
|
|
147
|
+
let updatedTestFile = contents.replace(createTestWithAwait, function () {
|
|
147
148
|
// str.replace treats characters like $ differently
|
|
148
149
|
// Using a function helps us avoid special handling
|
|
149
150
|
// https://stackoverflow.com/a/28103073
|
|
150
151
|
return "\n" + generatedCode;
|
|
151
152
|
});
|
|
152
|
-
const
|
|
153
|
-
|
|
153
|
+
const fixtureImportNode = sourceFile.getFirstDescendant((node) => !!(node.isKind(ts_morph_1.SyntaxKind.ImportDeclaration) &&
|
|
154
|
+
node.getText().includes("fixtures")));
|
|
155
|
+
if (!fixtureImportNode) {
|
|
156
|
+
throw new Error("No import from fixtures found.");
|
|
157
|
+
}
|
|
158
|
+
const importClause = fixtureImportNode.getImportClause();
|
|
159
|
+
const namedImports = importClause
|
|
160
|
+
.getNamedImports()
|
|
161
|
+
.map((imp) => imp.getName());
|
|
162
|
+
const isComplete = namedImports.includes("test") && namedImports.includes("expect");
|
|
163
|
+
if (!isComplete) {
|
|
164
|
+
const expectedImports = `import { test, expect } from "${getFixtureImportPath(filePath)}";`;
|
|
165
|
+
updatedTestFile = updatedTestFile.replace(fixtureImportNode.getText(), expectedImports);
|
|
166
|
+
}
|
|
167
|
+
return updatedTestFile;
|
|
154
168
|
}
|
|
155
169
|
exports.replaceCreateTestWithNewCode = replaceCreateTestWithNewCode;
|
package/dist/reporter/index.d.ts
CHANGED
|
@@ -16,10 +16,16 @@ export declare function getReporter(): Reporter | undefined;
|
|
|
16
16
|
* }
|
|
17
17
|
* @returns Promise<void> returns void
|
|
18
18
|
*/
|
|
19
|
-
export declare function reportTestGenVideos({ projectRepoName, testName, }: {
|
|
20
|
-
projectRepoName: string;
|
|
21
|
-
testName: string;
|
|
22
|
-
}): Promise<void>;
|
|
23
19
|
export declare function setReporterConfig(config: ReporterConfigType): void;
|
|
20
|
+
export declare class TestGenUpdatesReporter {
|
|
21
|
+
constructor();
|
|
22
|
+
sendGenTrace(trace: string): Promise<void>;
|
|
23
|
+
reportGenAssets({ projectRepoName, testName, }: {
|
|
24
|
+
projectRepoName: string;
|
|
25
|
+
testName: string;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
sendCurrentView(buffer: Buffer): Promise<void>;
|
|
28
|
+
sendMessage(message: string): Promise<void>;
|
|
29
|
+
}
|
|
24
30
|
export {};
|
|
25
31
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reporter/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,QAAQ,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reporter/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAc5E,KAAK,kBAAkB,GAAG;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,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;IAkCK,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA2B9C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAUlD"}
|
package/dist/reporter/index.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
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.
|
|
6
|
+
exports.TestGenUpdatesReporter = exports.setReporterConfig = exports.getReporter = void 0;
|
|
4
7
|
const reporter_1 = require("@empiricalrun/reporter");
|
|
8
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
5
10
|
const logger_1 = require("../bin/logger");
|
|
6
11
|
const uploader_1 = require("../uploader");
|
|
12
|
+
const r2_1 = require("../uploader/r2");
|
|
7
13
|
let reporterInstance = undefined;
|
|
8
14
|
let reporterConfig = undefined;
|
|
9
15
|
function getReporter() {
|
|
@@ -28,36 +34,72 @@ exports.getReporter = getReporter;
|
|
|
28
34
|
* }
|
|
29
35
|
* @returns Promise<void> returns void
|
|
30
36
|
*/
|
|
31
|
-
async function reportTestGenVideos({ projectRepoName, testName, }) {
|
|
32
|
-
const logger = new logger_1.CustomLogger();
|
|
33
|
-
try {
|
|
34
|
-
if (!(0, uploader_1.checkIfResultsUploadAllowed)()) {
|
|
35
|
-
logger.log("Skipped uploading generated test video");
|
|
36
|
-
}
|
|
37
|
-
const { videoUrls } = await (0, uploader_1.uploadTestResultsUsingPrjtRepo)({
|
|
38
|
-
projectRepoName,
|
|
39
|
-
testName,
|
|
40
|
-
});
|
|
41
|
-
const reporter = getReporter();
|
|
42
|
-
const reporterMessage = `
|
|
43
|
-
|
|
44
|
-
Here are the videos of the generated test:
|
|
45
|
-
|
|
46
|
-
${videoUrls
|
|
47
|
-
.map((url) => `
|
|
48
|
-
<video src="${url}" autoplay="true" muted="true" controls playsinline></video>`)
|
|
49
|
-
.join("\n")}
|
|
50
|
-
`;
|
|
51
|
-
await reporter?.report(new reporter_1.ProcessLogMessageBuilder({ message: reporterMessage }));
|
|
52
|
-
}
|
|
53
|
-
catch (err) {
|
|
54
|
-
logger.error("Failed to report test results");
|
|
55
|
-
console.error(err);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
exports.reportTestGenVideos = reportTestGenVideos;
|
|
59
37
|
function setReporterConfig(config) {
|
|
60
38
|
console.info("initialised reporter config");
|
|
61
39
|
reporterConfig = config;
|
|
62
40
|
}
|
|
63
41
|
exports.setReporterConfig = setReporterConfig;
|
|
42
|
+
class TestGenUpdatesReporter {
|
|
43
|
+
constructor() { }
|
|
44
|
+
async sendGenTrace(trace) {
|
|
45
|
+
console.log("trace", trace);
|
|
46
|
+
// upload trace to r2 and report it to reporter
|
|
47
|
+
}
|
|
48
|
+
async reportGenAssets({ projectRepoName, testName, }) {
|
|
49
|
+
const logger = new logger_1.CustomLogger();
|
|
50
|
+
try {
|
|
51
|
+
if (!(0, uploader_1.checkIfResultsUploadAllowed)()) {
|
|
52
|
+
logger.log("Skipped uploading generated test video");
|
|
53
|
+
}
|
|
54
|
+
const { videoUrls, traceFiles } = await (0, uploader_1.uploadTestResultsUsingPrjRepo)({
|
|
55
|
+
projectRepoName,
|
|
56
|
+
testName,
|
|
57
|
+
});
|
|
58
|
+
const reporter = getReporter();
|
|
59
|
+
const message = {
|
|
60
|
+
type: "video",
|
|
61
|
+
videoUrls,
|
|
62
|
+
};
|
|
63
|
+
await Promise.allSettled([
|
|
64
|
+
reporter?.report(new reporter_1.ProcessLogMessageBuilder({ message: JSON.stringify(message) })),
|
|
65
|
+
reporter?.report(new reporter_1.ProcessLogMessageBuilder({
|
|
66
|
+
message: JSON.stringify({
|
|
67
|
+
type: "trace",
|
|
68
|
+
traceFiles,
|
|
69
|
+
}),
|
|
70
|
+
})),
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
logger.error("Failed to report test results");
|
|
75
|
+
console.error(err);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async sendCurrentView(buffer) {
|
|
79
|
+
// upload current screenshot to r2 and report it to reporter
|
|
80
|
+
await promises_1.default.mkdir((process.cwd(), "gen-assets"));
|
|
81
|
+
await promises_1.default.writeFile(path_1.default.join(process.cwd(), "gen-assets", `current-view-${Date.now()}.png`), buffer);
|
|
82
|
+
const uploadDir = (0, uploader_1.getUploadPathForRun)(reporterConfig?.projectRepoName);
|
|
83
|
+
const files = await (0, r2_1.uploadDirectory)({
|
|
84
|
+
sourceDir: path_1.default.join(process.cwd(), "gen-assets"),
|
|
85
|
+
destinationDir: uploadDir,
|
|
86
|
+
uploadBucket: uploader_1.UPLOAD_BUCKET,
|
|
87
|
+
});
|
|
88
|
+
const filePath = Object.keys(files)[0];
|
|
89
|
+
const relativeFilePath = filePath.replace(path_1.default.join(process.cwd(), "gen-assets"), "");
|
|
90
|
+
const url = `${uploader_1.UPLOAD_DOMAIN}/${uploadDir}${relativeFilePath}`;
|
|
91
|
+
await getReporter()?.report(new reporter_1.ProcessLogMessageBuilder({
|
|
92
|
+
message: JSON.stringify({ type: "current-view", url }),
|
|
93
|
+
}));
|
|
94
|
+
await promises_1.default.rmdir((process.cwd(), "gen-assets"), { recursive: true });
|
|
95
|
+
}
|
|
96
|
+
async sendMessage(message) {
|
|
97
|
+
const reporter = getReporter();
|
|
98
|
+
if (reporter) {
|
|
99
|
+
await reporter.report(new reporter_1.ProcessLogMessageBuilder({
|
|
100
|
+
message,
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
exports.TestGenUpdatesReporter = TestGenUpdatesReporter;
|
package/dist/uploader/index.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
export declare const UPLOAD_BUCKET = "test-report";
|
|
2
|
+
export declare const UPLOAD_DOMAIN = "https://reports.empirical.run";
|
|
3
|
+
export declare function getFullUploadPath(filePath: string, uploadDir: string): string;
|
|
1
4
|
/**
|
|
2
5
|
* Function to upload test results to R2 using the project repo name and test name.
|
|
3
6
|
* This function uploads both the JSON summary of test results and associated video files.
|
|
@@ -8,12 +11,14 @@
|
|
|
8
11
|
* @returns {string[]} returns.videoUrls - URLs of the uploaded video files.
|
|
9
12
|
* @returns {string} returns.summaryUrl - URL of the uploaded summary JSON file.
|
|
10
13
|
*/
|
|
11
|
-
export declare function
|
|
14
|
+
export declare function uploadTestResultsUsingPrjRepo({ projectRepoName, testName, }: {
|
|
12
15
|
projectRepoName: string;
|
|
13
16
|
testName: string;
|
|
14
17
|
}): Promise<{
|
|
15
18
|
videoUrls: string[];
|
|
16
19
|
summaryUrl: string;
|
|
20
|
+
traceFiles: string[];
|
|
17
21
|
}>;
|
|
22
|
+
export declare function getUploadPathForRun(projectRepoName: string): string;
|
|
18
23
|
export declare function checkIfResultsUploadAllowed(): string | undefined;
|
|
19
24
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/uploader/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/uploader/index.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,aAAa,gBAAgB,CAAC;AAC3C,eAAO,MAAM,aAAa,kCAAkC,CAAC;AAG7D,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAMpE;AAED;;;;;;;;;GASG;AACH,wBAAsB,6BAA6B,CAAC,EAClD,eAAe,EACf,QAAQ,GACT,EAAE;IACD,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC;IACV,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,CAAC,CAoDD;AAED,wBAAgB,mBAAmB,CAAC,eAAe,EAAE,MAAM,UAM1D;AAED,wBAAgB,2BAA2B,uBAQ1C"}
|
package/dist/uploader/index.js
CHANGED
|
@@ -3,18 +3,20 @@ 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.checkIfResultsUploadAllowed = exports.
|
|
6
|
+
exports.checkIfResultsUploadAllowed = exports.getUploadPathForRun = exports.uploadTestResultsUsingPrjRepo = exports.getFullUploadPath = exports.UPLOAD_DOMAIN = exports.UPLOAD_BUCKET = void 0;
|
|
7
7
|
const reporter_1 = require("@empiricalrun/reporter");
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const r2_1 = require("./r2");
|
|
10
10
|
// json summary of test results
|
|
11
11
|
const TEST_RESULTS_DIR = "test-results";
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
exports.UPLOAD_BUCKET = "test-report";
|
|
13
|
+
exports.UPLOAD_DOMAIN = "https://reports.empirical.run"; // domain based on bucket mentioned above
|
|
14
|
+
const uploadId = crypto.randomUUID();
|
|
14
15
|
function getFullUploadPath(filePath, uploadDir) {
|
|
15
16
|
const relativeFilePath = filePath.replace(path_1.default.join(process.cwd(), TEST_RESULTS_DIR), "");
|
|
16
|
-
return `${UPLOAD_DOMAIN}/${uploadDir}${relativeFilePath}`;
|
|
17
|
+
return `${exports.UPLOAD_DOMAIN}/${uploadDir}${relativeFilePath}`;
|
|
17
18
|
}
|
|
19
|
+
exports.getFullUploadPath = getFullUploadPath;
|
|
18
20
|
/**
|
|
19
21
|
* Function to upload test results to R2 using the project repo name and test name.
|
|
20
22
|
* This function uploads both the JSON summary of test results and associated video files.
|
|
@@ -25,21 +27,19 @@ function getFullUploadPath(filePath, uploadDir) {
|
|
|
25
27
|
* @returns {string[]} returns.videoUrls - URLs of the uploaded video files.
|
|
26
28
|
* @returns {string} returns.summaryUrl - URL of the uploaded summary JSON file.
|
|
27
29
|
*/
|
|
28
|
-
async function
|
|
29
|
-
const uploadUniqueId = crypto.randomUUID();
|
|
30
|
+
async function uploadTestResultsUsingPrjRepo({ projectRepoName, testName, }) {
|
|
30
31
|
// project repo name is the github repo name
|
|
31
|
-
|
|
32
|
-
const uploadDir = `test-generation/${projectRepoName.replace("-tests", "")}/${uploadUniqueId}`;
|
|
32
|
+
const uploadDir = getUploadPathForRun(projectRepoName);
|
|
33
33
|
const files = await (0, r2_1.uploadDirectory)({
|
|
34
34
|
sourceDir: path_1.default.join(process.cwd(), TEST_RESULTS_DIR),
|
|
35
35
|
destinationDir: uploadDir,
|
|
36
|
-
uploadBucket: UPLOAD_BUCKET,
|
|
36
|
+
uploadBucket: exports.UPLOAD_BUCKET,
|
|
37
37
|
});
|
|
38
38
|
const fileNames = Object.keys(files); // fileNames are absolute paths of the input files
|
|
39
39
|
const defaultLocation = path_1.default.join(process.cwd(), "test-results", "summary.json");
|
|
40
40
|
const results = (0, reporter_1.parseJsonReport)(defaultLocation);
|
|
41
41
|
const flatTestsList = (0, reporter_1.getFlattenedTestList)(results.suites);
|
|
42
|
-
const
|
|
42
|
+
const testAttachmentPaths = [];
|
|
43
43
|
for (const test of flatTestsList) {
|
|
44
44
|
if (test.title === testName) {
|
|
45
45
|
if (test.tests[0]) {
|
|
@@ -47,7 +47,7 @@ async function uploadTestResultsUsingPrjtRepo({ projectRepoName, testName, }) {
|
|
|
47
47
|
// results array is basically made by retries
|
|
48
48
|
for (const attachments of test.tests[0].results[0].attachments) {
|
|
49
49
|
if (attachments.path) {
|
|
50
|
-
|
|
50
|
+
testAttachmentPaths.push(attachments.path);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -57,13 +57,20 @@ async function uploadTestResultsUsingPrjtRepo({ projectRepoName, testName, }) {
|
|
|
57
57
|
// current assumption
|
|
58
58
|
// - test gen will only run on a single spec file
|
|
59
59
|
// - the video files are of the format - <some-directory>/video.webm
|
|
60
|
-
const videoFiles = fileNames.filter((fileName) => fileName.endsWith(".webm") &&
|
|
60
|
+
const videoFiles = fileNames.filter((fileName) => fileName.endsWith(".webm") && testAttachmentPaths.includes(fileName));
|
|
61
|
+
const traceFiles = fileNames.filter((fileName) => fileName.endsWith(".zip") && testAttachmentPaths.includes(fileName));
|
|
61
62
|
return {
|
|
62
63
|
videoUrls: videoFiles.map((fileName) => getFullUploadPath(fileName, uploadDir)),
|
|
63
64
|
summaryUrl: getFullUploadPath("/test-results/summary.json", uploadDir),
|
|
65
|
+
traceFiles: traceFiles.map((fileName) => getFullUploadPath(fileName, uploadDir)),
|
|
64
66
|
};
|
|
65
67
|
}
|
|
66
|
-
exports.
|
|
68
|
+
exports.uploadTestResultsUsingPrjRepo = uploadTestResultsUsingPrjRepo;
|
|
69
|
+
function getUploadPathForRun(projectRepoName) {
|
|
70
|
+
const uploadDir = `test-generation/${projectRepoName.replace("-tests", "")}/${uploadId}`;
|
|
71
|
+
return uploadDir;
|
|
72
|
+
}
|
|
73
|
+
exports.getUploadPathForRun = getUploadPathForRun;
|
|
67
74
|
function checkIfResultsUploadAllowed() {
|
|
68
75
|
// TODO: check for valid R2 credentials
|
|
69
76
|
// check for project repo name, and r2 creds
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../../src/uploader/r2.ts"],"names":[],"mappings":"AAqBA,UAAU,OAAO;IACf,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB;
|
|
1
|
+
{"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../../src/uploader/r2.ts"],"names":[],"mappings":"AAqBA,UAAU,OAAO;IACf,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB;AAsGD,wBAAsB,eAAe,CAAC,EACpC,SAAS,EACT,cAAc,EACd,YAAY,GACb,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,OAAO,CAAC,CAWnB"}
|
package/dist/uploader/r2.js
CHANGED
|
@@ -61,7 +61,6 @@ const run = async (config) => {
|
|
|
61
61
|
},
|
|
62
62
|
});
|
|
63
63
|
const files = getFileList(config.sourceDir);
|
|
64
|
-
const mime = (await import("mime")).default;
|
|
65
64
|
await Promise.all(files.map(async (file) => {
|
|
66
65
|
console.log(file);
|
|
67
66
|
const fileStream = fs.readFileSync(file);
|
|
@@ -73,7 +72,14 @@ const run = async (config) => {
|
|
|
73
72
|
if (fileKey.includes(".gitkeep"))
|
|
74
73
|
return;
|
|
75
74
|
console.log(fileKey);
|
|
76
|
-
|
|
75
|
+
let mimeType = "application/octet-stream";
|
|
76
|
+
try {
|
|
77
|
+
const mime = (await import("mime")).default;
|
|
78
|
+
mimeType = mime.getType(file) || "application/octet-stream";
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
console.warn("Failed to get mime type for file", file, err);
|
|
82
|
+
}
|
|
77
83
|
const uploadParams = {
|
|
78
84
|
Bucket: config.bucket,
|
|
79
85
|
Key: fileKey,
|
package/dist/utils/exec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/utils/exec.ts"],"names":[],"mappings":"AAGA,wBAAgB,GAAG,CACjB,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACxC,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/utils/exec.ts"],"names":[],"mappings":"AAGA,wBAAgB,GAAG,CACjB,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACxC,OAAO,CAAC,MAAM,CAAC,CA2BjB"}
|
package/dist/utils/exec.js
CHANGED
|
@@ -7,25 +7,27 @@ exports.cmd = void 0;
|
|
|
7
7
|
const child_process_1 = require("child_process");
|
|
8
8
|
const process_1 = __importDefault(require("process"));
|
|
9
9
|
function cmd(command, options) {
|
|
10
|
-
let
|
|
10
|
+
let errorLogs = [];
|
|
11
11
|
return new Promise((resolveFunc, rejectFunc) => {
|
|
12
12
|
let p = (0, child_process_1.spawn)(command[0], command.slice(1), {
|
|
13
13
|
env: { ...process_1.default.env, ...options.env },
|
|
14
14
|
});
|
|
15
15
|
p.stdout.on("data", (x) => {
|
|
16
16
|
const log = x.toString();
|
|
17
|
+
if (log.includes("Error")) {
|
|
18
|
+
errorLogs.push(log);
|
|
19
|
+
}
|
|
17
20
|
process_1.default.stdout.write(log);
|
|
18
|
-
lastLog = log;
|
|
19
21
|
});
|
|
20
22
|
p.stderr.on("data", (x) => {
|
|
21
23
|
const log = x.toString();
|
|
22
24
|
process_1.default.stderr.write(x.toString());
|
|
23
|
-
|
|
25
|
+
errorLogs.push(log);
|
|
24
26
|
});
|
|
25
27
|
p.on("exit", (code) => {
|
|
26
28
|
if (code != 0) {
|
|
27
29
|
// assuming last log is the error message before exiting
|
|
28
|
-
rejectFunc(
|
|
30
|
+
rejectFunc(errorLogs.slice(-3).join("\n"));
|
|
29
31
|
}
|
|
30
32
|
else {
|
|
31
33
|
resolveFunc(code);
|