@empiricalrun/test-gen 0.81.0 → 0.81.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.
Files changed (75) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/file-info/adapters/github/reader.d.ts +1 -1
  3. package/dist/file-info/adapters/github/reader.d.ts.map +1 -1
  4. package/dist/file-info/adapters/github/reader.js +7 -5
  5. package/dist/tools/create-pull-request/index.d.ts.map +1 -1
  6. package/dist/tools/create-pull-request/index.js +1 -3
  7. package/dist/tools/create-pull-request/utils.d.ts +1 -0
  8. package/dist/tools/create-pull-request/utils.d.ts.map +1 -1
  9. package/dist/tools/create-pull-request/utils.js +4 -0
  10. package/dist/tools/executor/utils/git.d.ts +2 -1
  11. package/dist/tools/executor/utils/git.d.ts.map +1 -1
  12. package/dist/tools/executor/utils/git.js +3 -2
  13. package/dist/tools/executor/utils/index.d.ts.map +1 -1
  14. package/dist/tools/executor/utils/index.js +4 -0
  15. package/package.json +9 -9
  16. package/tsconfig.tsbuildinfo +1 -1
  17. package/dist/agent/browsing/index.d.ts +0 -15
  18. package/dist/agent/browsing/index.d.ts.map +0 -1
  19. package/dist/agent/browsing/index.js +0 -60
  20. package/dist/agent/master/action-tool-calls.d.ts +0 -42
  21. package/dist/agent/master/action-tool-calls.d.ts.map +0 -1
  22. package/dist/agent/master/action-tool-calls.js +0 -87
  23. package/dist/agent/master/element-annotation.d.ts +0 -30
  24. package/dist/agent/master/element-annotation.d.ts.map +0 -1
  25. package/dist/agent/master/element-annotation.js +0 -175
  26. package/dist/agent/master/execute-browser-action.d.ts +0 -24
  27. package/dist/agent/master/execute-browser-action.d.ts.map +0 -1
  28. package/dist/agent/master/execute-browser-action.js +0 -121
  29. package/dist/agent/master/next-action.d.ts +0 -22
  30. package/dist/agent/master/next-action.d.ts.map +0 -1
  31. package/dist/agent/master/next-action.js +0 -97
  32. package/dist/agent/master/planner.d.ts +0 -15
  33. package/dist/agent/master/planner.d.ts.map +0 -1
  34. package/dist/agent/master/planner.js +0 -142
  35. package/dist/agent/master/run.d.ts +0 -17
  36. package/dist/agent/master/run.d.ts.map +0 -1
  37. package/dist/agent/master/run.js +0 -156
  38. package/dist/agent/master/scroller.d.ts +0 -15
  39. package/dist/agent/master/scroller.d.ts.map +0 -1
  40. package/dist/agent/master/scroller.js +0 -369
  41. package/dist/agent/master/with-hints.d.ts +0 -17
  42. package/dist/agent/master/with-hints.d.ts.map +0 -1
  43. package/dist/agent/master/with-hints.js +0 -103
  44. package/dist/agent/planner/run-time-planner.d.ts +0 -15
  45. package/dist/agent/planner/run-time-planner.d.ts.map +0 -1
  46. package/dist/agent/planner/run-time-planner.js +0 -98
  47. package/dist/agent/planner/run.d.ts +0 -7
  48. package/dist/agent/planner/run.d.ts.map +0 -1
  49. package/dist/agent/planner/run.js +0 -128
  50. package/dist/browser-injected-scripts/annotate-elements.js +0 -612
  51. package/dist/browser-injected-scripts/annotate-elements.spec.d.ts +0 -2
  52. package/dist/browser-injected-scripts/annotate-elements.spec.d.ts.map +0 -1
  53. package/dist/browser-injected-scripts/annotate-elements.spec.js +0 -202
  54. package/dist/browser-injected-scripts/annotate-elements.spec.ts +0 -327
  55. package/dist/generate-summary/frame-sampling.d.ts +0 -12
  56. package/dist/generate-summary/frame-sampling.d.ts.map +0 -1
  57. package/dist/generate-summary/frame-sampling.js +0 -72
  58. package/dist/generate-summary/generate-error-stack-summary.d.ts +0 -11
  59. package/dist/generate-summary/generate-error-stack-summary.d.ts.map +0 -1
  60. package/dist/generate-summary/generate-error-stack-summary.js +0 -41
  61. package/dist/generate-summary/generate-failed-step-screenshot-diff-summary.d.ts +0 -58
  62. package/dist/generate-summary/generate-failed-step-screenshot-diff-summary.d.ts.map +0 -1
  63. package/dist/generate-summary/generate-failed-step-screenshot-diff-summary.js +0 -460
  64. package/dist/generate-summary/generate-grouped-summary.d.ts +0 -18
  65. package/dist/generate-summary/generate-grouped-summary.d.ts.map +0 -1
  66. package/dist/generate-summary/generate-grouped-summary.js +0 -88
  67. package/dist/generate-summary/merge-summary.d.ts +0 -16
  68. package/dist/generate-summary/merge-summary.d.ts.map +0 -1
  69. package/dist/generate-summary/merge-summary.js +0 -43
  70. package/dist/generate-summary/pick-videos-for-comparison.d.ts +0 -9
  71. package/dist/generate-summary/pick-videos-for-comparison.d.ts.map +0 -1
  72. package/dist/generate-summary/pick-videos-for-comparison.js +0 -54
  73. package/dist/utils/env.d.ts +0 -2
  74. package/dist/utils/env.d.ts.map +0 -1
  75. package/dist/utils/env.js +0 -7
