@empiricalrun/test-gen 0.69.1 → 0.69.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @empiricalrun/test-gen
2
2
 
3
+ ## 0.69.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 298b5e5: feat: ask for project name in recorder flow
8
+ - Updated dependencies [298b5e5]
9
+ - @empiricalrun/test-run@0.10.6
10
+
11
+ ## 0.69.2
12
+
13
+ ### Patch Changes
14
+
15
+ - e2f72b5: fix: handle video processing time and large uploads
16
+ - Updated dependencies [e2f72b5]
17
+ - @empiricalrun/llm@0.19.1
18
+
3
19
  ## 0.69.1
4
20
 
5
21
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"for-recorder.d.ts","sourceRoot":"","sources":["../../../../../src/agent/cua/pw-codegen/pw-pause/for-recorder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIvC,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC,qBAAa,iCAAiC;IAO1C,OAAO,CAAC,eAAe;IANzB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,IAAI,CAAmB;IAC/B,OAAO,CAAC,MAAM,CAA4C;IAC1D,OAAO,CAAC,iBAAiB,CAAqB;gBAGpC,eAAe,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC;YAKtD,QAAQ;IAWhB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBrC,sBAAsB,CAAC,IAAI,EAAE,IAAI;CAmCxC"}
1
+ {"version":3,"file":"for-recorder.d.ts","sourceRoot":"","sources":["../../../../../src/agent/cua/pw-codegen/pw-pause/for-recorder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIvC,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC,qBAAa,iCAAiC;IAO1C,OAAO,CAAC,eAAe;IANzB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,IAAI,CAAmB;IAC/B,OAAO,CAAC,MAAM,CAA4C;IAC1D,OAAO,CAAC,iBAAiB,CAAqB;gBAGpC,eAAe,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC;YAKtD,QAAQ;IAWhB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBrC,sBAAsB,CAAC,IAAI,EAAE,IAAI;CA4CxC"}
@@ -69,13 +69,22 @@ class PlaywrightPauseCodegenForRecorder {
69
69
  }
70
70
  });
71
71
  await page.addInitScript(() => {
72
- setInterval(() => {
72
+ let displayNoneSet = false;
73
+ function setDisplayNone() {
73
74
  const glassPane = document.querySelector("x-pw-glass");
74
75
  if (glassPane) {
75
76
  const styles = glassPane.getAttribute("style") || "";
76
77
  glassPane.setAttribute("style", styles + "; display: none;");
78
+ displayNoneSet = true;
77
79
  }
78
- }, 300);
80
+ }
81
+ let interval = setInterval(() => {
82
+ if (displayNoneSet) {
83
+ clearInterval(interval);
84
+ return;
85
+ }
86
+ setDisplayNone();
87
+ }, 100);
79
88
  });
80
89
  await Promise.all([pausePromise, evaluatePromise]);
81
90
  }
