@empiricalrun/test-gen 0.67.0 → 0.69.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 +23 -0
- package/dist/agent/chat/exports.d.ts +8 -8
- package/dist/agent/chat/exports.d.ts.map +1 -1
- package/dist/agent/chat/exports.js +10 -7
- package/dist/agent/chat/index.d.ts.map +1 -1
- package/dist/agent/chat/index.js +5 -2
- package/dist/agent/chat/state.d.ts +4 -2
- package/dist/agent/chat/state.d.ts.map +1 -1
- package/dist/agent/chat/state.js +10 -2
- package/dist/agent/chat/utils.d.ts +5 -1
- package/dist/agent/chat/utils.d.ts.map +1 -1
- package/dist/agent/chat/utils.js +22 -0
- package/dist/agent/cua/pw-codegen/pw-pause/for-recorder.d.ts.map +1 -1
- package/dist/agent/cua/pw-codegen/pw-pause/for-recorder.js +24 -3
- package/dist/agent/cua/pw-codegen/pw-pause/patch.d.ts.map +1 -1
- package/dist/agent/cua/pw-codegen/pw-pause/patch.js +4 -6
- package/dist/auth/api-client.d.ts +1 -2
- package/dist/auth/api-client.d.ts.map +1 -1
- package/dist/auth/api-client.js +15 -45
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +1 -4
- package/dist/bin/index.js +104 -108
- package/dist/bin/setup.d.ts +4 -0
- package/dist/bin/setup.d.ts.map +1 -0
- package/dist/bin/setup.js +86 -0
- package/dist/bin/utils/index.d.ts +2 -7
- package/dist/bin/utils/index.d.ts.map +1 -1
- package/dist/bin/utils/index.js +1 -9
- package/dist/file/server.js +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/logger.d.ts +3 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +11 -0
- package/dist/recorder/env-variables.d.ts +2 -0
- package/dist/recorder/env-variables.d.ts.map +1 -0
- package/dist/recorder/env-variables.js +29 -0
- package/dist/recorder/index.d.ts.map +1 -1
- package/dist/recorder/index.js +25 -34
- package/dist/recorder/request.d.ts +2 -1
- package/dist/recorder/request.d.ts.map +1 -1
- package/dist/recorder/request.js +15 -21
- package/dist/recorder/temp-files.d.ts.map +1 -1
- package/dist/recorder/temp-files.js +5 -4
- package/dist/recorder/upload.d.ts +1 -0
- package/dist/recorder/upload.d.ts.map +1 -1
- package/dist/recorder/upload.js +23 -11
- package/dist/recorder/validation.d.ts +1 -1
- package/dist/recorder/validation.d.ts.map +1 -1
- package/dist/recorder/validation.js +9 -4
- package/package.json +6 -4
- package/tsconfig.tsbuildinfo +1 -1
package/dist/bin/index.js
CHANGED
|
@@ -17,26 +17,18 @@ 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
19
|
const auth_1 = require("../auth");
|
|
20
|
+
const api_client_1 = require("../auth/api-client");
|
|
20
21
|
const recorder_1 = require("../recorder");
|
|
21
22
|
const reporter_1 = require("../reporter");
|
|
22
23
|
const session_1 = require("../session");
|
|
23
24
|
const test_build_1 = require("../test-build");
|
|
24
25
|
const logger_1 = require("./logger");
|
|
26
|
+
const setup_1 = require("./setup");
|
|
25
27
|
const utils_2 = require("./utils");
|
|
26
28
|
const scenarios_1 = require("./utils/scenarios");
|
|
27
29
|
dotenv_1.default.config({
|
|
28
30
|
path: [".env.local", ".env"],
|
|
29
31
|
});
|
|
30
|
-
const flushEvents = async () => {
|
|
31
|
-
await (0, llm_1.flushAllTraces)();
|
|
32
|
-
};
|
|
33
|
-
function setupProcessListeners(cleanup) {
|
|
34
|
-
const events = ["beforeExit", "exit", "SIGINT", "SIGTERM"];
|
|
35
|
-
events.forEach((event) => process.once(event, cleanup));
|
|
36
|
-
return () => {
|
|
37
|
-
events.forEach((event) => process.removeListener(event, cleanup));
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
32
|
async function runChatAgent({ modelInput, chatSessionId, useDiskForChatState, initialPromptPath, }) {
|
|
41
33
|
if (modelInput && !utils_2.ARGS_TO_MODEL_MAP[modelInput]) {
|
|
42
34
|
throw new Error(`Invalid chat model: ${modelInput}`);
|
|
@@ -201,13 +193,11 @@ async function runAgentsWorkflow(testGenConfig, testGenToken) {
|
|
|
201
193
|
return agent;
|
|
202
194
|
}
|
|
203
195
|
async function main() {
|
|
204
|
-
const removeListeners = setupProcessListeners(flushEvents);
|
|
205
196
|
await (0, utils_2.printBanner)();
|
|
206
197
|
const program = new commander_1.Command();
|
|
207
|
-
// Add authentication commands
|
|
208
198
|
program
|
|
209
199
|
.command("login")
|
|
210
|
-
.description("Authenticate with your Empirical
|
|
200
|
+
.description("Authenticate with your Empirical account")
|
|
211
201
|
.action(async () => {
|
|
212
202
|
console.log("🔐 Starting authentication...\n");
|
|
213
203
|
try {
|
|
@@ -232,7 +222,7 @@ async function main() {
|
|
|
232
222
|
});
|
|
233
223
|
program
|
|
234
224
|
.command("logout")
|
|
235
|
-
.description("Sign out of your Empirical
|
|
225
|
+
.description("Sign out of your Empirical account")
|
|
236
226
|
.action(async () => {
|
|
237
227
|
try {
|
|
238
228
|
await (0, auth_1.logout)();
|
|
@@ -265,118 +255,124 @@ async function main() {
|
|
|
265
255
|
console.error("❌ Error checking auth status:", error.message);
|
|
266
256
|
process.exit(1);
|
|
267
257
|
}
|
|
268
|
-
removeListeners();
|
|
269
|
-
await (0, llm_1.flushAllTraces)();
|
|
270
|
-
await (0, logger_1.waitForLogsToFlush)();
|
|
271
258
|
process.exit(0);
|
|
272
259
|
});
|
|
273
260
|
program
|
|
274
|
-
.command("
|
|
275
|
-
.description("
|
|
261
|
+
.command("record")
|
|
262
|
+
.description("Record a new test case")
|
|
263
|
+
.option("--name <string>", "Name of the test case")
|
|
264
|
+
.action(async (opts) => {
|
|
265
|
+
const options = await (0, utils_2.validateAndCompleteCliOptions)(opts, ["name"]);
|
|
266
|
+
await (0, recorder_1.runRecorder)({ name: options.name });
|
|
267
|
+
process.exit(0);
|
|
268
|
+
});
|
|
269
|
+
program
|
|
270
|
+
.command("repos")
|
|
271
|
+
.description("List your projects and repositories")
|
|
276
272
|
.action(async () => {
|
|
277
273
|
try {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
274
|
+
const response = await api_client_1.apiClient.request("/api/projects");
|
|
275
|
+
if (!response.ok) {
|
|
276
|
+
console.error("❌ Failed to fetch projects:", response.statusText);
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
const result = await response.json();
|
|
280
|
+
result.data.projects.forEach((project) => {
|
|
281
|
+
console.log(` ${project.repo_name}`);
|
|
282
|
+
});
|
|
282
283
|
}
|
|
283
284
|
catch (error) {
|
|
284
|
-
console.error("❌
|
|
285
|
-
if (error.message.includes("Authentication required")) {
|
|
286
|
-
console.log('\n💡 Tip: Run "npx @empiricalrun/test-gen login" to authenticate');
|
|
287
|
-
}
|
|
285
|
+
console.error("❌ Error fetching projects:", error.message);
|
|
288
286
|
process.exit(1);
|
|
289
287
|
}
|
|
290
|
-
removeListeners();
|
|
291
|
-
await (0, llm_1.flushAllTraces)();
|
|
292
|
-
await (0, logger_1.waitForLogsToFlush)();
|
|
293
288
|
process.exit(0);
|
|
294
289
|
});
|
|
295
290
|
program
|
|
296
|
-
.
|
|
297
|
-
.
|
|
298
|
-
.option("--
|
|
299
|
-
.option("--file <test-file>", "File path of the test case (inside tests dir)")
|
|
300
|
-
.option("--suites <suites>", "Comma separated list of describe blocks")
|
|
301
|
-
.option("--use-chat", "Use chat agent (and not the workflow)")
|
|
302
|
-
.option("--use-recorder", "Run the recorder flow to create a request")
|
|
303
|
-
.option("--chat-session-id <chat-session-id>", "Identifier for chat session (fetched from dash.empirical.run)")
|
|
291
|
+
.command("chat-agent")
|
|
292
|
+
.description("Run the chat agent")
|
|
293
|
+
.option("--chat-model <model>", "LLM to use (claude-3-7, claude-4 or gemini-2.5)")
|
|
304
294
|
.option("--use-disk-for-chat-state", "Save and load chat state from disk")
|
|
305
|
-
.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)")
|
|
306
295
|
.option("--initial-prompt <path>", "Path to an initial prompt file (e.g. prompt.md)")
|
|
307
|
-
.option("--
|
|
308
|
-
.
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
const testGenToken = completedOptions.token
|
|
317
|
-
? completedOptions.token
|
|
318
|
-
: (0, scenarios_1.buildTokenFromOptions)(completedOptions);
|
|
319
|
-
(0, reporter_1.setReporterConfig)({
|
|
320
|
-
projectRepoName: testGenConfig.options?.metadata.projectRepoName,
|
|
321
|
-
testSessionId: testGenConfig.options?.metadata.testSessionId,
|
|
322
|
-
generationId: testGenConfig.options?.metadata.generationId,
|
|
296
|
+
.option("--chat-session-id <chat-session-id>", "Identifier for chat session (fetched from dash.empirical.run)")
|
|
297
|
+
.action(async (options) => {
|
|
298
|
+
await runChatAgent({
|
|
299
|
+
chatSessionId: options.chatSessionId,
|
|
300
|
+
modelInput: options.chatModel,
|
|
301
|
+
useDiskForChatState: options.useDiskForChatState,
|
|
302
|
+
initialPromptPath: options.initialPrompt,
|
|
303
|
+
});
|
|
304
|
+
process.exit(0);
|
|
323
305
|
});
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
306
|
+
program
|
|
307
|
+
.command("setup")
|
|
308
|
+
.description("Clone a repository from your projects")
|
|
309
|
+
.option("--repo-name <string>", "Name of the repository to clone")
|
|
310
|
+
.action(async (opts) => {
|
|
311
|
+
const options = await (0, utils_2.validateAndCompleteCliOptions)(opts, ["repoName"]);
|
|
312
|
+
await (0, setup_1.runSetup)({ repoName: options.repoName });
|
|
313
|
+
process.exit(0);
|
|
329
314
|
});
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
useDiskForChatState: completedOptions.useDiskForChatState,
|
|
347
|
-
initialPromptPath: completedOptions.initialPrompt,
|
|
315
|
+
program
|
|
316
|
+
.command("legacy")
|
|
317
|
+
.description("Run the legacy workflows")
|
|
318
|
+
.option("-t, --token <token>", "Test generation token")
|
|
319
|
+
.action(async (opts) => {
|
|
320
|
+
const options = await (0, utils_2.validateAndCompleteCliOptions)(opts);
|
|
321
|
+
const testGenConfig = options.token
|
|
322
|
+
? (0, scenarios_1.loadTestConfigs)(options.token)
|
|
323
|
+
: (0, scenarios_1.buildTestConfigFromOptions)(options);
|
|
324
|
+
const testGenToken = options.token
|
|
325
|
+
? options.token
|
|
326
|
+
: (0, scenarios_1.buildTokenFromOptions)(options);
|
|
327
|
+
(0, reporter_1.setReporterConfig)({
|
|
328
|
+
projectRepoName: testGenConfig.options?.metadata.projectRepoName,
|
|
329
|
+
testSessionId: testGenConfig.options?.metadata.testSessionId,
|
|
330
|
+
generationId: testGenConfig.options?.metadata.generationId,
|
|
348
331
|
});
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
agentUsed = await runAgentsWorkflow(testGenConfig, testGenToken);
|
|
355
|
-
}
|
|
356
|
-
catch (e) {
|
|
357
|
-
testGenFailed = true;
|
|
358
|
-
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);
|
|
359
|
-
}
|
|
360
|
-
if (agentUsed &&
|
|
361
|
-
agentUsed !== "code" &&
|
|
362
|
-
agentUsed !== "plan" &&
|
|
363
|
-
testGenConfig.testCase.name &&
|
|
364
|
-
testGenConfig.options) {
|
|
365
|
-
await new reporter_1.TestGenUpdatesReporter().reportGenAssets({
|
|
366
|
-
projectRepoName: testGenConfig.options.metadata.projectRepoName,
|
|
367
|
-
testName: testGenConfig.testCase.name,
|
|
332
|
+
(0, session_1.setSessionDetails)({
|
|
333
|
+
testCaseId: testGenConfig.testCase.id,
|
|
334
|
+
sessionId: testGenConfig.options?.metadata.testSessionId,
|
|
335
|
+
generationId: testGenConfig.options?.metadata.generationId,
|
|
336
|
+
projectRepoName: testGenConfig.options?.metadata.projectRepoName,
|
|
368
337
|
});
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
338
|
+
if (testGenConfig.build?.url) {
|
|
339
|
+
// Download the build if repo has a download script
|
|
340
|
+
await (0, test_build_1.downloadBuild)({
|
|
341
|
+
buildUrl: testGenConfig.build.url,
|
|
342
|
+
repoPath: process.cwd(),
|
|
343
|
+
apiKey: process.env.EMPIRICALRUN_API_KEY,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
let agentUsed;
|
|
347
|
+
let testGenFailed = false;
|
|
348
|
+
try {
|
|
349
|
+
agentUsed = await runAgentsWorkflow(testGenConfig, testGenToken);
|
|
350
|
+
}
|
|
351
|
+
catch (e) {
|
|
352
|
+
testGenFailed = true;
|
|
353
|
+
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);
|
|
354
|
+
}
|
|
355
|
+
if (agentUsed &&
|
|
356
|
+
agentUsed !== "code" &&
|
|
357
|
+
agentUsed !== "plan" &&
|
|
358
|
+
testGenConfig.testCase.name &&
|
|
359
|
+
testGenConfig.options) {
|
|
360
|
+
await new reporter_1.TestGenUpdatesReporter().reportGenAssets({
|
|
361
|
+
projectRepoName: testGenConfig.options.metadata.projectRepoName,
|
|
362
|
+
testName: testGenConfig.testCase.name,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
await (0, llm_1.flushAllTraces)();
|
|
366
|
+
await (0, logger_1.waitForLogsToFlush)();
|
|
367
|
+
await (0, session_1.endSession)();
|
|
368
|
+
if (testGenFailed) {
|
|
369
|
+
process.exit(1);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
process.exit(0);
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
program.parse(process.argv);
|
|
380
376
|
}
|
|
381
377
|
main().catch((error) => {
|
|
382
378
|
console.error("Unhandled error in main function:", error);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/bin/setup.ts"],"names":[],"mappings":"AA+EA,wBAAsB,QAAQ,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,iBA2BhE"}
|
|
@@ -0,0 +1,86 @@
|
|
|
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.runSetup = runSetup;
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const util_1 = require("util");
|
|
11
|
+
const api_client_1 = require("../auth/api-client");
|
|
12
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
13
|
+
async function cloneRepository(cloneUrl, repoName) {
|
|
14
|
+
const targetDir = path_1.default.join(process.cwd(), repoName);
|
|
15
|
+
if (fs_1.default.existsSync(targetDir)) {
|
|
16
|
+
console.error(`Directory '${repoName}' already exists in current location`);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
console.log(`📥 Cloning repository to ./${repoName}...`);
|
|
20
|
+
const { stderr } = await execAsync(`git clone ${cloneUrl} ${repoName}`, {
|
|
21
|
+
cwd: process.cwd(),
|
|
22
|
+
});
|
|
23
|
+
if (stderr && !stderr.includes("Cloning into")) {
|
|
24
|
+
console.error(`Git clone error: ${stderr}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
console.log(`✅ Repository cloned successfully to ./${repoName}`);
|
|
28
|
+
return targetDir;
|
|
29
|
+
}
|
|
30
|
+
async function installDependencies(targetDir) {
|
|
31
|
+
console.log(`📦 Installing dependencies...`);
|
|
32
|
+
try {
|
|
33
|
+
const { stderr: installStderr } = await execAsync(`npm install`, {
|
|
34
|
+
cwd: targetDir,
|
|
35
|
+
});
|
|
36
|
+
if (installStderr && !installStderr.toLowerCase().includes("npm warn")) {
|
|
37
|
+
console.error(`npm install error: ${installStderr}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
console.log(`✅ Dependencies installed successfully`);
|
|
41
|
+
}
|
|
42
|
+
catch (installError) {
|
|
43
|
+
console.error(`❌ Failed to install dependencies: ${installError.message}`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function installPlaywrightBrowser(targetDir) {
|
|
48
|
+
console.log(`🎭 Installing Playwright browser...`);
|
|
49
|
+
try {
|
|
50
|
+
const { stderr: playwrightStderr } = await execAsync(`npx playwright install chromium --with-deps`, {
|
|
51
|
+
cwd: targetDir,
|
|
52
|
+
});
|
|
53
|
+
if (playwrightStderr && !playwrightStderr.includes("Installing")) {
|
|
54
|
+
console.error(`Playwright install error: ${playwrightStderr}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
console.log(`✅ Playwright browser installed successfully`);
|
|
58
|
+
}
|
|
59
|
+
catch (playwrightError) {
|
|
60
|
+
console.error(`❌ Failed to install Playwright browser: ${playwrightError.message}`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function runSetup({ repoName }) {
|
|
65
|
+
try {
|
|
66
|
+
console.log(`🔍 Fetching details for repository: ${repoName}`);
|
|
67
|
+
const response = await api_client_1.apiClient.request(`/api/projects/clone?project_repo_name=${repoName}`);
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
if (response.status === 404) {
|
|
70
|
+
throw new Error(`Repository '${repoName}' not found in your projects`);
|
|
71
|
+
}
|
|
72
|
+
throw new Error(`Failed to fetch repository details: ${response.statusText}`);
|
|
73
|
+
}
|
|
74
|
+
const { data: repoDetails } = await response.json();
|
|
75
|
+
const { clone_url } = repoDetails;
|
|
76
|
+
console.log(`📂 Clone URL: ${clone_url}`);
|
|
77
|
+
const targetDir = await cloneRepository(clone_url, repoName);
|
|
78
|
+
await installDependencies(targetDir);
|
|
79
|
+
await installPlaywrightBrowser(targetDir);
|
|
80
|
+
console.log(`\n🎉 Setup complete! Repository is ready at ./${repoName}`);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error(`❌ Setup failed: ${error.message}`);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -6,13 +6,8 @@ export interface CLIOptions {
|
|
|
6
6
|
file?: string;
|
|
7
7
|
prompt?: string;
|
|
8
8
|
suites?: string;
|
|
9
|
-
|
|
10
|
-
useDiskForChatState?: boolean;
|
|
11
|
-
initialPrompt?: string;
|
|
12
|
-
chatSessionId?: string;
|
|
13
|
-
chatModel?: (typeof ARGS_TO_MODEL_MAP)[keyof typeof ARGS_TO_MODEL_MAP];
|
|
14
|
-
useRecorder?: boolean;
|
|
9
|
+
repoName?: string;
|
|
15
10
|
}
|
|
16
|
-
export declare function validateAndCompleteCliOptions(options: CLIOptions): Promise<CLIOptions>;
|
|
11
|
+
export declare function validateAndCompleteCliOptions(options: CLIOptions, requiredFields?: string[]): Promise<CLIOptions>;
|
|
17
12
|
export declare function printBanner(): Promise<void>;
|
|
18
13
|
//# 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;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;
|
|
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;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAQD,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,UAAU,EACnB,cAAc,GAAE,MAAM,EAA+B,GACpD,OAAO,CAAC,UAAU,CAAC,CAqDrB;AAeD,wBAAsB,WAAW,kBAgDhC"}
|
package/dist/bin/utils/index.js
CHANGED
|
@@ -22,20 +22,12 @@ exports.ARGS_TO_MODEL_MAP = {
|
|
|
22
22
|
"o4-mini": "o4-mini-2025-04-16",
|
|
23
23
|
"o4-mini-2025-04-16": "o4-mini-2025-04-16",
|
|
24
24
|
};
|
|
25
|
-
async function validateAndCompleteCliOptions(options) {
|
|
25
|
+
async function validateAndCompleteCliOptions(options, requiredFields = ["name", "file", "prompt"]) {
|
|
26
26
|
// For existing flow between dashboard <> test-gen (via ci-worker)
|
|
27
27
|
const hasToken = !!options.token;
|
|
28
28
|
if (hasToken) {
|
|
29
29
|
return options;
|
|
30
30
|
}
|
|
31
|
-
let requiredFields = ["name", "file", "prompt"];
|
|
32
|
-
if (options.useChat) {
|
|
33
|
-
// Chat agent can prompt the user directly, nothing is required in CLI args
|
|
34
|
-
requiredFields = [];
|
|
35
|
-
}
|
|
36
|
-
if (options.useRecorder) {
|
|
37
|
-
requiredFields = ["name"];
|
|
38
|
-
}
|
|
39
31
|
const questions = [];
|
|
40
32
|
if (!options.name && requiredFields.includes("name")) {
|
|
41
33
|
questions.push({
|
package/dist/file/server.js
CHANGED
|
@@ -45,7 +45,10 @@ class FileServiceServer {
|
|
|
45
45
|
app.post("/codegen-sources", async (req) => {
|
|
46
46
|
const payload = req.body;
|
|
47
47
|
this.codegenSources = payload.map((c) => c.actions.join("\n")).join("\n");
|
|
48
|
-
console.log(
|
|
48
|
+
// console.log(
|
|
49
|
+
// "[FileServiceServer] Received codegen sources",
|
|
50
|
+
// this.codegenSources,
|
|
51
|
+
// );
|
|
49
52
|
});
|
|
50
53
|
app.post("/agent-results", async (req, res) => {
|
|
51
54
|
const { generatedCode, importPaths, result, usage } = req.body;
|
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;AAchD,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
|
@@ -13,6 +13,7 @@ const for_recorder_1 = require("./agent/cua/pw-codegen/pw-pause/for-recorder");
|
|
|
13
13
|
const run_1 = require("./agent/master/run");
|
|
14
14
|
const scenarios_1 = require("./bin/utils/scenarios");
|
|
15
15
|
const client_1 = __importDefault(require("./file/client"));
|
|
16
|
+
const logger_1 = require("./logger");
|
|
16
17
|
const reporter_1 = require("./reporter");
|
|
17
18
|
const session_1 = require("./session");
|
|
18
19
|
var test_build_1 = require("./test-build");
|
|
@@ -104,7 +105,7 @@ async function recordTest(pageRef) {
|
|
|
104
105
|
if (!canUsePwPause) {
|
|
105
106
|
return;
|
|
106
107
|
}
|
|
107
|
-
|
|
108
|
+
logger_1.logger.debug("[getCodegen] using PlaywrightPauseCodegen");
|
|
108
109
|
const codegen = new for_recorder_1.PlaywrightPauseCodegenForRecorder(async (sources) => {
|
|
109
110
|
await fileServiceClient.sendCodegenSources(sources);
|
|
110
111
|
});
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,MAAyB,MAAM,mBAAmB,CAAC;AAE1D,eAAO,MAAM,MAAM,eAGjB,CAAC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
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.logger = void 0;
|
|
7
|
+
const console_log_level_1 = __importDefault(require("console-log-level"));
|
|
8
|
+
exports.logger = (0, console_log_level_1.default)({
|
|
9
|
+
prefix: "test-gen",
|
|
10
|
+
level: process.env.LOG_LEVEL || "info",
|
|
11
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-variables.d.ts","sourceRoot":"","sources":["../../src/recorder/env-variables.ts"],"names":[],"mappings":"AAEA,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAgCjC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchEnvironmentVariables = fetchEnvironmentVariables;
|
|
4
|
+
const api_client_1 = require("../auth/api-client");
|
|
5
|
+
async function fetchEnvironmentVariables(repoName) {
|
|
6
|
+
try {
|
|
7
|
+
const response = await api_client_1.apiClient.request(`/api/environment-variables?project_repo_name=${encodeURIComponent(repoName)}`, {
|
|
8
|
+
method: "GET",
|
|
9
|
+
});
|
|
10
|
+
if (!response.ok) {
|
|
11
|
+
const errorMessage = await response.text();
|
|
12
|
+
throw new Error(`Failed to fetch environment variables: ${errorMessage}`);
|
|
13
|
+
}
|
|
14
|
+
const data = await response.json();
|
|
15
|
+
if (!data.data) {
|
|
16
|
+
console.error("Failed to fetch environment variables:", data);
|
|
17
|
+
throw new Error("Failed to fetch environment variables");
|
|
18
|
+
}
|
|
19
|
+
const envVars = data.data.environment_variables.reduce((acc, envVar) => {
|
|
20
|
+
acc[envVar.name] = envVar.value;
|
|
21
|
+
return acc;
|
|
22
|
+
}, {});
|
|
23
|
+
return envVars;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.error("Failed to fetch environment variables:", error);
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/recorder/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/recorder/index.ts"],"names":[],"mappings":"AAkBA,wBAAsB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,iBAyF3D"}
|
package/dist/recorder/index.js
CHANGED
|
@@ -6,66 +6,56 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.runRecorder = runRecorder;
|
|
7
7
|
const test_run_1 = require("@empiricalrun/test-run");
|
|
8
8
|
const detect_port_1 = __importDefault(require("detect-port"));
|
|
9
|
-
const fs_1 = __importDefault(require("fs"));
|
|
10
9
|
const path_1 = __importDefault(require("path"));
|
|
11
10
|
const utils_1 = require("../agent/browsing/utils");
|
|
12
|
-
const chat_1 = require("../agent/chat");
|
|
13
11
|
const pw_pause_1 = require("../agent/cua/pw-codegen/pw-pause");
|
|
14
|
-
const utils_2 = require("../artifacts/utils");
|
|
15
12
|
const server_1 = require("../file/server");
|
|
13
|
+
const logger_1 = require("../logger");
|
|
16
14
|
const display_1 = require("./display");
|
|
15
|
+
const env_variables_1 = require("./env-variables");
|
|
17
16
|
const request_1 = require("./request");
|
|
18
17
|
const temp_files_1 = require("./temp-files");
|
|
19
18
|
const upload_1 = require("./upload");
|
|
20
19
|
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
20
|
async function runRecorder({ name }) {
|
|
41
21
|
console.log(`Recording for test name: ${name}`);
|
|
42
22
|
const repoDir = process.cwd();
|
|
23
|
+
let repoName = "";
|
|
24
|
+
let fileServer = null;
|
|
25
|
+
process.on("SIGINT", async () => {
|
|
26
|
+
try {
|
|
27
|
+
await (0, temp_files_1.deleteTempTestFile)();
|
|
28
|
+
await (0, pw_pause_1.revertToOriginalPwCode)(repoDir);
|
|
29
|
+
if (fileServer) {
|
|
30
|
+
await fileServer.stop();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
console.error("Error during cleanup:", error);
|
|
35
|
+
}
|
|
36
|
+
process.exit(0);
|
|
37
|
+
});
|
|
43
38
|
try {
|
|
44
|
-
await (0, validation_1.
|
|
39
|
+
repoName = await (0, validation_1.validatePackageJson)(repoDir);
|
|
45
40
|
}
|
|
46
41
|
catch (error) {
|
|
47
42
|
console.error("Error running recorder:", error);
|
|
48
43
|
process.exit(1);
|
|
49
44
|
}
|
|
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
45
|
try {
|
|
55
|
-
|
|
56
|
-
console.log("[generateTestWithBrowserAgent] Preparing playwright for codegen");
|
|
46
|
+
logger_1.logger.debug("[generateTestWithBrowserAgent] Preparing playwright for codegen");
|
|
57
47
|
await (0, pw_pause_1.preparePlaywrightForCodegen)(repoDir);
|
|
58
48
|
}
|
|
59
49
|
catch (err) {
|
|
60
|
-
|
|
50
|
+
logger_1.logger.warn("[generateTestWithBrowserAgent] Error preparing playwright for codegen", err);
|
|
61
51
|
}
|
|
62
|
-
const envVariables = await (0,
|
|
52
|
+
const envVariables = await (0, env_variables_1.fetchEnvironmentVariables)(repoName);
|
|
63
53
|
await (0, temp_files_1.createTempTestFile)();
|
|
64
54
|
const absFilePath = path_1.default.join(process.cwd(), "tests", "temp-test.spec.ts");
|
|
65
55
|
await (0, utils_1.addImportForMethod)(absFilePath, "recordTest");
|
|
66
56
|
// Start a file service for IPC with the agent (which runs in a different process)
|
|
67
57
|
const availablePort = await (0, detect_port_1.default)(3030);
|
|
68
|
-
|
|
58
|
+
fileServer = new server_1.FileServiceServer({
|
|
69
59
|
port: availablePort,
|
|
70
60
|
repoDir,
|
|
71
61
|
updateFile: false,
|
|
@@ -84,10 +74,10 @@ async function runRecorder({ name }) {
|
|
|
84
74
|
IPC_FILE_SERVICE_PORT: availablePort.toString(),
|
|
85
75
|
},
|
|
86
76
|
});
|
|
87
|
-
const videoPaths = extractVideoAttachments(repoDir);
|
|
77
|
+
const videoPaths = (0, upload_1.extractVideoAttachments)(repoDir);
|
|
88
78
|
let attachments = [];
|
|
89
79
|
if (videoPaths.length === 0) {
|
|
90
|
-
|
|
80
|
+
logger_1.logger.warn("No video attachments found for temp test");
|
|
91
81
|
}
|
|
92
82
|
else {
|
|
93
83
|
const videoUrls = await (0, upload_1.uploadVideosWithSpinner)(videoPaths, name);
|
|
@@ -101,6 +91,7 @@ async function runRecorder({ name }) {
|
|
|
101
91
|
await fileServer.stop();
|
|
102
92
|
const finalCode = await (0, display_1.displayResultsAndConfirm)(name, codegenResult);
|
|
103
93
|
await (0, request_1.sendToDashboardAsRequest)({
|
|
94
|
+
repoName,
|
|
104
95
|
testName: name,
|
|
105
96
|
codegenResult: finalCode,
|
|
106
97
|
attachments,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export declare function sendToDashboardAsRequest({ testName, codegenResult, attachments, }: {
|
|
1
|
+
export declare function sendToDashboardAsRequest({ repoName, testName, codegenResult, attachments, }: {
|
|
2
|
+
repoName: string;
|
|
2
3
|
testName: string;
|
|
3
4
|
codegenResult: string;
|
|
4
5
|
attachments: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/recorder/request.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/recorder/request.ts"],"names":[],"mappings":"AAaA,wBAAsB,wBAAwB,CAAC,EAC7C,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,WAAW,GACZ,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,iBAMA"}
|