@@ -1,58 +0,0 @@
1
- import { LLMModel, LLMProvider, TraceClient } from "@empiricalrun/llm";
2
- import { Project } from "@empiricalrun/shared-types/api/projects";
3
- import { TestGroup } from "@empiricalrun/shared-types/failure-workflow";
4
- type ArgsT = {
5
- testRunId: number;
6
- test: TestGroup;
7
- trace?: TraceClient;
8
- project: Project;
9
- modelConfig?: {
10
- provider?: LLMProvider;
11
- providerApiKey?: string;
12
- model?: LLMModel;
13
- temperature?: number;
14
- prompt?: string;
15
- promptVersion?: number;
16
- };
17
- };
18
- type BeforeAction = {
19
- apiName: string;
20
- params: Record<string, any>;
21
- callId: string;
22
- type: "before";
23
- startTime: number;
24
- wallTime?: number;
25
- parentId?: string;
26
- stack?: {
27
- file: string;
28
- line: number;
29
- column: number;
30
- }[];
31
- };
32
- type ScreenshotsWithBase64 = {
33
- type: string;
34
- pageId: string;
35
- sha1: string;
36
- width: number;
37
- height: number;
38
- timestamp: number;
39
- base64?: string;
40
- };
41
- export declare const findSimilarActionFromList: ({ actionList, actionToFind, }: {
42
- actionList: BeforeAction[];
43
- actionToFind: BeforeAction;
44
- }) => BeforeAction;
45
- export declare const getFailedStep: ({ zipUrl, sendParentForBeforeAction, }: {
46
- testRunId?: number;
47
- zipUrl: string;
48
- sendParentForBeforeAction?: boolean;
49
- }) => Promise<BeforeAction>;
50
- export declare const getScreenshotsInFailedStepWindow: ({ failedStep, testRunId, zipUrl, isSuccessRun, }: {
51
- failedStep: BeforeAction;
52
- testRunId: number;
53
- zipUrl: string;
54
- isSuccessRun?: boolean;
55
- }) => Promise<ScreenshotsWithBase64[]>;
56
- export declare const generateFailedStepScreenshotDiffSummary: ({ testRunId, test, modelConfig, trace, project, }: ArgsT) => Promise<string>;
57
- export {};
58
- //# sourceMappingURL=generate-failed-step-screenshot-diff-summary.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"generate-failed-step-screenshot-diff-summary.d.ts","sourceRoot":"","sources":["../../src/generate-summary/generate-failed-step-screenshot-diff-summary.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,QAAQ,EACR,WAAW,EACX,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,6CAA6C,CAAC;AAaxE,KAAK,KAAK,GAAG;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE;QACZ,QAAQ,CAAC,EAAE,WAAW,CAAC;QACvB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,KAAK,CAAC,EAAE,QAAQ,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH,CAAC;AAwCF,KAAK,YAAY,GAAG;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC1D,CAAC;AAgBF,KAAK,qBAAqB,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAqDF,eAAO,MAAM,yBAAyB,GAAI,+BAGvC;IACD,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B,YAAY,EAAE,YAAY,CAAC;CAC5B,KAAG,YA6CH,CAAC;AAEF,eAAO,MAAM,aAAa,GAAU,wCAGjC;IACD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC,KAAG,OAAO,CAAC,YAAY,CA8DvB,CAAC;AAEF,eAAO,MAAM,gCAAgC,GAAU,kDAKpD;IACD,UAAU,EAAE,YAAY,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,KAAG,OAAO,CAAC,qBAAqB,EAAE,CA+OlC,CAAC;AAEF,eAAO,MAAM,uCAAuC,GAAU,mDAM3D,KAAK,KAAG,OAAO,CAAC,MAAM,CA2JxB,CAAC"}
@@ -1,460 +0,0 @@
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.generateFailedStepScreenshotDiffSummary = exports.getScreenshotsInFailedStepWindow = exports.getFailedStep = exports.findSimilarActionFromList = void 0;
7
- const llm_1 = require("@empiricalrun/llm");
8
- const r2_uploader_1 = require("@empiricalrun/r2-uploader");
9
- // import prompt from "../../../../prompts/video-diff-summary-prompt.handlebars";
10
- const trace_utils_1 = require("@empiricalrun/trace-utils");
11
- // import { waitUntil } from "@vercel/functions";
12
- const buffer_1 = require("buffer");
13
- // import fs from "fs";
14
- const lodash_isequal_1 = __importDefault(require("lodash.isequal"));
15
- const dedup_image_1 = require("../utils/dedup/dedup-image");
16
- const frame_sampling_1 = require("./frame-sampling");
17
- const responseFormat = {
18
- type: "json_schema",
19
- json_schema: {
20
- name: "screenshot-difference-with-failure-reason",
21
- strict: true,
22
- schema: {
23
- type: "object",
24
- required: ["difference_in_screenshots", "reason_for_test_failure"],
25
- properties: {
26
- difference_in_screenshots: {
27
- type: "string",
28
- description: "what has changed between the successful run and failed run screenshots",
29
- },
30
- reason_for_test_failure: {
31
- type: "string",
32
- description: "reason for test failure",
33
- },
34
- },
35
- additionalProperties: false,
36
- },
37
- },
38
- };
39
- const convertBufferToBase64 = (imageBuffer, mimeType) => {
40
- const base64Image = imageBuffer.toString("base64");
41
- const dataUrl = `data:${mimeType};base64,${base64Image}`;
42
- return dataUrl;
43
- };
44
- const uploadScreenshotsToR2 = async ({ successScreenshots, failureScreenshots, testRunId, project, test, }) => {
45
- try {
46
- const file = {
47
- buffer: buffer_1.Buffer.from(JSON.stringify({
48
- success: successScreenshots.map((screenshot) => {
49
- return screenshot.base64;
50
- }),
51
- failure: failureScreenshots.map((screenshot) => {
52
- return screenshot.base64;
53
- }),
54
- }), "utf-8"),
55
- fileName: `test-case-${test.testCaseId}-${test.slug}.json`,
56
- mimeType: "application/json",
57
- };
58
- const folderName = process.env.NODE_ENV === "production"
59
- ? "visual-comparison-screenshots"
60
- : "visual-comparison-screenshots-development";
61
- const fileUrls = await (0, r2_uploader_1.uploadInMemoryFiles)({
62
- files: [file],
63
- destinationDir: `${project.repo_name.replace("-tests", "")}/${testRunId}/${folderName}`,
64
- uploadBucket: "test-report",
65
- accountId: process.env.R2_ACCOUNT_ID,
66
- accessKeyId: process.env.R2_ACCESS_KEY_ID,
67
- secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
68
- });
69
- return fileUrls;
70
- }
71
- catch (e) {
72
- console.error(`[testRunId - ${testRunId}] uploadScreenshotsToR2 failed`, e);
73
- return {};
74
- }
75
- };
76
- const findSimilarActionFromList = ({ actionList, actionToFind, }) => {
77
- const actionStack = actionToFind?.stack?.[0];
78
- let matchingAction = actionList.find((currentAction) => {
79
- const currentStack = currentAction?.stack?.[0];
80
- return (currentStack?.file === actionStack?.file &&
81
- currentStack?.line === actionStack?.line &&
82
- currentStack?.column === actionStack?.column &&
83
- currentAction?.apiName === actionToFind?.apiName &&
84
- (0, lodash_isequal_1.default)(currentAction?.params, actionToFind?.params));
85
- });
86
- if (matchingAction) {
87
- return matchingAction;
88
- }
89
- matchingAction = actionList.find((currentAction) => {
90
- const currentStack = currentAction?.stack?.[0];
91
- return (currentStack?.file === actionStack?.file &&
92
- currentAction?.apiName === actionToFind?.apiName &&
93
- (0, lodash_isequal_1.default)(currentAction?.params, actionToFind?.params));
94
- });
95
- if (matchingAction) {
96
- return matchingAction;
97
- }
98
- matchingAction = actionList.find((currentAction) => {
99
- const currentStack = currentAction?.stack?.[0];
100
- return (currentStack?.file === actionStack?.file &&
101
- currentStack?.line === actionStack?.line &&
102
- currentStack?.column === actionStack?.column &&
103
- currentAction?.apiName === actionToFind?.apiName);
104
- });
105
- return matchingAction;
106
- };
107
- exports.findSimilarActionFromList = findSimilarActionFromList;
108
- const getFailedStep = async ({ zipUrl, sendParentForBeforeAction = true, }) => {
109
- const allTestActions = [];
110
- const testTraceFile = "test.trace";
111
- await (0, trace_utils_1.extractFileFromZip)({
112
- zipUrl,
113
- fileNames: [testTraceFile],
114
- chunkProcessor: (_, fileName) => {
115
- let testTraceTempBuffer = "";
116
- return (chunk) => {
117
- switch (fileName) {
118
- case testTraceFile: {
119
- testTraceTempBuffer += chunk;
120
- let lines = testTraceTempBuffer.split("\n");
121
- lines.slice(0, -1).forEach((line) => {
122
- const parsedEvent = JSON.parse(line);
123
- allTestActions.push(parsedEvent);
124
- });
125
- testTraceTempBuffer = lines[lines.length - 1];
126
- break;
127
- }
128
- default:
129
- break;
130
- }
131
- };
132
- },
133
- });
134
- const totalActions = allTestActions.length;
135
- let lastBeforeAction;
136
- let lastBeforeActionParent;
137
- for (let actionIndex = 0; actionIndex < totalActions; actionIndex++) {
138
- const currentAction = allTestActions[actionIndex];
139
- if (currentAction.type === "before") {
140
- lastBeforeAction = currentAction;
141
- }
142
- if (currentAction.type === "error") {
143
- break;
144
- }
145
- }
146
- // This handles cases where the failed step is inside a locator
147
- // patch method of playwright-utils, and our intent is to find
148
- // the parent action -- which is the caller in the actual test file
149
- const isPlaywrightUtilsPatch = lastBeforeAction?.stack?.some((stackFrame) => stackFrame.file.includes("@empiricalrun/playwright-utils"));
150
- if (isPlaywrightUtilsPatch && lastBeforeAction?.parentId) {
151
- lastBeforeActionParent = allTestActions.find((action) => action.type === "before" &&
152
- action.callId === lastBeforeAction?.parentId);
153
- }
154
- if (!lastBeforeAction) {
155
- throw new Error("No before action found before error");
156
- }
157
- // Return parent action if requested and available, otherwise return the last before action
158
- return sendParentForBeforeAction && lastBeforeActionParent
159
- ? lastBeforeActionParent
160
- : lastBeforeAction;
161
- };
162
- exports.getFailedStep = getFailedStep;
163
- const getScreenshotsInFailedStepWindow = async ({ failedStep, testRunId, zipUrl, isSuccessRun = false, }) => {
164
- try {
165
- const allTestActions = [];
166
- const allScreenshots = [];
167
- const stepIdToCallIdMap = {};
168
- const detailedBeforeTraceActions = [];
169
- const wallTimeToCallIdMap = {};
170
- const testTraceFile = "test.trace";
171
- const fileNames = await (0, trace_utils_1.getFilenamesInZip)(zipUrl, {
172
- recursive: false,
173
- });
174
- const detailedTraceFileList = fileNames.filter((fileName) => fileName.includes("trace.trace"));
175
- await (0, trace_utils_1.extractFileFromZip)({
176
- zipUrl,
177
- fileNames: [testTraceFile, ...detailedTraceFileList],
178
- chunkProcessor: (_, fileName) => {
179
- let testTraceTempBuffer = "";
180
- let detailedTraceTempBuffer = "";
181
- return (chunk) => {
182
- if (fileName === testTraceFile) {
183
- testTraceTempBuffer += chunk;
184
- let lines = testTraceTempBuffer.split("\n");
185
- lines.slice(0, -1).forEach((line) => {
186
- const parsedEvent = JSON.parse(line);
187
- if (parsedEvent.type === "before" ||
188
- parsedEvent.type === "after") {
189
- allTestActions.push(parsedEvent);
190
- }
191
- });
192
- testTraceTempBuffer = lines[lines.length - 1];
193
- }
194
- else if (fileName.includes("trace.trace")) {
195
- detailedTraceTempBuffer += chunk;
196
- let lines = detailedTraceTempBuffer.split("\n");
197
- lines.slice(0, -1).forEach((line) => {
198
- const parsedEvent = JSON.parse(line);
199
- if (parsedEvent.type === "screencast-frame") {
200
- allScreenshots.push({
201
- ...parsedEvent,
202
- sha1: `resources/${parsedEvent.sha1}`,
203
- });
204
- }
205
- else if (parsedEvent.type === "before") {
206
- detailedBeforeTraceActions.push(parsedEvent);
207
- if (parsedEvent.stepId) {
208
- stepIdToCallIdMap[parsedEvent.stepId] =
209
- parsedEvent;
210
- }
211
- if (parsedEvent.wallTime) {
212
- wallTimeToCallIdMap[parsedEvent.wallTime] =
213
- parsedEvent;
214
- }
215
- }
216
- });
217
- detailedTraceTempBuffer = lines[lines.length - 1];
218
- }
219
- };
220
- },
221
- });
222
- const beforeActions = allTestActions.filter((action) => {
223
- const isBefore = action.type === "before";
224
- return isBefore;
225
- });
226
- let currentFailedStep = (0, exports.findSimilarActionFromList)({
227
- actionList: beforeActions,
228
- actionToFind: failedStep,
229
- });
230
- // if the callId is a step then that mapping doesnt exist inside the detail trace.
231
- // we need to find the right step inside it to map it
232
- // currently assuming test.step can only be in case playwright utils patched apis
233
- if (currentFailedStep?.callId.includes("test.step")) {
234
- currentFailedStep =
235
- beforeActions.find((a) => a.parentId === currentFailedStep.callId) ||
236
- currentFailedStep;
237
- }
238
- // console.log("allscreenshots", allScreenshots.slice(0, 3));
239
- const failedStepIndex = beforeActions.findIndex((a) => {
240
- return a.callId === currentFailedStep.callId;
241
- });
242
- console.log("failedStepIndex", failedStepIndex);
243
- console.log("beforeActions", beforeActions[failedStepIndex]);
244
- let stepEndTime = allTestActions.find((action) => {
245
- return (action.type === "after" && action.callId === currentFailedStep.callId);
246
- }).endTime;
247
- let lastActionCapturedInTestTrace = currentFailedStep;
248
- let lastActionCapturedInDetailTrace = (stepIdToCallIdMap[currentFailedStep.callId] ||
249
- wallTimeToCallIdMap[currentFailedStep.wallTime]);
250
- if (!lastActionCapturedInDetailTrace) {
251
- const actionsTakenTillLastFailedStepInReverseOrder = beforeActions
252
- .slice(0, failedStepIndex)
253
- .reverse();
254
- const totalReversedActions = actionsTakenTillLastFailedStepInReverseOrder.length;
255
- for (let actionIndex = 0; actionIndex < totalReversedActions; actionIndex++) {
256
- const action = actionsTakenTillLastFailedStepInReverseOrder[actionIndex];
257
- const correspondingDetailTraceAction = stepIdToCallIdMap[action.callId] ||
258
- wallTimeToCallIdMap[action.wallTime];
259
- if (correspondingDetailTraceAction) {
260
- lastActionCapturedInTestTrace = action;
261
- lastActionCapturedInDetailTrace = correspondingDetailTraceAction;
262
- }
263
- if (lastActionCapturedInDetailTrace) {
264
- break;
265
- }
266
- }
267
- }
268
- const defaultWindowSize = 2000;
269
- const pageIdForFailedStep = lastActionCapturedInDetailTrace.pageId;
270
- const stepStartTime = isSuccessRun
271
- ? lastActionCapturedInTestTrace.startTime - defaultWindowSize / 2
272
- : lastActionCapturedInTestTrace.startTime;
273
- const endTime = isSuccessRun
274
- ? stepEndTime + defaultWindowSize
275
- : stepEndTime;
276
- // console.log("stepStartTime", stepStartTime);
277
- // console.log("endTime", endTime);
278
- const screenshotsForPage = allScreenshots.filter((screenshot) => {
279
- return screenshot.pageId === pageIdForFailedStep;
280
- });
281
- allScreenshots.sort((a, b) => a.timestamp - b.timestamp);
282
- const availableScreenshotTimestamps = screenshotsForPage.map((s) => s.timestamp);
283
- let screenshotsToConsider = allScreenshots.filter((screenshot) => {
284
- return (screenshot.pageId === pageIdForFailedStep &&
285
- screenshot.timestamp <= endTime &&
286
- screenshot.timestamp >= stepStartTime);
287
- });
288
- if (screenshotsToConsider.length === 0) {
289
- const lastScreenshotTimestamp = availableScreenshotTimestamps[availableScreenshotTimestamps.length - 1];
290
- // if the available screenshot timestamps are a lot less than the step start time
291
- // take a window of last 2 seconds from the end of the screenshot timeline
292
- if (lastScreenshotTimestamp < stepStartTime) {
293
- screenshotsToConsider = allScreenshots.filter((screenshot) => {
294
- return (screenshot.pageId === pageIdForFailedStep &&
295
- screenshot.timestamp <= lastScreenshotTimestamp &&
296
- screenshot.timestamp >= lastScreenshotTimestamp - defaultWindowSize);
297
- });
298
- }
299
- else {
300
- // if the failed step is in the middle of screenshot timestamp but no corresponding image is found
301
- // take a window of 4 seconds before and after the failed step
302
- screenshotsToConsider = allScreenshots.filter((screenshot) => {
303
- return (screenshot.pageId === pageIdForFailedStep &&
304
- screenshot.timestamp <= endTime + defaultWindowSize / 2 &&
305
- screenshot.timestamp >= stepStartTime - defaultWindowSize / 2);
306
- });
307
- }
308
- }
309
- const imageBufferMap = {};
310
- await (0, trace_utils_1.extractFileFromZip)({
311
- zipUrl,
312
- fileNames: screenshotsToConsider.map((s) => s.sha1),
313
- chunkProcessor: (_, fileName) => {
314
- imageBufferMap[fileName] = imageBufferMap[fileName] || [];
315
- return (chunk) => {
316
- if (chunk) {
317
- imageBufferMap[fileName].push(chunk);
318
- }
319
- };
320
- },
321
- });
322
- const screenshotsWithBase64 = screenshotsToConsider.map((screenshot) => {
323
- const imageBuffer = buffer_1.Buffer.concat(imageBufferMap[screenshot.sha1]);
324
- const base64 = convertBufferToBase64(imageBuffer, "image/jpeg");
325
- return {
326
- metadata: { ...screenshot, base64 },
327
- image: imageBuffer.toString("base64"),
328
- };
329
- });
330
- // console.log("SCREENSHOT", screenshotsWithBase64.length);
331
- const images = await (0, dedup_image_1.deduplicateImages)({
332
- base64Images: screenshotsWithBase64,
333
- threshold: 0.001,
334
- logPrefix: `TestRun: ${testRunId}`,
335
- });
336
- // console.log("DEDUPED IMAGES", images.length);
337
- return images.map((i) => i.metadata);
338
- }
339
- catch (e) {
340
- console.warn(`Error extracting screenshots for testRunId - "${testRunId}", zipUrl - "${zipUrl}"`, e?.message);
341
- return [];
342
- }
343
- };
344
- exports.getScreenshotsInFailedStepWindow = getScreenshotsInFailedStepWindow;
345
- const generateFailedStepScreenshotDiffSummary = async ({ testRunId, test, modelConfig, trace, project, }) => {
346
- if (!test.success?.trace && !test.failure?.trace) {
347
- console.warn(`[testRunId - ${testRunId}][test - ${test.title}] No success and failure trace found for test, exiting early ...`);
348
- return "";
349
- }
350
- if (!test.failure?.trace) {
351
- console.warn(`[testRunId - ${testRunId}][test - ${test.title}] No failure trace found for test, exiting early ...`);
352
- return "";
353
- }
354
- try {
355
- const failedStep = await (0, exports.getFailedStep)({
356
- testRunId,
357
- zipUrl: test.failure.trace,
358
- });
359
- let failureScreenshots = await (0, exports.getScreenshotsInFailedStepWindow)({
360
- failedStep,
361
- testRunId,
362
- zipUrl: test.failure.trace,
363
- });
364
- const totalFailureScreenshots = failureScreenshots?.length ?? 0;
365
- console.log(`[testRunId - ${testRunId}][test - ${test.title}] has - "${totalFailureScreenshots}" failure screenshots`);
366
- trace?.event({
367
- name: "collected-failure-actions",
368
- output: {
369
- success: true,
370
- data: { count: totalFailureScreenshots },
371
- },
372
- });
373
- if (!totalFailureScreenshots) {
374
- return "";
375
- }
376
- let successScreenshots = test.success.trace
377
- ? await (0, exports.getScreenshotsInFailedStepWindow)({
378
- failedStep,
379
- testRunId,
380
- zipUrl: test.success.trace,
381
- isSuccessRun: true,
382
- })
383
- : [];
384
- const totalSuccessScreenshots = successScreenshots?.length ?? 0;
385
- console.log(`[testRunId - ${testRunId}][test - ${test.title}] has - "${totalSuccessScreenshots}" success screenshots`);
386
- trace?.event({
387
- name: "collected-success-actions",
388
- output: {
389
- success: true,
390
- data: { count: totalSuccessScreenshots },
391
- },
392
- });
393
- const totalScreenshots = totalSuccessScreenshots + totalFailureScreenshots;
394
- const maxScreenshotsAllowed = 250;
395
- if (totalScreenshots > maxScreenshotsAllowed) {
396
- console.log(`[testRunId - ${testRunId}][testCaseId - ${test.testCaseId}] has - "${totalScreenshots}" screenshots, sampling to - "${maxScreenshotsAllowed}"`);
397
- const sampledList = (0, frame_sampling_1.sampleCombinedList)(failureScreenshots, successScreenshots, maxScreenshotsAllowed);
398
- failureScreenshots = sampledList.list1;
399
- successScreenshots = sampledList.list2;
400
- }
401
- // waitUntil(
402
- // uploadScreenshotsToR2({
403
- // successScreenshots,
404
- // failureScreenshots,
405
- // testRunId,
406
- // project,
407
- // test,
408
- // }),
409
- // );
410
- const modelProvider = modelConfig?.provider ?? "openai";
411
- const model = modelConfig?.model ?? "gpt-4o";
412
- const temperature = modelConfig?.temperature ?? 0.5;
413
- const llm = new llm_1.LLM({
414
- provider: modelProvider,
415
- defaultModel: model,
416
- });
417
- const generationTrace = trace?.generation({
418
- name: "generate-trace-screenshot-diff-summary",
419
- model,
420
- modelParameters: {
421
- temperature,
422
- },
423
- });
424
- const totalImageCount = successScreenshots.length + failureScreenshots.length;
425
- // If there are too many images LLM failes to respond within alloted timeout
426
- const imageDetail = totalImageCount > 40 ? "low" : "high";
427
- const messages = (0, llm_1.compilePrompt)("prompt", {
428
- successScreenshots: successScreenshots.map((s) => s.base64),
429
- failureScreenshots: failureScreenshots.map((s) => s.base64),
430
- errorStack: test.failure.stack,
431
- }, {
432
- imageDetail,
433
- });
434
- const llmResponse = await llm.createChatCompletion({
435
- messages,
436
- trace: generationTrace,
437
- modelParameters: {
438
- temperature,
439
- },
440
- responseFormat,
441
- });
442
- const parsedResponse = JSON.parse(llmResponse?.content);
443
- generationTrace?.end({
444
- output: {
445
- videoDiffSummary: JSON.stringify(parsedResponse),
446
- },
447
- usage: {
448
- input: llm.promptTokens,
449
- output: llm.completionTokens,
450
- unit: "TOKENS",
451
- },
452
- });
453
- return parsedResponse?.reason_for_test_failure ?? "";
454
- }
455
- catch (e) {
456
- console.error(`[testRunId - ${testRunId}][testCaseId - ${test.testCaseId}] Error generating trace screenshot diff summary`, e);
457
- return "";
458
- }
459
- };
460
- exports.generateFailedStepScreenshotDiffSummary = generateFailedStepScreenshotDiffSummary;
@@ -1,18 +0,0 @@
1
- import { TraceClient } from "@empiricalrun/llm";
2
- import { z } from "zod";
3
- declare const groupedSummarySchema: z.ZodArray<z.ZodObject<{
4
- testIds: z.ZodArray<z.ZodString>;
5
- groupSummary: z.ZodString;
6
- }, z.core.$strip>>;
7
- export type GroupedSummarySchemaType = z.infer<typeof groupedSummarySchema>;
8
- type ArgsT = {
9
- testRunId: number;
10
- tests: {
11
- testId: string;
12
- errorSummary: string;
13
- }[];
14
- trace?: TraceClient;
15
- };
16
- export declare const generateGroupedSummary: ({ testRunId, tests, trace, }: ArgsT) => Promise<GroupedSummarySchemaType | null>;
17
- export {};
18
- //# sourceMappingURL=generate-grouped-summary.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"generate-grouped-summary.d.ts","sourceRoot":"","sources":["../../src/generate-summary/generate-grouped-summary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,QAAA,MAAM,oBAAoB;;;kBAKzB,CAAC;AACF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AA0C5E,KAAK,KAAK,GAAG;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAClD,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,CAAC;AACF,eAAO,MAAM,sBAAsB,GAAU,8BAI1C,KAAK,KAAG,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAgDjD,CAAC"}
@@ -1,88 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateGroupedSummary = void 0;
4
- const llm_1 = require("@empiricalrun/llm");
5
- const zod_1 = require("zod");
6
- const promptTemplate_0 = "{{#section \"system\"}}\nYou are a software engineer, who is given a task is to summarize test failures\n\nThe test failures will be provided to you in this format\n```\n[\n {\n testId: string, // this is a unique id of the test\n errorSummary: string, // this is the error summary of the test failure\n }\n]\n```\n\nThe errorSummary for each test is in this format:\n```\n<reason for failure of the test>\n\n<steps taken in the tests before it failed>\n```\nYou need to group the tests based on the test failure reason. steps taken can be ignored\n\nYour output should be of the following format:\n```\n{\n \"groups\": [\n // Group 1\n {\n testIds: string[] // testIds grouped with similar errors\n groupSummary: string // a single error summary of all the grouped tests\n },\n // Group 2\n {\n testIds: string[]\n groupSummary: string\n },\n ... and so on\n ]\n}\n```\n\nThe group summary string should follow this format:\n```\n<common reason for failure of the tests>\n\n<common steps or pattern of steps taken in the tests before it failed>\n```\n\nFollow these instructions before responding with output:\n- Do not respond with backticks\n- The output should be a valid JSON object\n- Do not group tests which have different error summary\n- Do not drop useful information about unique elements, locators, status code, error messages in the summary\n- Avoid repetitions in the group summary content\n- Timeout difference in errorSummary can be ignored during grouping\n- If a test is grouped alone, just send its errorSummary as groupSummary. Do not make changes in this case\n{{/section}}\n\n{{#section \"user\"}}\nFollowing are the test failures which needs to be summarized:\n{{testList}}\n{{/section}}\n";
7
- const groupedSummarySchema = zod_1.z.array(zod_1.z.object({
8
- testIds: zod_1.z.array(zod_1.z.string()),
9
- groupSummary: zod_1.z.string(),
10
- }));
11
- const getResponseFormat = (availableTestIds) => ({
12
- type: "json_schema",
13
- json_schema: {
14
- name: "test-case-failure-grouped-summary",
15
- strict: true,
16
- schema: {
17
- type: "object",
18
- properties: {
19
- groups: {
20
- type: "array",
21
- description: "array containing tests grouped by similar error summaries",
22
- items: {
23
- type: "object",
24
- properties: {
25
- testIds: {
26
- type: "array",
27
- description: "array of test ids which are grouped together",
28
- items: {
29
- type: "string",
30
- description: "Unique identifier for the tests, provided by the user",
31
- enum: availableTestIds,
32
- },
33
- },
34
- groupSummary: {
35
- type: "string",
36
- description: "Summary of the grouped tests",
37
- },
38
- },
39
- required: ["testIds", "groupSummary"],
40
- additionalProperties: false,
41
- },
42
- },
43
- },
44
- required: ["groups"],
45
- additionalProperties: false,
46
- },
47
- },
48
- });
49
- const generateGroupedSummary = async ({ testRunId, tests, trace, }) => {
50
- let output = null;
51
- const availableTestIds = tests.map((t) => t.testId);
52
- try {
53
- const messages = (0, llm_1.compilePrompt)(promptTemplate_0, {
54
- testList: JSON.stringify(tests),
55
- });
56
- trace?.event({
57
- input: {
58
- testList: JSON.stringify(tests),
59
- },
60
- output: { messages },
61
- });
62
- const llm = new llm_1.LLM({
63
- trace,
64
- provider: "openai",
65
- defaultModel: "gpt-4o",
66
- });
67
- const llmResponse = await llm.createChatCompletion({
68
- messages,
69
- trace,
70
- modelParameters: {
71
- temperature: 0.2,
72
- },
73
- responseFormat: getResponseFormat(availableTestIds),
74
- });
75
- output = groupedSummarySchema.parse(JSON.parse(llmResponse?.content).groups);
76
- }
77
- catch (e) {
78
- console.error(`Error grouping tests, returning all tests without groups for testRunId - "${testRunId}"`, e?.message);
79
- output = tests.map((test) => {
80
- return {
81
- testIds: [test.testId],
82
- groupSummary: test.errorSummary,
83
- };
84
- });
85
- }
86
- return output;
87
- };
88
- exports.generateGroupedSummary = generateGroupedSummary;
@@ -1,16 +0,0 @@
1
- import { TraceClient } from "@empiricalrun/llm";
2
- import { TestGroup } from "@empiricalrun/shared-types/failure-workflow";
3
- type ArgsT = {
4
- testRunId: number;
5
- test: TestGroup;
6
- errorSummary: string;
7
- videoDiffSummary: string;
8
- networkFailures: {
9
- endpoint: string;
10
- status: number;
11
- }[];
12
- trace?: TraceClient;
13
- };
14
- export declare const mergeSummary: ({ testRunId, test, errorSummary: errorStackSummary, networkFailures, videoDiffSummary, trace, }: ArgsT) => Promise<string>;
15
- export {};
16
- //# sourceMappingURL=merge-summary.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"merge-summary.d.ts","sourceRoot":"","sources":["../../src/generate-summary/merge-summary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,6CAA6C,CAAC;AAGxE,KAAK,KAAK,GAAG;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACxD,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,CAAC;AACF,eAAO,MAAM,YAAY,GAAU,iGAOhC,KAAK,KAAG,OAAO,CAAC,MAAM,CA2CxB,CAAC"}