@@ -0,0 +1,2 @@
1
+ export declare function generateMatchingString(patterns: string[]): string | null;
2
+ //# sourceMappingURL=glob.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../src/recorder/glob.ts"],"names":[],"mappings":"AAGA,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CA8FxE"}
@@ -0,0 +1,74 @@
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.generateMatchingString = generateMatchingString;
7
+ const minimatch_1 = require("minimatch");
8
+ const path_1 = __importDefault(require("path"));
9
+ function generateMatchingString(patterns) {
10
+ // Separate positive and negative patterns
11
+ const positivePatterns = patterns.filter((p) => !p.startsWith("!"));
12
+ const negativePatterns = patterns
13
+ .filter((p) => p.startsWith("!"))
14
+ .map((p) => p.slice(1));
15
+ // Start with the most specific pattern - temp-test.spec.ts
16
+ const tempTestPattern = positivePatterns.find((p) => p.includes("temp-test.spec.ts"));
17
+ if (!tempTestPattern) {
18
+ return null;
19
+ }
20
+ // Extract the base directory from the testDirPattern
21
+ const testDirPattern = positivePatterns.find((p) => p.includes("/**"));
22
+ if (!testDirPattern) {
23
+ return null;
24
+ }
25
+ // Get the base directory (everything before /**)
26
+ const baseDir = testDirPattern.replace("/**", "");
27
+ // Generate a simple path that matches all positive patterns
28
+ let candidatePath = path_1.default.join(baseDir, "temp-test.spec.ts");
29
+ // Check if it matches all positive patterns
30
+ for (const pattern of positivePatterns) {
31
+ if (!(0, minimatch_1.minimatch)(candidatePath, pattern)) {
32
+ // If it doesn't match, try to adjust the path
33
+ // For patterns like **/*.spec.ts, we might need to add subdirectories
34
+ if (pattern.includes("**/")) {
35
+ // Try adding a subdirectory
36
+ candidatePath = path_1.default.join(baseDir, "e2e", "temp-test.spec.ts");
37
+ }
38
+ }
39
+ }
40
+ // Check against negative patterns
41
+ for (const pattern of negativePatterns) {
42
+ if ((0, minimatch_1.minimatch)(candidatePath, pattern)) {
43
+ // If it matches a negative pattern, try to find an alternative path
44
+ // Add a different subdirectory or modify the path
45
+ candidatePath = path_1.default.join(baseDir, "integration", "temp-test.spec.ts");
46
+ // Re-check against all patterns
47
+ const matchesAllPositive = positivePatterns.every((p) => (0, minimatch_1.minimatch)(candidatePath, p));
48
+ const matchesNoNegative = !negativePatterns.some((p) => (0, minimatch_1.minimatch)(candidatePath, p));
49
+ if (!matchesAllPositive || !matchesNoNegative) {
50
+ // Try another path
51
+ candidatePath = path_1.default.join(baseDir, "specs", "temp-test.spec.ts");
52
+ }
53
+ }
54
+ }
55
+ // Final validation
56
+ const matchesAllPositive = positivePatterns.every((p) => (0, minimatch_1.minimatch)(candidatePath, p));
57
+ const matchesNoNegative = !negativePatterns.some((p) => (0, minimatch_1.minimatch)(candidatePath, p));
58
+ if (matchesAllPositive && matchesNoNegative) {
59
+ return candidatePath;
60
+ }
61
+ // If we still can't find a valid path, try a more systematic approach
62
+ const subdirs = ["", "e2e", "integration", "specs", "playwright", "tests"];
63
+ for (const subdir of subdirs) {
64
+ const testPath = subdir
65
+ ? path_1.default.join(baseDir, subdir, "temp-test.spec.ts")
66
+ : path_1.default.join(baseDir, "temp-test.spec.ts");
67
+ const matchesAllPositive = positivePatterns.every((p) => (0, minimatch_1.minimatch)(testPath, p));
68
+ const matchesNoNegative = !negativePatterns.some((p) => (0, minimatch_1.minimatch)(testPath, p));
69
+ if (matchesAllPositive && matchesNoNegative) {
70
+ return testPath;
71
+ }
72
+ }
73
+ return null;
74
+ }
@@ -1 +1 @@
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,iBAgG3D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/recorder/index.ts"],"names":[],"mappings":"AA4BA,wBAAsB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,iBAgI3D"}
@@ -6,6 +6,7 @@ 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 inquirer_1 = __importDefault(require("inquirer"));
9
10
  const path_1 = __importDefault(require("path"));
10
11
  const utils_1 = require("../agent/browsing/utils");
11
12
  const pw_pause_1 = require("../agent/cua/pw-codegen/pw-pause");
@@ -18,7 +19,6 @@ const temp_files_1 = require("./temp-files");
18
19
  const upload_1 = require("./upload");
19
20
  const validation_1 = require("./validation");
