@empiricalrun/test-gen 0.66.0 → 0.66.2
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 +26 -0
- package/dist/agent/browsing/run.js +4 -4
- package/dist/agent/browsing/utils.d.ts +1 -0
- package/dist/agent/browsing/utils.d.ts.map +1 -1
- package/dist/agent/browsing/utils.js +5 -4
- package/dist/agent/chat/index.d.ts +1 -0
- package/dist/agent/chat/index.d.ts.map +1 -1
- package/dist/agent/chat/index.js +2 -0
- package/dist/agent/chat/{prompt.d.ts → prompt/index.d.ts} +2 -2
- package/dist/agent/chat/prompt/index.d.ts.map +1 -0
- package/dist/agent/chat/{prompt.js → prompt/index.js} +17 -64
- package/dist/agent/chat/prompt/pw-utils-docs.d.ts +2 -0
- package/dist/agent/chat/prompt/pw-utils-docs.d.ts.map +1 -0
- package/dist/agent/chat/prompt/pw-utils-docs.js +62 -0
- package/dist/agent/chat/{repo.d.ts → prompt/repo.d.ts} +1 -1
- package/dist/agent/chat/prompt/repo.d.ts.map +1 -0
- package/dist/agent/chat/{repo.js → prompt/repo.js} +1 -1
- package/dist/agent/cua/pw-codegen/pw-pause/for-recorder.d.ts +14 -0
- package/dist/agent/cua/pw-codegen/pw-pause/for-recorder.d.ts.map +1 -0
- package/dist/agent/cua/pw-codegen/pw-pause/for-recorder.js +62 -0
- package/dist/agent/cua/pw-codegen/pw-pause/index.d.ts.map +1 -1
- package/dist/agent/cua/pw-codegen/pw-pause/index.js +19 -15
- package/dist/agent/cua/pw-codegen/pw-pause/patch.d.ts +7 -4
- package/dist/agent/cua/pw-codegen/pw-pause/patch.d.ts.map +1 -1
- package/dist/agent/cua/pw-codegen/pw-pause/patch.js +51 -24
- package/dist/agent/cua/pw-codegen/pw-pause/types.d.ts +14 -0
- package/dist/agent/cua/pw-codegen/pw-pause/types.d.ts.map +1 -0
- package/dist/agent/cua/pw-codegen/pw-pause/types.js +2 -0
- package/dist/artifacts/utils.d.ts +1 -1
- package/dist/artifacts/utils.d.ts.map +1 -1
- package/dist/artifacts/utils.js +19 -8
- package/dist/bin/index.js +7 -1
- package/dist/bin/utils/index.d.ts +2 -1
- package/dist/bin/utils/index.d.ts.map +1 -1
- package/dist/bin/utils/index.js +34 -5
- package/dist/browser-injected-scripts/annotate-elements.js +1 -4
- package/dist/file/client.d.ts +1 -0
- package/dist/file/client.d.ts.map +1 -1
- package/dist/file/client.js +3 -0
- package/dist/file/server.d.ts +2 -0
- package/dist/file/server.d.ts.map +1 -1
- package/dist/file/server.js +9 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -0
- package/dist/recorder/display.d.ts +2 -0
- package/dist/recorder/display.d.ts.map +1 -0
- package/dist/recorder/display.js +50 -0
- package/dist/recorder/index.d.ts +4 -0
- package/dist/recorder/index.d.ts.map +1 -0
- package/dist/recorder/index.js +108 -0
- package/dist/recorder/request.d.ts +6 -0
- package/dist/recorder/request.d.ts.map +1 -0
- package/dist/recorder/request.js +55 -0
- package/dist/recorder/temp-files.d.ts +3 -0
- package/dist/recorder/temp-files.d.ts.map +1 -0
- package/dist/recorder/temp-files.js +39 -0
- package/dist/recorder/upload.d.ts +2 -0
- package/dist/recorder/upload.d.ts.map +1 -0
- package/dist/recorder/upload.js +85 -0
- package/dist/recorder/validation.d.ts +2 -0
- package/dist/recorder/validation.d.ts.map +1 -0
- package/dist/recorder/validation.js +24 -0
- package/dist/uploader/index.d.ts.map +1 -1
- package/dist/uploader/index.js +1 -0
- package/package.json +6 -6
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/agent/chat/prompt.d.ts.map +0 -1
- package/dist/agent/chat/repo.d.ts.map +0 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type SourcesPayload = {
|
|
2
|
+
isRecorded: boolean;
|
|
3
|
+
label: "library";
|
|
4
|
+
group: "Node.js";
|
|
5
|
+
id: "javascript";
|
|
6
|
+
text: string;
|
|
7
|
+
header: string;
|
|
8
|
+
footer: string;
|
|
9
|
+
actions: string[];
|
|
10
|
+
language: "javascript";
|
|
11
|
+
revealLine: number;
|
|
12
|
+
highlight: string[];
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/agent/cua/pw-codegen/pw-pause/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;IACjB,EAAE,EAAE,YAAY,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,YAAY,CAAC;IAEvB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC"}
|
|
@@ -5,7 +5,7 @@ import { JSONReport as PlaywrightJSONReport } from "@playwright/test/reporter";
|
|
|
5
5
|
* @param report The Playwright JSON report to extract attachments from
|
|
6
6
|
* @returns An array of objects containing path and contentType for each attachment
|
|
7
7
|
*/
|
|
8
|
-
export declare function extractAttachmentsFromPlaywrightJSONReport(report: PlaywrightJSONReport): ArtifactInputPath[];
|
|
8
|
+
export declare function extractAttachmentsFromPlaywrightJSONReport(report: PlaywrightJSONReport, testNameFilter?: string): ArtifactInputPath[];
|
|
9
9
|
/**
|
|
10
10
|
* Scans the given repository directory for Playwright artifacts (attachments) by:
|
|
11
11
|
* - Constructing the path to the Playwright report directory using the provided repoDir.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/artifacts/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EACL,UAAU,IAAI,oBAAoB,EAGnC,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/artifacts/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EACL,UAAU,IAAI,oBAAoB,EAGnC,MAAM,2BAA2B,CAAC;AAInC;;;;GAIG;AACH,wBAAgB,0CAA0C,CACxD,MAAM,EAAE,oBAAoB,EAC5B,cAAc,CAAC,EAAE,MAAM,GACtB,iBAAiB,EAAE,CA2DrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAmCxE"}
|
package/dist/artifacts/utils.js
CHANGED
|
@@ -6,12 +6,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.extractAttachmentsFromPlaywrightJSONReport = extractAttachmentsFromPlaywrightJSONReport;
|
|
7
7
|
exports.findPlaywrightArtifacts = findPlaywrightArtifacts;
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
9
10
|
/**
|
|
10
11
|
* Extracts attachment information from a Playwright JSON report.
|
|
11
12
|
* @param report The Playwright JSON report to extract attachments from
|
|
12
13
|
* @returns An array of objects containing path and contentType for each attachment
|
|
13
14
|
*/
|
|
14
|
-
function extractAttachmentsFromPlaywrightJSONReport(report) {
|
|
15
|
+
function extractAttachmentsFromPlaywrightJSONReport(report, testNameFilter) {
|
|
15
16
|
const attachments = [];
|
|
16
17
|
if (!report || !report.suites || report.suites.length === 0) {
|
|
17
18
|
return attachments;
|
|
@@ -25,6 +26,9 @@ function extractAttachmentsFromPlaywrightJSONReport(report) {
|
|
|
25
26
|
if (!spec.tests) {
|
|
26
27
|
return;
|
|
27
28
|
}
|
|
29
|
+
if (testNameFilter && !testTitle.includes(testNameFilter)) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
28
32
|
for (const test of spec.tests) {
|
|
29
33
|
if (!test.results) {
|
|
30
34
|
continue;
|
|
@@ -37,7 +41,7 @@ function extractAttachmentsFromPlaywrightJSONReport(report) {
|
|
|
37
41
|
// Only collect attachments that have a 'path' (i.e., not embedded content)
|
|
38
42
|
if (attachment.path && attachment.contentType) {
|
|
39
43
|
attachments.push({
|
|
40
|
-
name: `${testTitle} ${attachment.name}`,
|
|
44
|
+
name: `${testTitle} - ${attachment.name}`,
|
|
41
45
|
path: attachment.path,
|
|
42
46
|
contentType: attachment.contentType,
|
|
43
47
|
});
|
|
@@ -55,19 +59,16 @@ function extractAttachmentsFromPlaywrightJSONReport(report) {
|
|
|
55
59
|
return;
|
|
56
60
|
}
|
|
57
61
|
for (const suite of suites) {
|
|
58
|
-
// Process specs directly within the current suite
|
|
59
62
|
if (suite.specs) {
|
|
60
63
|
for (const spec of suite.specs) {
|
|
61
64
|
processSpec(spec);
|
|
62
65
|
}
|
|
63
66
|
}
|
|
64
|
-
// Recursively call for any nested suites
|
|
65
67
|
if (suite.suites) {
|
|
66
68
|
traverseSuites(suite.suites);
|
|
67
69
|
}
|
|
68
70
|
}
|
|
69
71
|
}
|
|
70
|
-
// Start the recursive traversal from the top-level suites
|
|
71
72
|
traverseSuites(report.suites);
|
|
72
73
|
return attachments;
|
|
73
74
|
}
|
|
@@ -84,9 +85,19 @@ function extractAttachmentsFromPlaywrightJSONReport(report) {
|
|
|
84
85
|
*/
|
|
85
86
|
function findPlaywrightArtifacts(repoDir) {
|
|
86
87
|
const artifacts = [];
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
|
|
88
|
+
const pathForPlaywright147 = path_1.default.join(repoDir, "playwright-report", "summary.json");
|
|
89
|
+
const pathForPlaywright153 = path_1.default.join(repoDir, "summary.json");
|
|
90
|
+
let summaryJsonPath;
|
|
91
|
+
if (fs_1.default.existsSync(pathForPlaywright147)) {
|
|
92
|
+
summaryJsonPath = pathForPlaywright147;
|
|
93
|
+
}
|
|
94
|
+
else if (fs_1.default.existsSync(pathForPlaywright153)) {
|
|
95
|
+
summaryJsonPath = pathForPlaywright153;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
console.warn(`[findPlaywrightArtifacts] No Playwright report found in ${repoDir}`);
|
|
99
|
+
}
|
|
100
|
+
if (summaryJsonPath) {
|
|
90
101
|
try {
|
|
91
102
|
const summaryJson = JSON.parse(fs_1.default.readFileSync(summaryJsonPath, "utf-8"));
|
|
92
103
|
const found = extractAttachmentsFromPlaywrightJSONReport(summaryJson);
|
package/dist/bin/index.js
CHANGED
|
@@ -16,6 +16,7 @@ const diagnosis_agent_1 = require("../agent/diagnosis-agent");
|
|
|
16
16
|
const enrich_prompt_1 = require("../agent/enrich-prompt");
|
|
17
17
|
const infer_agent_1 = require("../agent/infer-agent");
|
|
18
18
|
const run_3 = require("../agent/planner/run");
|
|
19
|
+
const recorder_1 = require("../recorder");
|
|
19
20
|
const reporter_1 = require("../reporter");
|
|
20
21
|
const session_1 = require("../session");
|
|
21
22
|
const test_build_1 = require("../test-build");
|
|
@@ -200,7 +201,7 @@ async function runAgentsWorkflow(testGenConfig, testGenToken) {
|
|
|
200
201
|
}
|
|
201
202
|
async function main() {
|
|
202
203
|
const removeListeners = setupProcessListeners(flushEvents);
|
|
203
|
-
(0, utils_2.printBanner)();
|
|
204
|
+
await (0, utils_2.printBanner)();
|
|
204
205
|
const program = new commander_1.Command();
|
|
205
206
|
program
|
|
206
207
|
.option("--token <token>", "Test generation token")
|
|
@@ -209,6 +210,7 @@ async function main() {
|
|
|
209
210
|
.option("--file <test-file>", "File path of the test case (inside tests dir)")
|
|
210
211
|
.option("--suites <suites>", "Comma separated list of describe blocks")
|
|
211
212
|
.option("--use-chat", "Use chat agent (and not the workflow)")
|
|
213
|
+
.option("--use-recorder", "Run the recorder flow to create a request")
|
|
212
214
|
.option("--chat-session-id <chat-session-id>", "Identifier for chat session (fetched from dash.empirical.run)")
|
|
213
215
|
.option("--use-disk-for-chat-state", "Save and load chat state from disk")
|
|
214
216
|
.option("--chat-model <model>", "Chat model to use (claude-3-7-sonnet-20250219 or claude-3-5-sonnet-20241022 or gemini-2.5-pro-preview-06-05)")
|
|
@@ -242,6 +244,10 @@ async function main() {
|
|
|
242
244
|
apiKey: process.env.EMPIRICALRUN_API_KEY,
|
|
243
245
|
});
|
|
244
246
|
}
|
|
247
|
+
if (completedOptions.useRecorder) {
|
|
248
|
+
await (0, recorder_1.runRecorder)({ name: completedOptions.name });
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
245
251
|
if (completedOptions.useChat) {
|
|
246
252
|
await runChatAgent({
|
|
247
253
|
chatSessionId: completedOptions.chatSessionId,
|
|
@@ -11,7 +11,8 @@ export interface CLIOptions {
|
|
|
11
11
|
initialPrompt?: string;
|
|
12
12
|
chatSessionId?: string;
|
|
13
13
|
chatModel?: (typeof ARGS_TO_MODEL_MAP)[keyof typeof ARGS_TO_MODEL_MAP];
|
|
14
|
+
useRecorder?: boolean;
|
|
14
15
|
}
|
|
15
16
|
export declare function validateAndCompleteCliOptions(options: CLIOptions): Promise<CLIOptions>;
|
|
16
|
-
export declare function printBanner(): void
|
|
17
|
+
export declare function printBanner(): Promise<void>;
|
|
17
18
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bin/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bin/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAKjE,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAgBjE,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC;IAGvE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAQD,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,UAAU,CAAC,CA8DrB;AAeD,wBAAsB,WAAW,kBAgDhC"}
|
package/dist/bin/utils/index.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.ARGS_TO_MODEL_MAP = void 0;
|
|
|
7
7
|
exports.validateAndCompleteCliOptions = validateAndCompleteCliOptions;
|
|
8
8
|
exports.printBanner = printBanner;
|
|
9
9
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
|
+
const PACKAGE_NAME = "@empiricalrun/test-gen";
|
|
10
11
|
exports.ARGS_TO_MODEL_MAP = {
|
|
11
12
|
"claude-3-5": "claude-3-5-sonnet-20241022",
|
|
12
13
|
"claude-3-7": "claude-3-7-sonnet-20250219",
|
|
@@ -32,6 +33,9 @@ async function validateAndCompleteCliOptions(options) {
|
|
|
32
33
|
// Chat agent can prompt the user directly, nothing is required in CLI args
|
|
33
34
|
requiredFields = [];
|
|
34
35
|
}
|
|
36
|
+
if (options.useRecorder) {
|
|
37
|
+
requiredFields = ["name"];
|
|
38
|
+
}
|
|
35
39
|
const questions = [];
|
|
36
40
|
if (!options.name && requiredFields.includes("name")) {
|
|
37
41
|
questions.push({
|
|
@@ -76,7 +80,19 @@ async function validateAndCompleteCliOptions(options) {
|
|
|
76
80
|
}
|
|
77
81
|
return options;
|
|
78
82
|
}
|
|
79
|
-
function
|
|
83
|
+
async function getLatestVersion(packageName) {
|
|
84
|
+
try {
|
|
85
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`);
|
|
86
|
+
if (!response.ok)
|
|
87
|
+
return null;
|
|
88
|
+
const data = await response.json();
|
|
89
|
+
return data.version;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function printBanner() {
|
|
80
96
|
const gray = "\x1b[90m";
|
|
81
97
|
const reset = "\x1b[0m";
|
|
82
98
|
const asciiArtRaw = `
|
|
@@ -85,7 +101,17 @@ function printBanner() {
|
|
|
85
101
|
/)__)
|
|
86
102
|
--"-"-`;
|
|
87
103
|
const version = require("../../../package.json").version;
|
|
88
|
-
const
|
|
104
|
+
const latestVersion = await getLatestVersion(PACKAGE_NAME);
|
|
105
|
+
let versionSuffix = "";
|
|
106
|
+
if (latestVersion) {
|
|
107
|
+
if (version === latestVersion) {
|
|
108
|
+
versionSuffix = ` ${gray}(latest)${reset}`;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
versionSuffix = ` (latest is ${latestVersion})`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const logLine1 = `Running ${PACKAGE_NAME} v${version}${versionSuffix}`;
|
|
89
115
|
const logLine2 = `from ${__dirname.split("/bin/utils")[0]}`;
|
|
90
116
|
// Process ASCII art
|
|
91
117
|
const asciiLines = asciiArtRaw
|
|
@@ -94,20 +120,23 @@ function printBanner() {
|
|
|
94
120
|
const maxWidth = Math.max(...asciiLines.map((line) => line.length));
|
|
95
121
|
const middleIndex = Math.floor(asciiLines.length / 2);
|
|
96
122
|
const spacing = " "; // 4 spaces for padding
|
|
123
|
+
const leftPadding = " "; // Left padding
|
|
124
|
+
console.log(""); // Top padding
|
|
97
125
|
// Print formatted output (art default, logs gray)
|
|
98
126
|
asciiLines.forEach((line, index) => {
|
|
99
127
|
const paddedLine = line.padEnd(maxWidth, " ");
|
|
100
128
|
if (index === middleIndex) {
|
|
101
129
|
// Print art line (default color) + first log line (gray)
|
|
102
|
-
console.log(`${paddedLine}${spacing}${gray}${logLine1}${reset}`);
|
|
130
|
+
console.log(`${leftPadding}${paddedLine}${spacing}${gray}${logLine1}${reset}`);
|
|
103
131
|
}
|
|
104
132
|
else if (index === middleIndex + 1) {
|
|
105
133
|
// Print corresponding art line (default color) + second log line (gray)
|
|
106
|
-
console.log(`${paddedLine}${spacing}${gray}${logLine2}${reset}`);
|
|
134
|
+
console.log(`${leftPadding}${paddedLine}${spacing}${gray}${logLine2}${reset}`);
|
|
107
135
|
}
|
|
108
136
|
else {
|
|
109
137
|
// Print other art lines (default color)
|
|
110
|
-
console.log(paddedLine);
|
|
138
|
+
console.log(`${leftPadding}${paddedLine}`);
|
|
111
139
|
}
|
|
112
140
|
});
|
|
141
|
+
console.log(""); // Bottom padding
|
|
113
142
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/* eslint-disable autofix/no-unused-vars */
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Annotates all clickable elements on the page with unique hint markers.
|
|
5
3
|
* Returns an object containing annotations and methods to enable/disable them.
|
|
@@ -10,6 +8,7 @@
|
|
|
10
8
|
* @param {string} options.markerClass - CSS class to apply to hint markers.
|
|
11
9
|
* @returns {Object} An object containing annotations map and enable/disable methods.
|
|
12
10
|
*/
|
|
11
|
+
// eslint-disable-next-line no-unused-vars, autofix/no-unused-vars
|
|
13
12
|
function annotateElementsWithPreference({
|
|
14
13
|
options = {},
|
|
15
14
|
preference = {},
|
|
@@ -32,8 +31,6 @@ function annotateElementsWithPreference({
|
|
|
32
31
|
// Check if the element is not blocked and visible for clicking
|
|
33
32
|
function isElementClickNotBlocked(element, windowToAnnotate) {
|
|
34
33
|
const rect = element.getBoundingClientRect();
|
|
35
|
-
const originalScrollX = windowToAnnotate.scrollX;
|
|
36
|
-
const originalScrollY = windowToAnnotate.scrollY;
|
|
37
34
|
|
|
38
35
|
// Calculate the center point of the element
|
|
39
36
|
const centerX = rect.left + rect.width / 2;
|
package/dist/file/client.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ declare class FileServiceClient {
|
|
|
5
5
|
constructor();
|
|
6
6
|
static isAvailable(): boolean;
|
|
7
7
|
sendAgentResult(payload: BrowserAgentIPCPayload): Promise<any>;
|
|
8
|
+
sendCodegenSources(payload: any): Promise<any>;
|
|
8
9
|
post(path: string, body: any): Promise<any>;
|
|
9
10
|
}
|
|
10
11
|
export default FileServiceClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/file/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAElD,cAAM,iBAAiB;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;;IAUzB,MAAM,CAAC,WAAW;IAIZ,eAAe,CAAC,OAAO,EAAE,sBAAsB;IAI/C,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG;CAgBnC;AAED,eAAe,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/file/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAElD,cAAM,iBAAiB;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;;IAUzB,MAAM,CAAC,WAAW;IAIZ,eAAe,CAAC,OAAO,EAAE,sBAAsB;IAI/C,kBAAkB,CAAC,OAAO,EAAE,GAAG;IAI/B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG;CAgBnC;AAED,eAAe,iBAAiB,CAAC"}
|
package/dist/file/client.js
CHANGED
|
@@ -16,6 +16,9 @@ class FileServiceClient {
|
|
|
16
16
|
async sendAgentResult(payload) {
|
|
17
17
|
return this.post("/agent-results", payload);
|
|
18
18
|
}
|
|
19
|
+
async sendCodegenSources(payload) {
|
|
20
|
+
return this.post("/codegen-sources", payload);
|
|
21
|
+
}
|
|
19
22
|
async post(path, body) {
|
|
20
23
|
const resp = await fetch(`${this.baseUrl}${path}`, {
|
|
21
24
|
method: "POST",
|
package/dist/file/server.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export declare class FileServiceServer {
|
|
|
17
17
|
private artifactsInputs;
|
|
18
18
|
private result;
|
|
19
19
|
private usage;
|
|
20
|
+
private codegenSources;
|
|
20
21
|
constructor({ port, repoDir, updateFile, onComplete, }: {
|
|
21
22
|
port: number;
|
|
22
23
|
repoDir: string;
|
|
@@ -28,6 +29,7 @@ export declare class FileServiceServer {
|
|
|
28
29
|
usage: Usage | undefined;
|
|
29
30
|
};
|
|
30
31
|
getArtifactInputsFromServer(): ArtifactInput[];
|
|
32
|
+
getCodegenSources(): string | undefined;
|
|
31
33
|
setFilePath(filePath: string): void;
|
|
32
34
|
startFileService(): Promise<number>;
|
|
33
35
|
stop(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/file/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAKlE,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/file/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAKlE,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AASlD,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,kBAAkB,CAAC;IAC3B,KAAK,EAAE,KAAK,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAEF,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,MAAM,CAA4C;IAC1D,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,UAAU,CAAC,CAAa;IAEhC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,KAAK,CAAoB;IAEjC,OAAO,CAAC,cAAc,CAAqB;gBAE/B,EACV,IAAI,EACJ,OAAO,EACP,UAAU,EACV,UAAU,GACX,EAAE;QACD,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,OAAO,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;KACzB;IAOD,iBAAiB;;;;IAIjB,2BAA2B;IAI3B,iBAAiB;IAIjB,WAAW,CAAC,QAAQ,EAAE,MAAM;IAItB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IAqEnC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB5B"}
|
package/dist/file/server.js
CHANGED
|
@@ -19,6 +19,7 @@ class FileServiceServer {
|
|
|
19
19
|
artifactsInputs = [];
|
|
20
20
|
result;
|
|
21
21
|
usage;
|
|
22
|
+
codegenSources;
|
|
22
23
|
constructor({ port, repoDir, updateFile, onComplete, }) {
|
|
23
24
|
this.port = port;
|
|
24
25
|
this.repoDir = repoDir;
|
|
@@ -31,6 +32,9 @@ class FileServiceServer {
|
|
|
31
32
|
getArtifactInputsFromServer() {
|
|
32
33
|
return this.artifactsInputs;
|
|
33
34
|
}
|
|
35
|
+
getCodegenSources() {
|
|
36
|
+
return this.codegenSources;
|
|
37
|
+
}
|
|
34
38
|
setFilePath(filePath) {
|
|
35
39
|
this.filePath = path_1.default.resolve(this.repoDir, filePath);
|
|
36
40
|
}
|
|
@@ -38,6 +42,11 @@ class FileServiceServer {
|
|
|
38
42
|
const app = (0, express_1.default)();
|
|
39
43
|
app.use(express_1.default.json({ limit: "50mb" }));
|
|
40
44
|
(0, ipc_1.humanLoopRoute)(app);
|
|
45
|
+
app.post("/codegen-sources", async (req) => {
|
|
46
|
+
const payload = req.body;
|
|
47
|
+
this.codegenSources = payload.map((c) => c.actions.join("\n")).join("\n");
|
|
48
|
+
console.log("[FileServiceServer] Received codegen sources", this.codegenSources);
|
|
49
|
+
});
|
|
41
50
|
app.post("/agent-results", async (req, res) => {
|
|
42
51
|
const { generatedCode, importPaths, result, usage } = req.body;
|
|
43
52
|
this.result = result;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,4 +2,5 @@ import { FrameLocator, Page } from "playwright";
|
|
|
2
2
|
import { ScopeVars } from "./types";
|
|
3
3
|
export { downloadBuild } from "./test-build";
|
|
4
4
|
export declare function createTest(task: string, pageRef: Page | FrameLocator, scope?: ScopeVars): Promise<void>;
|
|
5
|
+
export declare function recordTest(pageRef: Page): Promise<void>;
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAahD,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAsB7C,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,IAAI,GAAG,YAAY,EAC5B,KAAK,CAAC,EAAE,SAAS,iBAwElB;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,IAAI,iBAY7C"}
|
package/dist/index.js
CHANGED
|
@@ -5,8 +5,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.downloadBuild = void 0;
|
|
7
7
|
exports.createTest = createTest;
|
|
8
|
+
exports.recordTest = recordTest;
|
|
8
9
|
const llm_1 = require("@empiricalrun/llm");
|
|
9
10
|
const cua_1 = require("./agent/cua");
|
|
11
|
+
const pw_pause_1 = require("./agent/cua/pw-codegen/pw-pause");
|
|
12
|
+
const for_recorder_1 = require("./agent/cua/pw-codegen/pw-pause/for-recorder");
|
|
10
13
|
const run_1 = require("./agent/master/run");
|
|
11
14
|
const scenarios_1 = require("./bin/utils/scenarios");
|
|
12
15
|
const client_1 = __importDefault(require("./file/client"));
|
|
@@ -94,3 +97,16 @@ async function createTest(task, pageRef, scope) {
|
|
|
94
97
|
await flushEvents();
|
|
95
98
|
}
|
|
96
99
|
}
|
|
100
|
+
async function recordTest(pageRef) {
|
|
101
|
+
const fileServiceClient = new client_1.default();
|
|
102
|
+
const repoDir = process.cwd();
|
|
103
|
+
const canUsePwPause = await (0, pw_pause_1.canUsePauseCodegen)(repoDir);
|
|
104
|
+
if (!canUsePwPause) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
console.log("[getCodegen] using PlaywrightPauseCodegen");
|
|
108
|
+
const codegen = new for_recorder_1.PlaywrightPauseCodegenForRecorder(async (sources) => {
|
|
109
|
+
await fileServiceClient.sendCodegenSources(sources);
|
|
110
|
+
});
|
|
111
|
+
await codegen.initialize(pageRef);
|
|
112
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../src/recorder/display.ts"],"names":[],"mappings":"AAEA,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,mBA+CtB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.displayResultsAndConfirm = displayResultsAndConfirm;
|
|
7
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
|
+
async function displayResultsAndConfirm(name, codegenResult) {
|
|
9
|
+
let finalResult = codegenResult || "No code generated";
|
|
10
|
+
let approved = false;
|
|
11
|
+
while (!approved) {
|
|
12
|
+
// Display results in a box format
|
|
13
|
+
console.log("\n" + "=".repeat(80));
|
|
14
|
+
console.log("📝 TEST GENERATION RESULTS");
|
|
15
|
+
console.log("=".repeat(80));
|
|
16
|
+
console.log(`Test Name: ${name}`);
|
|
17
|
+
console.log("-".repeat(80));
|
|
18
|
+
console.log("Generated Code:");
|
|
19
|
+
console.log("-".repeat(80));
|
|
20
|
+
console.log(finalResult);
|
|
21
|
+
console.log("=".repeat(80));
|
|
22
|
+
// Ask user for confirmation
|
|
23
|
+
const { confirmed } = await inquirer_1.default.prompt([
|
|
24
|
+
{
|
|
25
|
+
type: "confirm",
|
|
26
|
+
name: "confirmed",
|
|
27
|
+
message: "Does this look good to you?",
|
|
28
|
+
default: true,
|
|
29
|
+
},
|
|
30
|
+
]);
|
|
31
|
+
if (confirmed) {
|
|
32
|
+
console.log("✅ Great! The test generation was successful.");
|
|
33
|
+
approved = true;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// Open multiline editor for user to modify
|
|
37
|
+
const { editedCode } = await inquirer_1.default.prompt([
|
|
38
|
+
{
|
|
39
|
+
type: "editor",
|
|
40
|
+
name: "editedCode",
|
|
41
|
+
message: "Edit the generated code:",
|
|
42
|
+
default: finalResult,
|
|
43
|
+
},
|
|
44
|
+
]);
|
|
45
|
+
finalResult = editedCode;
|
|
46
|
+
console.log("Code updated. Let's review the changes...");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return finalResult;
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/recorder/index.ts"],"names":[],"mappings":"AAyCA,wBAAsB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,iBAiF3D"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runRecorder = runRecorder;
|
|
7
|
+
const test_run_1 = require("@empiricalrun/test-run");
|
|
8
|
+
const detect_port_1 = __importDefault(require("detect-port"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const utils_1 = require("../agent/browsing/utils");
|
|
12
|
+
const chat_1 = require("../agent/chat");
|
|
13
|
+
const pw_pause_1 = require("../agent/cua/pw-codegen/pw-pause");
|
|
14
|
+
const utils_2 = require("../artifacts/utils");
|
|
15
|
+
const server_1 = require("../file/server");
|
|
16
|
+
const display_1 = require("./display");
|
|
17
|
+
const request_1 = require("./request");
|
|
18
|
+
const temp_files_1 = require("./temp-files");
|
|
19
|
+
const upload_1 = require("./upload");
|
|
20
|
+
const validation_1 = require("./validation");
|
|
21
|
+
function extractVideoAttachments(repoDir) {
|
|
22
|
+
try {
|
|
23
|
+
const summaryPath = path_1.default.join(repoDir, "summary.json");
|
|
24
|
+
if (!fs_1.default.existsSync(summaryPath)) {
|
|
25
|
+
console.log("summary.json not found");
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
const summaryContent = JSON.parse(fs_1.default.readFileSync(summaryPath, "utf-8"));
|
|
29
|
+
const attachments = (0, utils_2.extractAttachmentsFromPlaywrightJSONReport)(summaryContent, "temp test");
|
|
30
|
+
const videoPaths = attachments
|
|
31
|
+
.filter((attachment) => attachment.contentType === "video/webm")
|
|
32
|
+
.map((attachment) => attachment.path);
|
|
33
|
+
return videoPaths;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
console.warn("Error processing summary.json:", error);
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function runRecorder({ name }) {
|
|
41
|
+
console.log(`Recording for test name: ${name}`);
|
|
42
|
+
const repoDir = process.cwd();
|
|
43
|
+
try {
|
|
44
|
+
await (0, validation_1.validate)(repoDir);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
console.error("Error running recorder:", error);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
if (!process.env.EMPIRICALRUN_API_KEY) {
|
|
51
|
+
console.error("EMPIRICALRUN_API_KEY is not set. Please set it in your environment variables.");
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
// Prepare playwright for codegen
|
|
56
|
+
console.log("[generateTestWithBrowserAgent] Preparing playwright for codegen");
|
|
57
|
+
await (0, pw_pause_1.preparePlaywrightForCodegen)(repoDir);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
console.warn("[generateTestWithBrowserAgent] Error preparing playwright for codegen", err);
|
|
61
|
+
}
|
|
62
|
+
const envVariables = await (0, chat_1.fetchEnvironmentVariables)();
|
|
63
|
+
await (0, temp_files_1.createTempTestFile)();
|
|
64
|
+
const absFilePath = path_1.default.join(process.cwd(), "tests", "temp-test.spec.ts");
|
|
65
|
+
await (0, utils_1.addImportForMethod)(absFilePath, "recordTest");
|
|
66
|
+
// Start a file service for IPC with the agent (which runs in a different process)
|
|
67
|
+
const availablePort = await (0, detect_port_1.default)(3030);
|
|
68
|
+
const fileServer = new server_1.FileServiceServer({
|
|
69
|
+
port: availablePort,
|
|
70
|
+
repoDir,
|
|
71
|
+
updateFile: false,
|
|
72
|
+
});
|
|
73
|
+
await fileServer.startFileService();
|
|
74
|
+
await (0, test_run_1.runSingleTest)({
|
|
75
|
+
testName: "temp test",
|
|
76
|
+
suites: [],
|
|
77
|
+
filePath: "tests/temp-test.spec.ts",
|
|
78
|
+
projects: ["chromium"],
|
|
79
|
+
repoDir: process.cwd(),
|
|
80
|
+
envOverrides: {
|
|
81
|
+
...envVariables,
|
|
82
|
+
RUN_PLAYWRIGHT_HEADED: "true",
|
|
83
|
+
PW_CODEGEN_NO_INSPECTOR: "1",
|
|
84
|
+
IPC_FILE_SERVICE_PORT: availablePort.toString(),
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
const videoPaths = extractVideoAttachments(repoDir);
|
|
88
|
+
let attachments = [];
|
|
89
|
+
if (videoPaths.length === 0) {
|
|
90
|
+
console.warn("No video attachments found for temp test");
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const videoUrls = await (0, upload_1.uploadVideosWithSpinner)(videoPaths, name);
|
|
94
|
+
if (videoUrls) {
|
|
95
|
+
attachments = [...attachments, ...videoUrls];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
await (0, temp_files_1.deleteTempTestFile)();
|
|
99
|
+
await (0, pw_pause_1.revertToOriginalPwCode)(repoDir);
|
|
100
|
+
const codegenResult = fileServer.getCodegenSources();
|
|
101
|
+
await fileServer.stop();
|
|
102
|
+
const finalCode = await (0, display_1.displayResultsAndConfirm)(name, codegenResult);
|
|
103
|
+
await (0, request_1.sendToDashboardAsRequest)({
|
|
104
|
+
testName: name,
|
|
105
|
+
codegenResult: finalCode,
|
|
106
|
+
attachments,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/recorder/request.ts"],"names":[],"mappings":"AAeA,wBAAsB,wBAAwB,CAAC,EAC7C,QAAQ,EACR,aAAa,EACb,WAAW,GACZ,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,iBAKA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendToDashboardAsRequest = sendToDashboardAsRequest;
|
|
4
|
+
const DASHBOARD_DOMAIN = process.env.DASHBOARD_DOMAIN || "https://dash.empirical.run";
|
|
5
|
+
const title = (name) => `Add a test: ${name}`;
|
|
6
|
+
function description(codegenResult, attachments) {
|
|
7
|
+
return [
|
|
8
|
+
`To add this test, refer to the following code that was captured using playwright codegen. Make modifications that you need to make to convert this into a test case that sits well with other tests in this repository.`,
|
|
9
|
+
`Codegen result:`,
|
|
10
|
+
codegenResult,
|
|
11
|
+
`Other attachments:`,
|
|
12
|
+
...attachments,
|
|
13
|
+
].join("\n\n");
|
|
14
|
+
}
|
|
15
|
+
async function sendToDashboardAsRequest({ testName, codegenResult, attachments, }) {
|
|
16
|
+
return createRequest({
|
|
17
|
+
title: title(testName),
|
|
18
|
+
description: description(codegenResult, attachments),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async function createRequest({ title, description, }) {
|
|
22
|
+
if (!DASHBOARD_DOMAIN) {
|
|
23
|
+
console.warn("DASHBOARD_DOMAIN not set, skipping request creation");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (!process.env.EMPIRICALRUN_API_KEY) {
|
|
27
|
+
console.warn("EMPIRICALRUN_API_KEY not set, skipping request creation");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const source = "cli";
|
|
32
|
+
const sourceIdentifier = "random-string";
|
|
33
|
+
const response = await fetch(`${DASHBOARD_DOMAIN}/api/requests`, {
|
|
34
|
+
method: "POST",
|
|
35
|
+
headers: {
|
|
36
|
+
"Content-Type": "application/json",
|
|
37
|
+
Authorization: `Bearer ${process.env.EMPIRICALRUN_API_KEY}`,
|
|
38
|
+
},
|
|
39
|
+
body: JSON.stringify({
|
|
40
|
+
source,
|
|
41
|
+
source_identifier: sourceIdentifier,
|
|
42
|
+
title,
|
|
43
|
+
description,
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
throw new Error(`Failed to create request: ${response.statusText}`);
|
|
48
|
+
}
|
|
49
|
+
const data = await response.json();
|
|
50
|
+
console.log("Request created successfully:", data);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.error("Failed to create request:", error);
|
|
54
|
+
}
|
|
55
|
+
}
|