20
21
  async function runRecorder({ name }) {
21
- console.log(`Recording for test name: ${name}`);
22
22
  try {
23
23
  await api_client_1.apiClient.ensureAuthenticated();
24
24
  }
@@ -29,9 +29,10 @@ async function runRecorder({ name }) {
29
29
  const repoDir = process.cwd();
30
30
  let repoName = "";
31
31
  let fileServer = null;
32
+ let tempTestFilePath = "tests/temp-test.spec.ts";
32
33
  process.on("SIGINT", async () => {
33
34
  try {
34
- await (0, temp_files_1.deleteTempTestFile)();
35
+ await (0, temp_files_1.deleteTempTestFile)(repoDir, tempTestFilePath);
35
36
  await (0, pw_pause_1.revertToOriginalPwCode)(repoDir);
36
37
  if (fileServer) {
37
38
  await fileServer.stop();
@@ -46,7 +47,7 @@ async function runRecorder({ name }) {
46
47
  repoName = await (0, validation_1.validatePackageJson)(repoDir);
47
48
  }
48
49
  catch (error) {
49
- console.error("Error running recorder:", error);
50
+ console.error(`Could not validate package.json: ensure you are running this in an Empirical repo.`);
50
51
  process.exit(1);
51
52
  }
52
53
  try {
@@ -65,14 +66,38 @@ async function runRecorder({ name }) {
65
66
  updateFile: false,
66
67
  });
67
68
  await fileServer.startFileService();
68
- await (0, temp_files_1.createTempTestFile)(availablePort);
69
- const absFilePath = path_1.default.join(process.cwd(), "tests", "temp-test.spec.ts");
69
+ // Get available Playwright projects
70
+ const projects = await (0, test_run_1.getProjectsFromPlaywrightConfig)(test_run_1.Platform.WEB, repoDir);
71
+ let selectedProjects = ["chromium"]; // default fallback
72
+ let selectedProjectObj;
73
+ if (projects.length > 0) {
74
+ const projectNames = projects.map((p) => p.name);
75
+ const { selectedProject } = await inquirer_1.default.prompt([
76
+ {
77
+ type: "list",
78
+ name: "selectedProject",
79
+ message: "Select a Playwright project to use:",
80
+ choices: projectNames,
81
+ default: projectNames.includes("chromium")
82
+ ? "chromium"
83
+ : projectNames[0],
84
+ },
85
+ ]);
86
+ selectedProjects = [selectedProject];
87
+ selectedProjectObj = projects.find((p) => p.name === selectedProject);
88
+ if (selectedProjectObj) {
89
+ tempTestFilePath = (0, temp_files_1.getTempTestFileLocation)(selectedProjectObj);
90
+ }
91
+ }
92
+ // Create temp test file in the determined location
93
+ await (0, temp_files_1.createTempTestFile)(availablePort, repoDir, tempTestFilePath);
94
+ const absFilePath = path_1.default.join(repoDir, tempTestFilePath);
70
95
  await (0, utils_1.addImportForMethod)(absFilePath, "recordTest");
71
96
  await (0, test_run_1.runSingleTest)({
72
97
  testName: "temp test",
73
98
  suites: [],
74
- filePath: "tests/temp-test.spec.ts",
75
- projects: ["chromium"],
99
+ filePath: tempTestFilePath,
100
+ projects: selectedProjects,
76
101
  repoDir: process.cwd(),
77
102
  envOverrides: {
78
103
  ...envVariables,
@@ -92,14 +117,18 @@ async function runRecorder({ name }) {
92
117
  attachments = [...attachments, ...videoUrls];
93
118
  }
94
119
  }
95
- await (0, temp_files_1.deleteTempTestFile)();
120
+ await (0, temp_files_1.deleteTempTestFile)(repoDir, tempTestFilePath);
96
121
  await (0, pw_pause_1.revertToOriginalPwCode)(repoDir);
97
122
  const codegenResult = fileServer.getCodegenSources();
98
123
  await fileServer.stop();
124
+ if (!name || !codegenResult) {
125
+ logger_1.logger.error("Test name or codegen result is missing");
126
+ process.exit(1);
127
+ }
99
128
  await (0, request_1.sendToDashboardAsRequest)({
100
129
  repoName,
101
130
  testName: name,
102
- codegenResult: codegenResult,
131
+ codegenResult,
103
132
  attachments,
104
133
  });
105
134
  }
@@ -1,3 +1,12 @@
1
- export declare function createTempTestFile(port: number): Promise<void>;
2
- export declare function deleteTempTestFile(): Promise<void>;
1
+ export type PlaywrightProject = {
2
+ name: string;
3
+ use: any;
4
+ testMatch: string[] | string | undefined;
5
+ testIgnore: string[] | string | undefined;
6
+ testDir: string | undefined;
7
+ teardown: string | undefined;
8
+ };
9
+ export declare function getTempTestFileLocation(selectedProject: PlaywrightProject): string;
10
+ export declare function createTempTestFile(port: number, repoDir: string, tempFileRelativePath: string): Promise<void>;
11
+ export declare function deleteTempTestFile(repoDir: string, tempFileRelativePath: string): Promise<void>;
3
12
  //# sourceMappingURL=temp-files.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"temp-files.d.ts","sourceRoot":"","sources":["../../src/recorder/temp-files.ts"],"names":[],"mappings":"AAKA,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,iBAmBpD;AAED,wBAAsB,kBAAkB,kBAUvC"}
1
+ {"version":3,"file":"temp-files.d.ts","sourceRoot":"","sources":["../../src/recorder/temp-files.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,GAAG,CAAC;IACT,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IACzC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IAC1C,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B,CAAC;AAEF,wBAAgB,uBAAuB,CACrC,eAAe,EAAE,iBAAiB,GACjC,MAAM,CA+BR;AAqBD,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,oBAAoB,EAAE,MAAM,iBAkB7B;AAED,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,oBAAoB,EAAE,MAAM,iBAS7B"}
@@ -3,32 +3,79 @@ 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.getTempTestFileLocation = getTempTestFileLocation;
6
7
  exports.createTempTestFile = createTempTestFile;
7
8
  exports.deleteTempTestFile = deleteTempTestFile;
8
9
  const fs_1 = __importDefault(require("fs"));
9
10
  const path_1 = __importDefault(require("path"));
10
11
  const logger_1 = require("../logger");
11
- async function createTempTestFile(port) {
12
- const tempFilePath = path_1.default.join(process.cwd(), "tests", "temp-test.spec.ts");
13
- // Check if the temp file already exists
12
+ const glob_1 = require("./glob");
13
+ function getTempTestFileLocation(selectedProject) {
14
+ const baseTestDir = selectedProject.testDir || "tests";
15
+ const normalized = path_1.default.normalize(baseTestDir).endsWith("/")
16
+ ? path_1.default.normalize(baseTestDir).slice(0, -1)
17
+ : path_1.default.normalize(baseTestDir);
18
+ const testDirPattern = `${normalized}/**`;
19
+ const testMatchPattern = selectedProject.testMatch
20
+ ? Array.isArray(selectedProject.testMatch)
21
+ ? selectedProject.testMatch
22
+ : [selectedProject.testMatch]
23
+ : ["**/*.spec.ts"];
24
+ const testIgnorePattern = selectedProject.testIgnore
25
+ ? Array.isArray(selectedProject.testIgnore)
26
+ ? selectedProject.testIgnore
27
+ : [selectedProject.testIgnore]
28
+ : [];
29
+ const patterns = [
30
+ "**/temp-test.spec.ts",
31
+ testDirPattern,
32
+ ...testMatchPattern,
33
+ ...testIgnorePattern.map((p) => `!${p}`),
34
+ ];
35
+ console.log("Generated patterns:", patterns);
36
+ const common = (0, glob_1.generateMatchingString)(patterns);
37
+ if (!common) {
38
+ throw new Error("Could not generate a valid test file location. Please check your testMatch and testIgnore patterns.");
39
+ }
40
+ return common;
41
+ }
42
+ function getFixturesImportPath(tempFileRelativePath) {
43
+ const tempFileStartsWithSlash = tempFileRelativePath.startsWith("/")
44
+ ? tempFileRelativePath
45
+ : `/${tempFileRelativePath}`;
46
+ const subFolder = tempFileStartsWithSlash.split("/tests/")[1];
47
+ if (!subFolder) {
48
+ return "./fixtures";
49
+ }
50
+ // Count directory levels from temp file to tests directory
51
+ const pathParts = subFolder.split("/");
52
+ // Remove the filename to get just directory parts
53
+ const directoryParts = pathParts.slice(0, -1);
54
+ const subFolderDepth = directoryParts.length;
55
+ // Create relative path back to tests directory, then into fixtures
56
+ const upLevels = subFolderDepth > 0 ? new Array(subFolderDepth).fill("../").join("") : "./";
57
+ return `${upLevels}fixtures`;
58
+ }
59
+ async function createTempTestFile(port, repoDir, tempFileRelativePath) {
60
+ logger_1.logger.debug("Creating temporary test file at:", tempFileRelativePath);
61
+ const tempFilePath = path_1.default.join(repoDir, tempFileRelativePath);
14
62
  if (fs_1.default.existsSync(tempFilePath)) {
15
63
  logger_1.logger.warn("Temporary test file already exists. Skipping creation.");
16
64
  return;
17
65
  }
18
- // Create a basic test file
19
- const content = `import { test, expect } from './fixtures';
66
+ const fixturesImportPath = getFixturesImportPath(tempFileRelativePath);
67
+ const content = `import { test, expect } from '${fixturesImportPath}';
20
68
 
21
69
  test('temp test', async ({ page }) => {
22
70
  await page.goto('http://localhost:${port}/ready');
23
71
  await recordTest(page);
24
72
  });
25
73
  `;
74
+ logger_1.logger.debug("File content:", content);
26
75
  fs_1.default.writeFileSync(tempFilePath, content);
27
- logger_1.logger.debug("Temporary test file created:", tempFilePath);
28
76
  }
29
- async function deleteTempTestFile() {
30
- const tempFilePath = path_1.default.join(process.cwd(), "tests", "temp-test.spec.ts");
31
- // Check if the temp file exists
77
+ async function deleteTempTestFile(repoDir, tempFileRelativePath) {
78
+ const tempFilePath = path_1.default.join(repoDir, tempFileRelativePath);
32
79
  if (fs_1.default.existsSync(tempFilePath)) {
33
80
  fs_1.default.unlinkSync(tempFilePath);
34
81
  logger_1.logger.debug("Temporary test file deleted:", tempFilePath);
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/recorder/upload.ts"],"names":[],"mappings":"AAcA,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAoBjE;AA4DD,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,MAAM,EAAE,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,GAAG,MAAM,EAAE,CAAC,CAc1B"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/recorder/upload.ts"],"names":[],"mappings":"AAcA,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAoBjE;AA6FD,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,MAAM,EAAE,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,GAAG,MAAM,EAAE,CAAC,CAc1B"}
@@ -47,30 +47,56 @@ async function uploadVideos(videoPaths, testSlug) {
47
47
  const uploadDestinationDir = `recorder-uploads/${testSlug}`;
48
48
  const bucket = ASSETS_PRODUCTION_BUCKET;
49
49
  try {
50
- const formData = new FormData();
51
- formData.append("destination_dir", uploadDestinationDir);
52
- formData.append("bucket", bucket);
53
- for (const videoPath of videoPaths) {
54
- if (fs_1.default.existsSync(videoPath)) {
55
- const fileBuffer = fs_1.default.readFileSync(videoPath);
56
- const fileName = path_1.default.basename(videoPath);
57
- const blob = new Blob([fileBuffer], { type: "video/webm" });
58
- formData.append("files", blob, fileName);
59
- }
50
+ // Step 1: Get pre-signed URLs from the API
51
+ const files = videoPaths
52
+ .filter((videoPath) => fs_1.default.existsSync(videoPath))
53
+ .map((videoPath) => ({
54
+ name: path_1.default.basename(videoPath),
55
+ type: "video/webm",
56
+ }));
57
+ if (files.length === 0) {
58
+ return null;
60
59
  }
61
- const response = await api_client_1.apiClient.request("/api/upload", {
60
+ const presignedResponse = await api_client_1.apiClient.request("/api/upload", {
62
61
  method: "POST",
63
- body: formData,
62
+ headers: {
63
+ "Content-Type": "application/json",
64
+ },
65
+ body: JSON.stringify({
66
+ files,
67
+ destination_dir: uploadDestinationDir,
68
+ bucket,
69
+ }),
64
70
  });
65
- if (!response.ok) {
66
- console.warn(`Failed to upload videos: ${response.status} ${response.statusText}`);
71
+ if (!presignedResponse.ok) {
72
+ console.warn(`Failed to get pre-signed URLs: ${presignedResponse.status} ${presignedResponse.statusText}`);
67
73
  return null;
68
74
  }
69
- const result = await response.json();
70
- if (result.error) {
71
- console.warn("Video upload error:", result.error.message);
75
+ const presignedResult = await presignedResponse.json();
76
+ if (presignedResult.error) {
77
+ console.warn("Pre-signed URL error:", presignedResult.error.message);
72
78
  return null;
73
79
  }
80
+ // Step 2: Upload files directly to R2 using pre-signed URLs
81
+ const uploadPromises = presignedResult.data.presigned_urls.map(async (urlInfo) => {
82
+ const videoPath = videoPaths.find((p) => path_1.default.basename(p) === urlInfo.file_name);
83
+ if (!videoPath || !fs_1.default.existsSync(videoPath)) {
84
+ throw new Error(`Video file not found: ${urlInfo.file_name}`);
85
+ }
86
+ const fileBuffer = fs_1.default.readFileSync(videoPath);
87
+ const uploadResponse = await fetch(urlInfo.upload_url, {
88
+ method: "PUT",
89
+ body: fileBuffer,
90
+ headers: {
91
+ "Content-Type": "video/webm",
92
+ },
93
+ });
94
+ if (!uploadResponse.ok) {
95
+ throw new Error(`Failed to upload ${urlInfo.file_name}: ${uploadResponse.status} ${uploadResponse.statusText}`);
96
+ }
97
+ return urlInfo.key;
98
+ });
99
+ await Promise.all(uploadPromises);
74
100
  return videoPaths.map((p) => buildVideoUrl(p, uploadDestinationDir, bucket));
75
101
  }
76
102
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/test-gen",
3
- "version": "0.69.1",
3
+ "version": "0.69.3",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -64,9 +64,9 @@
64
64
  "tsx": "^4.16.2",
65
65
  "typescript": "^5.3.3",
66
66
  "zod": "^3.23.8",
67
- "@empiricalrun/llm": "^0.19.0",
67
+ "@empiricalrun/llm": "^0.19.1",
68
68
  "@empiricalrun/r2-uploader": "^0.3.9",
69
- "@empiricalrun/test-run": "^0.10.5"
69
+ "@empiricalrun/test-run": "^0.10.6"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@playwright/test": "1.53.0",
@@ -1 +1 @@
1
- {"root":["./src/index.ts","./src/logger.ts","./src/actions/assert.ts","./src/actions/click.ts","./src/actions/done.ts","./src/actions/fill.ts","./src/actions/goto.ts","./src/actions/hover.ts","./src/actions/index.ts","./src/actions/next-task.ts","./src/actions/press.ts","./src/actions/skill.ts","./src/actions/text-content.ts","./src/actions/constants/index.ts","./src/actions/utils/index.ts","./src/agent/browsing/index.ts","./src/agent/browsing/run.ts","./src/agent/browsing/utils.ts","./src/agent/chat/agent-loop.ts","./src/agent/chat/exports.ts","./src/agent/chat/index.ts","./src/agent/chat/models.ts","./src/agent/chat/state.ts","./src/agent/chat/types.ts","./src/agent/chat/utils.ts","./src/agent/chat/prompt/index.ts","./src/agent/chat/prompt/pw-utils-docs.ts","./src/agent/chat/prompt/repo.ts","./src/agent/codegen/create-test-block.ts","./src/agent/codegen/fix-ts-errors.ts","./src/agent/codegen/generate-code-apply-changes.ts","./src/agent/codegen/lexical-scoped-vars.ts","./src/agent/codegen/repo-edit.ts","./src/agent/codegen/run.ts","./src/agent/codegen/skills-retriever.ts","./src/agent/codegen/test-update-feedback.ts","./src/agent/codegen/types.ts","./src/agent/codegen/update-flow.ts","./src/agent/codegen/use-skill.ts","./src/agent/codegen/utils.ts","./src/agent/cua/computer.ts","./src/agent/cua/index.ts","./src/agent/cua/model.ts","./src/agent/cua/pw-codegen/element-from-point.ts","./src/agent/cua/pw-codegen/types.ts","./src/agent/cua/pw-codegen/pw-pause/for-recorder.ts","./src/agent/cua/pw-codegen/pw-pause/index.ts","./src/agent/cua/pw-codegen/pw-pause/ipc.ts","./src/agent/cua/pw-codegen/pw-pause/patch.ts","./src/agent/cua/pw-codegen/pw-pause/types.ts","./src/agent/diagnosis-agent/index.ts","./src/agent/diagnosis-agent/strict-mode-violation.ts","./src/agent/enrich-prompt/index.ts","./src/agent/enrich-prompt/utils.ts","./src/agent/infer-agent/index.ts","./src/agent/master/action-tool-calls.ts","./src/agent/master/element-annotation.ts","./src/agent/master/execute-browser-action.ts","./src/agent/master/execute-skill-action.ts","./src/agent/master/next-action.ts","./src/agent/master/planner.ts","./src/agent/master/run.ts","./src/agent/master/scroller.ts","./src/agent/master/with-hints.ts","./src/agent/master/browser-tests/cua.spec.ts","./src/agent/master/browser-tests/fixtures.ts","./src/agent/master/browser-tests/index.spec.ts","./src/agent/master/browser-tests/skills.spec.ts","./src/agent/master/icon-descriptor/index.ts","./src/agent/master/icon-descriptor/normalize-svg.ts","./src/agent/planner/run-time-planner.ts","./src/agent/planner/run.ts","./src/artifacts/index.ts","./src/artifacts/utils.ts","./src/auth/api-client.ts","./src/auth/cli-auth.ts","./src/auth/index.ts","./src/auth/token-store.ts","./src/bin/index.ts","./src/bin/setup.ts","./src/bin/logger/index.ts","./src/bin/utils/context.ts","./src/bin/utils/index.ts","./src/bin/utils/fs/index.ts","./src/bin/utils/platform/web/index.ts","./src/bin/utils/platform/web/test-files/ts-path-import-validate.ts","./src/bin/utils/scenarios/index.ts","./src/browser-injected-scripts/annotate-elements.spec.ts","./src/constants/index.ts","./src/errors/index.ts","./src/evals/add-scenario-agent.evals.ts","./src/evals/append-create-test-agent.evals.ts","./src/evals/fetch-pom-skills-agent.evals.ts","./src/evals/infer-master-or-code-agent.evals.ts","./src/evals/master-agent.evals.ts","./src/evals/type.ts","./src/evals/update-scenario-agent.evals.ts","./src/file/client.ts","./src/file/server.ts","./src/human-in-the-loop/cli.ts","./src/human-in-the-loop/index.ts","./src/human-in-the-loop/ipc.ts","./src/page/index.ts","./src/prompts/lib/ts-transformer.ts","./src/recorder/env-variables.ts","./src/recorder/index.ts","./src/recorder/request.ts","./src/recorder/temp-files.ts","./src/recorder/upload.ts","./src/recorder/validation.ts","./src/reporter/index.ts","./src/reporter/lib.ts","./src/session/index.ts","./src/test-build/index.ts","./src/tool-call-service/index.ts","./src/tool-call-service/utils.ts","./src/tools/commit-and-create-pr.ts","./src/tools/diagnosis-fetcher.ts","./src/tools/download-build.ts","./src/tools/list-environments.ts","./src/tools/str_replace_editor.ts","./src/tools/test-gen-browser.ts","./src/tools/test-run.ts","./src/tools/grep/index.ts","./src/tools/grep/ripgrep/index.ts","./src/tools/grep/ripgrep/types.ts","./src/tools/test-run-fetcher/index.ts","./src/tools/test-run-fetcher/types.ts","./src/tools/upgrade-packages/index.ts","./src/tools/upgrade-packages/utils.ts","./src/tools/utils/index.ts","./src/types/handlebars.d.ts","./src/types/index.ts","./src/uploader/index.ts","./src/uploader/utils.ts","./src/utils/checkpoint.ts","./src/utils/env.ts","./src/utils/exec.ts","./src/utils/file-tree.ts","./src/utils/file.ts","./src/utils/git.ts","./src/utils/html.ts","./src/utils/index.ts","./src/utils/json.ts","./src/utils/repo-tree.ts","./src/utils/slug.ts","./src/utils/string.ts","./src/utils/stripAnsi.ts"],"version":"5.8.3"}
1
+ {"root":["./src/index.ts","./src/logger.ts","./src/actions/assert.ts","./src/actions/click.ts","./src/actions/done.ts","./src/actions/fill.ts","./src/actions/goto.ts","./src/actions/hover.ts","./src/actions/index.ts","./src/actions/next-task.ts","./src/actions/press.ts","./src/actions/skill.ts","./src/actions/text-content.ts","./src/actions/constants/index.ts","./src/actions/utils/index.ts","./src/agent/browsing/index.ts","./src/agent/browsing/run.ts","./src/agent/browsing/utils.ts","./src/agent/chat/agent-loop.ts","./src/agent/chat/exports.ts","./src/agent/chat/index.ts","./src/agent/chat/models.ts","./src/agent/chat/state.ts","./src/agent/chat/types.ts","./src/agent/chat/utils.ts","./src/agent/chat/prompt/index.ts","./src/agent/chat/prompt/pw-utils-docs.ts","./src/agent/chat/prompt/repo.ts","./src/agent/codegen/create-test-block.ts","./src/agent/codegen/fix-ts-errors.ts","./src/agent/codegen/generate-code-apply-changes.ts","./src/agent/codegen/lexical-scoped-vars.ts","./src/agent/codegen/repo-edit.ts","./src/agent/codegen/run.ts","./src/agent/codegen/skills-retriever.ts","./src/agent/codegen/test-update-feedback.ts","./src/agent/codegen/types.ts","./src/agent/codegen/update-flow.ts","./src/agent/codegen/use-skill.ts","./src/agent/codegen/utils.ts","./src/agent/cua/computer.ts","./src/agent/cua/index.ts","./src/agent/cua/model.ts","./src/agent/cua/pw-codegen/element-from-point.ts","./src/agent/cua/pw-codegen/types.ts","./src/agent/cua/pw-codegen/pw-pause/for-recorder.ts","./src/agent/cua/pw-codegen/pw-pause/index.ts","./src/agent/cua/pw-codegen/pw-pause/ipc.ts","./src/agent/cua/pw-codegen/pw-pause/patch.ts","./src/agent/cua/pw-codegen/pw-pause/types.ts","./src/agent/diagnosis-agent/index.ts","./src/agent/diagnosis-agent/strict-mode-violation.ts","./src/agent/enrich-prompt/index.ts","./src/agent/enrich-prompt/utils.ts","./src/agent/infer-agent/index.ts","./src/agent/master/action-tool-calls.ts","./src/agent/master/element-annotation.ts","./src/agent/master/execute-browser-action.ts","./src/agent/master/execute-skill-action.ts","./src/agent/master/next-action.ts","./src/agent/master/planner.ts","./src/agent/master/run.ts","./src/agent/master/scroller.ts","./src/agent/master/with-hints.ts","./src/agent/master/browser-tests/cua.spec.ts","./src/agent/master/browser-tests/fixtures.ts","./src/agent/master/browser-tests/index.spec.ts","./src/agent/master/browser-tests/skills.spec.ts","./src/agent/master/icon-descriptor/index.ts","./src/agent/master/icon-descriptor/normalize-svg.ts","./src/agent/planner/run-time-planner.ts","./src/agent/planner/run.ts","./src/artifacts/index.ts","./src/artifacts/utils.ts","./src/auth/api-client.ts","./src/auth/cli-auth.ts","./src/auth/index.ts","./src/auth/token-store.ts","./src/bin/index.ts","./src/bin/setup.ts","./src/bin/logger/index.ts","./src/bin/utils/context.ts","./src/bin/utils/index.ts","./src/bin/utils/fs/index.ts","./src/bin/utils/platform/web/index.ts","./src/bin/utils/platform/web/test-files/ts-path-import-validate.ts","./src/bin/utils/scenarios/index.ts","./src/browser-injected-scripts/annotate-elements.spec.ts","./src/constants/index.ts","./src/errors/index.ts","./src/evals/add-scenario-agent.evals.ts","./src/evals/append-create-test-agent.evals.ts","./src/evals/fetch-pom-skills-agent.evals.ts","./src/evals/infer-master-or-code-agent.evals.ts","./src/evals/master-agent.evals.ts","./src/evals/type.ts","./src/evals/update-scenario-agent.evals.ts","./src/file/client.ts","./src/file/server.ts","./src/human-in-the-loop/cli.ts","./src/human-in-the-loop/index.ts","./src/human-in-the-loop/ipc.ts","./src/page/index.ts","./src/prompts/lib/ts-transformer.ts","./src/recorder/env-variables.ts","./src/recorder/glob.ts","./src/recorder/index.ts","./src/recorder/request.ts","./src/recorder/temp-files.ts","./src/recorder/upload.ts","./src/recorder/validation.ts","./src/reporter/index.ts","./src/reporter/lib.ts","./src/session/index.ts","./src/test-build/index.ts","./src/tool-call-service/index.ts","./src/tool-call-service/utils.ts","./src/tools/commit-and-create-pr.ts","./src/tools/diagnosis-fetcher.ts","./src/tools/download-build.ts","./src/tools/list-environments.ts","./src/tools/str_replace_editor.ts","./src/tools/test-gen-browser.ts","./src/tools/test-run.ts","./src/tools/grep/index.ts","./src/tools/grep/ripgrep/index.ts","./src/tools/grep/ripgrep/types.ts","./src/tools/test-run-fetcher/index.ts","./src/tools/test-run-fetcher/types.ts","./src/tools/upgrade-packages/index.ts","./src/tools/upgrade-packages/utils.ts","./src/tools/utils/index.ts","./src/types/handlebars.d.ts","./src/types/index.ts","./src/uploader/index.ts","./src/uploader/utils.ts","./src/utils/checkpoint.ts","./src/utils/env.ts","./src/utils/exec.ts","./src/utils/file-tree.ts","./src/utils/file.ts","./src/utils/git.ts","./src/utils/html.ts","./src/utils/index.ts","./src/utils/json.ts","./src/utils/repo-tree.ts","./src/utils/slug.ts","./src/utils/string.ts","./src/utils/stripAnsi.ts"],"version":"5.8.3"}