@empiricalrun/test-gen 0.79.3 → 0.79.5
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 +17 -0
- package/dist/agent/browsing/run.d.ts +1 -1
- package/dist/agent/browsing/run.d.ts.map +1 -1
- package/dist/agent/browsing/utils.d.ts +0 -7
- package/dist/agent/browsing/utils.d.ts.map +1 -1
- package/dist/agent/browsing/utils.js +1 -56
- package/dist/agent/chat/index.d.ts.map +1 -1
- package/dist/agent/chat/index.js +21 -2
- package/dist/agent/chat/prompt/pw-utils-docs.d.ts +1 -1
- package/dist/agent/chat/prompt/pw-utils-docs.d.ts.map +1 -1
- package/dist/agent/chat/prompt/pw-utils-docs.js +1 -1
- package/dist/agent/chat/prompt/trace-utils-docs.d.ts +2 -0
- package/dist/agent/chat/prompt/trace-utils-docs.d.ts.map +1 -0
- package/dist/agent/chat/prompt/trace-utils-docs.js +208 -0
- package/dist/agent/code-review/index.d.ts +1 -1
- package/dist/agent/code-review/index.d.ts.map +1 -1
- package/dist/agent/code-review/index.js +4 -4
- package/dist/agent/code-review/{parser.d.ts → xml-parser.d.ts} +1 -1
- package/dist/agent/code-review/xml-parser.d.ts.map +1 -0
- package/dist/agent/code-review/{parser.js → xml-parser.js} +1 -1
- package/dist/agent/fast-triage/index.d.ts.map +1 -1
- package/dist/agent/fast-triage/index.js +31 -3
- package/dist/agent/master/element-annotation.d.ts.map +1 -1
- package/dist/agent/master/element-annotation.js +2 -19
- package/dist/agent/master/run.d.ts +1 -1
- package/dist/agent/master/run.d.ts.map +1 -1
- package/dist/agent/master/run.js +1 -1
- package/dist/bin/index.js +0 -2
- package/dist/constants/index.d.ts +1 -1
- package/dist/constants/index.js +1 -1
- package/dist/dashboard/client.d.ts +2 -40
- package/dist/dashboard/client.d.ts.map +1 -1
- package/dist/dashboard/client.js +4 -206
- package/dist/dashboard/index.d.ts +2 -3
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +10 -10
- package/dist/dashboard/tool-response-from-sandbox.d.ts +2 -0
- package/dist/dashboard/tool-response-from-sandbox.d.ts.map +1 -0
- package/dist/dashboard/tool-response-from-sandbox.js +6 -0
- package/dist/dashboard/tool-response.d.ts +1 -4
- package/dist/dashboard/tool-response.d.ts.map +1 -1
- package/dist/dashboard/tool-response.js +5 -86
- package/dist/dashboard/types.d.ts +1 -8
- package/dist/dashboard/types.d.ts.map +1 -1
- package/dist/dashboard/types.js +4 -14
- package/dist/file/server.d.ts +1 -1
- package/dist/file/server.d.ts.map +1 -1
- package/dist/file-info/adapters/github/reader.d.ts.map +1 -1
- package/dist/file-info/adapters/github/reader.js +9 -3
- package/dist/generate-summary/generate-error-stack-summary.js +1 -4
- package/dist/generate-summary/generate-failed-step-screenshot-diff-summary.d.ts.map +1 -1
- package/dist/generate-summary/generate-failed-step-screenshot-diff-summary.js +8 -8
- package/dist/generate-summary/generate-grouped-summary.js +1 -4
- package/dist/generate-summary/merge-summary.js +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/recorder/index.d.ts.map +1 -1
- package/dist/recorder/index.js +2 -2
- package/dist/telemetry/index.d.ts +3 -3
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/index.js +8 -5
- package/dist/tools/analyse-video/index.js +1 -1
- package/dist/tools/definitions/publish-markdown-report.d.ts +8 -0
- package/dist/tools/definitions/publish-markdown-report.d.ts.map +1 -0
- package/dist/tools/definitions/publish-markdown-report.js +29 -0
- package/dist/tools/diagnosis-fetcher.d.ts +5 -0
- package/dist/tools/diagnosis-fetcher.d.ts.map +1 -1
- package/dist/tools/diagnosis-fetcher.js +17 -12
- package/dist/tools/executor/index.d.ts.map +1 -1
- package/dist/tools/executor/index.js +2 -2
- package/dist/tools/fetch-file/index.d.ts.map +1 -1
- package/dist/tools/fetch-file/index.js +11 -10
- package/dist/tools/fetch-file/utils.d.ts +13 -1
- package/dist/tools/fetch-file/utils.d.ts.map +1 -1
- package/dist/tools/fetch-file/utils.js +44 -118
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +9 -5
- package/dist/tools/issues-v1/index.d.ts +0 -2
- package/dist/tools/issues-v1/index.d.ts.map +1 -1
- package/dist/tools/issues-v1/index.js +1 -5
- package/dist/tools/publish-markdown-report/index.d.ts +3 -0
- package/dist/tools/publish-markdown-report/index.d.ts.map +1 -0
- package/dist/tools/publish-markdown-report/index.js +196 -0
- package/dist/tools/test-gen-browser.d.ts.map +1 -1
- package/dist/tools/test-gen-browser.js +4 -4
- package/dist/tools/trace-dot-zip/index.d.ts.map +1 -1
- package/dist/tools/trace-dot-zip/index.js +19 -9
- package/dist/utils/model.d.ts.map +1 -1
- package/dist/utils/model.js +2 -6
- package/package.json +4 -11
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/agent/code-review/parser.d.ts.map +0 -1
- package/dist/agent/cua/computer.d.ts +0 -14
- package/dist/agent/cua/computer.d.ts.map +0 -1
- package/dist/agent/cua/computer.js +0 -191
- package/dist/agent/cua/index.d.ts +0 -22
- package/dist/agent/cua/index.d.ts.map +0 -1
- package/dist/agent/cua/index.js +0 -254
- package/dist/agent/cua/model.d.ts +0 -25
- package/dist/agent/cua/model.d.ts.map +0 -1
- package/dist/agent/cua/model.js +0 -66
- package/dist/agent/cua/pw-codegen/element-from-point.d.ts +0 -10
- package/dist/agent/cua/pw-codegen/element-from-point.d.ts.map +0 -1
- package/dist/agent/cua/pw-codegen/element-from-point.js +0 -135
- package/dist/agent/cua/pw-codegen/factory.d.ts +0 -15
- package/dist/agent/cua/pw-codegen/factory.d.ts.map +0 -1
- package/dist/agent/cua/pw-codegen/factory.js +0 -59
- package/dist/agent/cua/pw-codegen/index.d.ts +0 -7
- package/dist/agent/cua/pw-codegen/index.d.ts.map +0 -1
- package/dist/agent/cua/pw-codegen/index.js +0 -14
- package/dist/agent/cua/pw-codegen/pw-event-sink/index.d.ts +0 -43
- package/dist/agent/cua/pw-codegen/pw-event-sink/index.d.ts.map +0 -1
- package/dist/agent/cua/pw-codegen/pw-event-sink/index.js +0 -250
- package/dist/agent/cua/pw-codegen/pw-pause/for-recorder.d.ts +0 -14
- package/dist/agent/cua/pw-codegen/pw-pause/for-recorder.d.ts.map +0 -1
- package/dist/agent/cua/pw-codegen/pw-pause/for-recorder.js +0 -88
- package/dist/agent/cua/pw-codegen/pw-pause/index.d.ts +0 -17
- package/dist/agent/cua/pw-codegen/pw-pause/index.d.ts.map +0 -1
- package/dist/agent/cua/pw-codegen/pw-pause/index.js +0 -117
- package/dist/agent/cua/pw-codegen/pw-pause/ipc.d.ts +0 -3
- package/dist/agent/cua/pw-codegen/pw-pause/ipc.d.ts.map +0 -1
- package/dist/agent/cua/pw-codegen/pw-pause/ipc.js +0 -13
- package/dist/agent/cua/pw-codegen/pw-pause/patch.d.ts +0 -24
- package/dist/agent/cua/pw-codegen/pw-pause/patch.d.ts.map +0 -1
- package/dist/agent/cua/pw-codegen/pw-pause/patch.js +0 -197
- package/dist/agent/cua/pw-codegen/pw-pause/types.d.ts +0 -14
- package/dist/agent/cua/pw-codegen/pw-pause/types.d.ts.map +0 -1
- package/dist/agent/cua/pw-codegen/pw-pause/types.js +0 -2
- package/dist/agent/cua/pw-codegen/pw-pause/utils.d.ts +0 -2
- package/dist/agent/cua/pw-codegen/pw-pause/utils.d.ts.map +0 -1
- package/dist/agent/cua/pw-codegen/pw-pause/utils.js +0 -6
- package/dist/agent/cua/pw-codegen/types.d.ts +0 -47
- package/dist/agent/cua/pw-codegen/types.d.ts.map +0 -1
- package/dist/agent/cua/pw-codegen/types.js +0 -2
- package/dist/agent/cua/pw-codegen/version.d.ts +0 -25
- package/dist/agent/cua/pw-codegen/version.d.ts.map +0 -1
- package/dist/agent/cua/pw-codegen/version.js +0 -86
- package/dist/agent/master/icon-descriptor/index.d.ts +0 -22
- package/dist/agent/master/icon-descriptor/index.d.ts.map +0 -1
- package/dist/agent/master/icon-descriptor/index.js +0 -249
- package/dist/agent/master/icon-descriptor/normalize-svg.d.ts +0 -2
- package/dist/agent/master/icon-descriptor/normalize-svg.d.ts.map +0 -1
- package/dist/agent/master/icon-descriptor/normalize-svg.js +0 -247
- package/dist/tools/issues-v1/create-issue.d.ts +0 -3
- package/dist/tools/issues-v1/create-issue.d.ts.map +0 -1
- package/dist/tools/issues-v1/create-issue.js +0 -72
- package/dist/tools/issues-v1/update-issue.d.ts +0 -3
- package/dist/tools/issues-v1/update-issue.d.ts.map +0 -1
- package/dist/tools/issues-v1/update-issue.js +0 -74
- package/dist/trace-utils/cli.d.ts +0 -3
- package/dist/trace-utils/cli.d.ts.map +0 -1
- package/dist/trace-utils/cli.js +0 -302
- package/dist/trace-utils/console.d.ts +0 -11
- package/dist/trace-utils/console.d.ts.map +0 -1
- package/dist/trace-utils/console.js +0 -74
- package/dist/trace-utils/dom-snapshot.d.ts +0 -19
- package/dist/trace-utils/dom-snapshot.d.ts.map +0 -1
- package/dist/trace-utils/dom-snapshot.js +0 -328
- package/dist/trace-utils/index.d.ts +0 -12
- package/dist/trace-utils/index.d.ts.map +0 -1
- package/dist/trace-utils/index.js +0 -28
- package/dist/trace-utils/network.d.ts +0 -16
- package/dist/trace-utils/network.d.ts.map +0 -1
- package/dist/trace-utils/network.js +0 -178
- package/dist/trace-utils/normalize-trace-url.d.ts +0 -2
- package/dist/trace-utils/normalize-trace-url.d.ts.map +0 -1
- package/dist/trace-utils/normalize-trace-url.js +0 -15
- package/dist/trace-utils/screenshots.d.ts +0 -24
- package/dist/trace-utils/screenshots.d.ts.map +0 -1
- package/dist/trace-utils/screenshots.js +0 -197
- package/dist/trace-utils/steps.d.ts +0 -10
- package/dist/trace-utils/steps.d.ts.map +0 -1
- package/dist/trace-utils/steps.js +0 -126
- package/dist/trace-utils/types.d.ts +0 -51
- package/dist/trace-utils/types.d.ts.map +0 -1
- package/dist/trace-utils/types.js +0 -2
- package/dist/utils/playwright-report-parser.d.ts +0 -2
- package/dist/utils/playwright-report-parser.d.ts.map +0 -1
- package/dist/utils/playwright-report-parser.js +0 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @empiricalrun/test-gen
|
|
2
2
|
|
|
3
|
+
## 0.79.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b58777e: refactor: extract CUA agent into standalone @empiricalrun/cua package
|
|
8
|
+
- fda9bc3: feat: extract DashboardAPIClient into standalone @empiricalrun/dashboard-client package
|
|
9
|
+
- Updated dependencies [b58777e]
|
|
10
|
+
- Updated dependencies [fda9bc3]
|
|
11
|
+
- @empiricalrun/cua@0.2.0
|
|
12
|
+
- @empiricalrun/dashboard-client@0.2.0
|
|
13
|
+
|
|
14
|
+
## 0.79.4
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- dc2e6c9: feat: dashboard api client upgrade
|
|
19
|
+
|
|
3
20
|
## 0.79.3
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,uCAAuC,CAAC;AAc9D,KAAK,iBAAiB,GAAG;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yBAAyB,EAAE,OAAO,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC,CAAC;AAEF,wBAAsB,8BAA8B,CAAC,EACnD,gBAAgB,EAChB,OAAO,EACP,YAAY,GACb,EAAE;IACD,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,CAAC,CAQlB;AAED,wBAAsB,gBAAgB,CAAC,EACrC,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,OAAO,EACP,OAAO,EACP,yBAAyB,EACzB,YAAY,GACb,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACvC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;CAC1B,CAAC,CA+FD"}
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import { Page } from "playwright";
|
|
2
2
|
import { PlaywrightTestConfig } from "playwright/test";
|
|
3
3
|
export declare function isRegExp(obj: any): obj is RegExp;
|
|
4
|
-
export declare function prepareBrowsingAgentTask(steps: string[]): string;
|
|
5
4
|
export declare function addImportForMethod(testFilePath: string, methodName: string): void;
|
|
6
5
|
export declare function replaceTodoWithCreateTest(testFilePath: string, repoDir: string): string | undefined;
|
|
7
|
-
export declare function markTestAsOnly({ testCaseName, testCaseSuites, specPath, }: {
|
|
8
|
-
testCaseName: string;
|
|
9
|
-
testCaseSuites: string[];
|
|
10
|
-
specPath: string;
|
|
11
|
-
}): Promise<void>;
|
|
12
6
|
export declare function injectPwLocatorGenerator(page: Page): Promise<void>;
|
|
13
7
|
/**
|
|
14
8
|
* function to read playwright config from the source repo
|
|
15
9
|
* @return {*} {Promise<PlaywrightTestConfig>}
|
|
16
10
|
*/
|
|
17
11
|
export declare function readPlaywrightConfig(repoDir: string): Promise<PlaywrightTestConfig>;
|
|
18
|
-
export declare function getValidProjectNames(playwrightConfig: PlaywrightTestConfig): Promise<string[]>;
|
|
19
12
|
/**
|
|
20
13
|
* detect the project name for the given file in playwright test repo
|
|
21
14
|
* if project and test file path for running test don't match, then playwright throws error
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/utils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/utils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAOvD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,MAAM,CAKhD;AAED,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAe1E;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,GACd,MAAM,GAAG,SAAS,CAsBpB;AAED,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,IAAI,iBA0GxD;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,oBAAoB,CAAC,CA2B/B;AAWD;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,oBAAoB,EACtC,gBAAgB,GAAE,MAAM,EAAU,GACjC,OAAO,CAAC,MAAM,CAAC,CA+CjB"}
|
|
@@ -4,13 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.isRegExp = isRegExp;
|
|
7
|
-
exports.prepareBrowsingAgentTask = prepareBrowsingAgentTask;
|
|
8
7
|
exports.addImportForMethod = addImportForMethod;
|
|
9
8
|
exports.replaceTodoWithCreateTest = replaceTodoWithCreateTest;
|
|
10
|
-
exports.markTestAsOnly = markTestAsOnly;
|
|
11
9
|
exports.injectPwLocatorGenerator = injectPwLocatorGenerator;
|
|
12
10
|
exports.readPlaywrightConfig = readPlaywrightConfig;
|
|
13
|
-
exports.getValidProjectNames = getValidProjectNames;
|
|
14
11
|
exports.detectProjectName = detectProjectName;
|
|
15
12
|
const fs_1 = __importDefault(require("fs"));
|
|
16
13
|
const minimatch_1 = require("minimatch");
|
|
@@ -22,11 +19,6 @@ function isRegExp(obj) {
|
|
|
22
19
|
return (obj instanceof RegExp ||
|
|
23
20
|
Object.prototype.toString.call(obj) === "[object RegExp]");
|
|
24
21
|
}
|
|
25
|
-
function prepareBrowsingAgentTask(steps) {
|
|
26
|
-
const sanitizedSteps = steps.map((step) => step.replace(/`/g, "\\`"));
|
|
27
|
-
const task = `${sanitizedSteps.join("\n")}\n`;
|
|
28
|
-
return task;
|
|
29
|
-
}
|
|
30
22
|
function addImportForMethod(testFilePath, methodName) {
|
|
31
23
|
// Instead of using "@empiricalrun/test-gen", we use the local dist file
|
|
32
24
|
// This is to avoid assuming that the test-gen package is installed in the project
|
|
@@ -50,50 +42,12 @@ function replaceTodoWithCreateTest(testFilePath, repoDir) {
|
|
|
50
42
|
addImportForMethod(absoluteTestFilePath, "createTest");
|
|
51
43
|
return todoContent;
|
|
52
44
|
}
|
|
53
|
-
async function markTestAsOnly({ testCaseName, testCaseSuites, specPath, }) {
|
|
54
|
-
const testFileContent = fs_1.default.readFileSync(specPath, "utf-8");
|
|
55
|
-
const { testBlock, testNode } = (0, web_1.getTypescriptTestBlock)({
|
|
56
|
-
scenarioName: testCaseName,
|
|
57
|
-
content: testFileContent,
|
|
58
|
-
suites: testCaseSuites,
|
|
59
|
-
});
|
|
60
|
-
const parentDescribe = (0, web_1.findFirstSerialDescribeBlock)(testNode);
|
|
61
|
-
const isFileMarkedSerial = await (0, web_1.hasTopLevelDescribeConfigureWithSerialMode)(specPath);
|
|
62
|
-
// add test.only / describe.only to the spec file so that only that block is executed
|
|
63
|
-
if (!isFileMarkedSerial) {
|
|
64
|
-
const updatedTestFileContent = newContentsWithTestOnly(testFileContent, testBlock, testBlock, parentDescribe?.getText() || "");
|
|
65
|
-
fs_1.default.writeFileSync(specPath, updatedTestFileContent);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function newContentsWithTestOnly(existingContents, originalTestBlock, updatedTestBlock, parentDescribeBlock) {
|
|
69
|
-
if (!parentDescribeBlock) {
|
|
70
|
-
const testMarkedAsOnly = updatedTestBlock.replace("test(", "test.only(");
|
|
71
|
-
return existingContents.replace(originalTestBlock, testMarkedAsOnly);
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
const updatedDescribeBlock = parentDescribeBlock.replace(originalTestBlock, updatedTestBlock);
|
|
75
|
-
// TODO: this should only happen when the describe block has "serial" execution
|
|
76
|
-
const describeMarkedAsOnly = updatedDescribeBlock.replace("test.describe(", "test.describe.only(");
|
|
77
|
-
return existingContents.replace(parentDescribeBlock, describeMarkedAsOnly);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
45
|
async function injectPwLocatorGenerator(page) {
|
|
81
|
-
let pathToInstalledTestGen = require.resolve(".").split("dist")[0];
|
|
82
|
-
if (process.env.RUNNING_BROWSER_TESTS_FOR_TEST_GEN) {
|
|
83
|
-
pathToInstalledTestGen = process.cwd();
|
|
84
|
-
}
|
|
85
|
-
const annotateElementPath = path_1.default.join(pathToInstalledTestGen, "dist", "browser-injected-scripts", "annotate-elements.js");
|
|
86
|
-
if (!fs_1.default.existsSync(annotateElementPath)) {
|
|
87
|
-
throw new Error(`annotate-elements.js not found at path: ${annotateElementPath}`);
|
|
88
|
-
}
|
|
89
46
|
const remoteScriptResponses = await Promise.all([
|
|
90
47
|
"https://assets-test.empirical.run/pw-selector.js",
|
|
91
48
|
"https://code.jquery.com/jquery-3.7.1.min.js",
|
|
92
49
|
].map((url) => fetch(url)));
|
|
93
|
-
const scripts = await Promise.all(
|
|
94
|
-
...remoteScriptResponses.map((r) => r.text()),
|
|
95
|
-
fs_1.default.readFileSync(annotateElementPath, "utf-8"),
|
|
96
|
-
]);
|
|
50
|
+
const scripts = await Promise.all(remoteScriptResponses.map((r) => r.text()));
|
|
97
51
|
page.on("load", async () => {
|
|
98
52
|
try {
|
|
99
53
|
await Promise.all(scripts.map((s) => page.addScriptTag({ content: s })));
|
|
@@ -219,15 +173,6 @@ function matchAgainstPattern(pattern, filePathToTest) {
|
|
|
219
173
|
return (0, minimatch_1.minimatch)(filePathToTest, pattern);
|
|
220
174
|
}
|
|
221
175
|
}
|
|
222
|
-
async function getValidProjectNames(playwrightConfig) {
|
|
223
|
-
if (!playwrightConfig.projects) {
|
|
224
|
-
return [];
|
|
225
|
-
}
|
|
226
|
-
const filteredProjectNames = playwrightConfig.projects
|
|
227
|
-
.map((p) => p.name)
|
|
228
|
-
.filter((p) => !!p);
|
|
229
|
-
return filteredProjectNames;
|
|
230
|
-
}
|
|
231
176
|
/**
|
|
232
177
|
* detect the project name for the given file in playwright test repo
|
|
233
178
|
* if project and test file path for running test don't match, then playwright throws error
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAsBpE,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAMpC,qBAAa,SAAS,CAAC,CAAC,CAAE,SAAQ,SAAS,CAAC,CAAC,CAAC;IAC5C,SAAS,CAAC,QAAQ,IAAI,WAAW;IA0B3B,iBAAiB,CACrB,eAAe,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GACvC,OAAO,CAAC,MAAM,CAAC;CAyGnB"}
|
package/dist/agent/chat/index.js
CHANGED
|
@@ -3,32 +3,49 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ChatAgent = void 0;
|
|
4
4
|
const tools_1 = require("../../tools");
|
|
5
5
|
const analyse_video_1 = require("../../tools/definitions/analyse-video");
|
|
6
|
+
const download_build_1 = require("../../tools/definitions/download-build");
|
|
7
|
+
const grep_1 = require("../../tools/definitions/grep");
|
|
8
|
+
const list_tests_and_projects_1 = require("../../tools/definitions/list-tests-and-projects");
|
|
9
|
+
const run_test_1 = require("../../tools/definitions/run-test");
|
|
6
10
|
const diagnosis_fetcher_1 = require("../../tools/diagnosis-fetcher");
|
|
11
|
+
const fetch_file_1 = require("../../tools/fetch-file");
|
|
12
|
+
const list_environments_1 = require("../../tools/list-environments");
|
|
7
13
|
const test_run_fetcher_1 = require("../../tools/test-run-fetcher");
|
|
8
14
|
const base_1 = require("../base");
|
|
9
15
|
const pw_utils_docs_1 = require("./prompt/pw-utils-docs");
|
|
10
16
|
const repo_1 = require("./prompt/repo");
|
|
11
17
|
const test_case_def_1 = require("./prompt/test-case-def");
|
|
18
|
+
const trace_utils_docs_1 = require("./prompt/trace-utils-docs");
|
|
12
19
|
class ChatAgent extends base_1.BaseAgent {
|
|
13
20
|
getTools() {
|
|
14
21
|
const custom = [
|
|
15
22
|
analyse_video_1.analyseVideo,
|
|
16
|
-
|
|
23
|
+
run_test_1.runTestTool,
|
|
24
|
+
grep_1.grepTool,
|
|
25
|
+
list_environments_1.listEnvironmentsTool,
|
|
26
|
+
download_build_1.downloadBuildTool,
|
|
27
|
+
fetch_file_1.fetchFileTool,
|
|
28
|
+
list_tests_and_projects_1.listProjectsTool,
|
|
29
|
+
list_tests_and_projects_1.listTestsForProjectTool,
|
|
17
30
|
...tools_1.testGenerationTools,
|
|
18
31
|
test_run_fetcher_1.fetchTestRunDetailsTool,
|
|
19
32
|
diagnosis_fetcher_1.fetchDiagnosisReportTool,
|
|
20
33
|
...(0, tools_1.textEditorToolsForModel)(this.selectedModel),
|
|
21
34
|
tools_1.safeBashTool,
|
|
22
|
-
...(this.
|
|
35
|
+
...(!(0, tools_1.hasBuiltInWebFetch)(this.selectedModel) ? [tools_1.scrapeHtmlTool] : []),
|
|
23
36
|
];
|
|
24
37
|
return {
|
|
25
38
|
custom,
|
|
26
39
|
builtInTextEditor: (0, tools_1.hasBuiltInTextEditor)(this.selectedModel),
|
|
40
|
+
builtInWebFetch: (0, tools_1.hasBuiltInWebFetch)(this.selectedModel)
|
|
41
|
+
? { enabled: true, max_uses: 1 }
|
|
42
|
+
: undefined,
|
|
27
43
|
};
|
|
28
44
|
}
|
|
29
45
|
async buildSystemPrompt(repoInfoBuilder) {
|
|
30
46
|
const repoInfo = await repoInfoBuilder();
|
|
31
47
|
const repoContext = await (0, repo_1.getRepoContextPrompt)(repoInfo);
|
|
48
|
+
const hasTraceUtils = this.featureFlags.includes("enableTraceUtilsViaBash");
|
|
32
49
|
const preamble = `
|
|
33
50
|
You are a helpful assistant that can answer questions and help with tasks related to writing and maintaining Playwright tests.
|
|
34
51
|
|
|
@@ -121,6 +138,8 @@ ${test_case_def_1.testCasesDefinitionPrompt}
|
|
|
121
138
|
# Recipes
|
|
122
139
|
${pw_utils_docs_1.playwrightUtilsDocs}
|
|
123
140
|
|
|
141
|
+
${trace_utils_docs_1.traceUtilsDoc}
|
|
142
|
+
|
|
124
143
|
# Repo context
|
|
125
144
|
${repoContext}
|
|
126
145
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const playwrightUtilsDocs = "\nYou can refer to the following recipes to learn how to write tests for different scenarios.\n\n<email-automation>\n\n# Email automation\n\n## Example usage\n\n### Dynamic email\n\nThis dynamically generates a random email address that can \nbe used for the test (e.g. invite a new user).\n\n```ts\nimport { EmailClient } from \"@empiricalrun/playwright-utils\";\nimport { expect } from \"@playwright/test\";\n\nconst client = new EmailClient();\nconst address = client.getAddress();\n\n// Input the `address` in the application\n// that sends the email.\n\n// Get email received on the `address`\nconst email = await client.waitForEmail();\nexpect(\n email.links.find((l) => l.text === \"Join your team\")\n).toBeTruthy();\n```\n\n### Static email\n\nThis uses a known (static) email that can be used to login\ninto an application.\n\nThis needs an email id (e.g. `test-login-user`). The email id\nis appended with the domain (managed internally) to get the full\nemail address.\n\n```ts\nimport { EmailClient } from \"@empiricalrun/playwright-utils\";\n\nconst emailId = `test-login-user`;\n\nconst client = new EmailClient({ emailId });\nconst address = client.getAddress(); // Returns full address with domain\n\n// Get email received on the `address`\nconst email = await client.waitForEmail();\n\n// Get login OTP\nconst loginCode = email.codes[0];\n```\n\n</email-automation>\n\n<fixtures>\n\nThe playwright-utils package provides fixtures that wrap around Playwright's built-in\n`page`, `context` fixtures to provide a mouse highlighter (which makes it easier to\nsee actions taken in a video).\n\nTo use this, you can use the `baseTestFixture` and `extendExpect` imports\nin your fixtures file.\n\n```ts\nimport { test as base, expect as baseExpect } from \"@playwright/test\";\nimport { baseTestFixture, extendExpect } from \"@empiricalrun/playwright-utils/test\";\n\nexport const test = baseTestFixture(base);\nexport const expect = extendExpect(baseExpect);\n```\n\n### Get a new browser context\n\nThis package provides a fixture `customContextPageProvider` which is a good way to create\na fresh, new browser context, and a page inside it.\n\nThere are two benefits of using this to create contexts or pages:\n1. Videos get recorded and attached to the test report\n2. Mouse highlights are available\n\n```ts\nimport { test, expect } from \"./fixtures\";\n\ntest(\"Example test\", async ({ page: builtInPage, customContextPageProvider }) => {\n // builtInPage is from default browser context\n const { page: newPage, context } = await customContextPageProvider();\n // newPage is from this other browser context\n});\n```\n\ncustomContextPageProvider can accept options to customize the browser context.\n\n```\n customContextPageProvider: (\n options?: BrowserContextOptions,\n ) => Promise<{ context: BrowserContext; page: Page }>;\n```\n\nFor example, pass { storageState: undefined } to create a new browser context without\nthe auth state of the current browser context. This is useful for multi-user scenarios.\n\n</fixtures>\n\n<video-labels>\n\n# Video Labels\n\nPages generate video recordings after test execution, with 1 page generating 1 video file (webm). \n\nIf your test case relies on multiple pages (e.g. for multi-user or multi-app flows), it can get difficult to\nknow which page does \"video-1.webm\" belong to.\n\nTo solve this, you should set video labels for pages. This will enable you to identify videos faster.\n\n## Usage\n\n```typescript\nimport { setVideoLabel } from '@empiricalrun/playwright-utils/test';\n\ntest('my test', async ({ page }) => {\n setVideoLabel(page, 'checkout-flow');\n // Video will be saved as 'checkout-flow.webm'\n});\n```\n\n## Multiple Contexts\n\n```typescript\ntest('multi-user scenario', async ({ page, customContextPageProvider }) => {\n setVideoLabel(page, 'host-page');\n\n const { page: guestPage } = await customContextPageProvider({ storageState: undefined });\n setVideoLabel(guestPage, 'guest-page');\n // Videos saved as 'guest-page.webm' and 'host-page.webm'\n});\n```\n\n## Notes\n\n- The default behavior is to label videos for multiple pages as: `video-0.webm`, `video-1.webm`, etc.\n- If setVideoLabel is called twice for the same page, the last label will be set\n\n</video-labels>\n\n";
|
|
1
|
+
export declare const playwrightUtilsDocs = "\nYou can refer to the following recipes to learn how to write or diagnose tests for different scenarios.\n\n<email-automation>\n\n# Email automation\n\n## Example usage\n\n### Dynamic email\n\nThis dynamically generates a random email address that can \nbe used for the test (e.g. invite a new user).\n\n```ts\nimport { EmailClient } from \"@empiricalrun/playwright-utils\";\nimport { expect } from \"@playwright/test\";\n\nconst client = new EmailClient();\nconst address = client.getAddress();\n\n// Input the `address` in the application\n// that sends the email.\n\n// Get email received on the `address`\nconst email = await client.waitForEmail();\nexpect(\n email.links.find((l) => l.text === \"Join your team\")\n).toBeTruthy();\n```\n\n### Static email\n\nThis uses a known (static) email that can be used to login\ninto an application.\n\nThis needs an email id (e.g. `test-login-user`). The email id\nis appended with the domain (managed internally) to get the full\nemail address.\n\n```ts\nimport { EmailClient } from \"@empiricalrun/playwright-utils\";\n\nconst emailId = `test-login-user`;\n\nconst client = new EmailClient({ emailId });\nconst address = client.getAddress(); // Returns full address with domain\n\n// Get email received on the `address`\nconst email = await client.waitForEmail();\n\n// Get login OTP\nconst loginCode = email.codes[0];\n```\n\n</email-automation>\n\n<fixtures>\n\nThe playwright-utils package provides fixtures that wrap around Playwright's built-in\n`page`, `context` fixtures to provide a mouse highlighter (which makes it easier to\nsee actions taken in a video).\n\nTo use this, you can use the `baseTestFixture` and `extendExpect` imports\nin your fixtures file.\n\n```ts\nimport { test as base, expect as baseExpect } from \"@playwright/test\";\nimport { baseTestFixture, extendExpect } from \"@empiricalrun/playwright-utils/test\";\n\nexport const test = baseTestFixture(base);\nexport const expect = extendExpect(baseExpect);\n```\n\n### Get a new browser context\n\nThis package provides a fixture `customContextPageProvider` which is a good way to create\na fresh, new browser context, and a page inside it.\n\nThere are two benefits of using this to create contexts or pages:\n1. Videos get recorded and attached to the test report\n2. Mouse highlights are available\n\n```ts\nimport { test, expect } from \"./fixtures\";\n\ntest(\"Example test\", async ({ page: builtInPage, customContextPageProvider }) => {\n // builtInPage is from default browser context\n const { page: newPage, context } = await customContextPageProvider();\n // newPage is from this other browser context\n});\n```\n\ncustomContextPageProvider can accept options to customize the browser context.\n\n```\n customContextPageProvider: (\n options?: BrowserContextOptions,\n ) => Promise<{ context: BrowserContext; page: Page }>;\n```\n\nFor example, pass { storageState: undefined } to create a new browser context without\nthe auth state of the current browser context. This is useful for multi-user scenarios.\n\n</fixtures>\n\n<video-labels>\n\n# Video Labels\n\nPages generate video recordings after test execution, with 1 page generating 1 video file (webm). \n\nIf your test case relies on multiple pages (e.g. for multi-user or multi-app flows), it can get difficult to\nknow which page does \"video-1.webm\" belong to.\n\nTo solve this, you should set video labels for pages. This will enable you to identify videos faster.\n\n## Usage\n\n```typescript\nimport { setVideoLabel } from '@empiricalrun/playwright-utils/test';\n\ntest('my test', async ({ page }) => {\n setVideoLabel(page, 'checkout-flow');\n // Video will be saved as 'checkout-flow.webm'\n});\n```\n\n## Multiple Contexts\n\n```typescript\ntest('multi-user scenario', async ({ page, customContextPageProvider }) => {\n setVideoLabel(page, 'host-page');\n\n const { page: guestPage } = await customContextPageProvider({ storageState: undefined });\n setVideoLabel(guestPage, 'guest-page');\n // Videos saved as 'guest-page.webm' and 'host-page.webm'\n});\n```\n\n## Notes\n\n- The default behavior is to label videos for multiple pages as: `video-0.webm`, `video-1.webm`, etc.\n- If setVideoLabel is called twice for the same page, the last label will be set\n\n</video-labels>\n\n";
|
|
2
2
|
//# sourceMappingURL=pw-utils-docs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pw-utils-docs.d.ts","sourceRoot":"","sources":["../../../../src/agent/chat/prompt/pw-utils-docs.ts"],"names":[],"mappings":"AA4IA,eAAO,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"pw-utils-docs.d.ts","sourceRoot":"","sources":["../../../../src/agent/chat/prompt/pw-utils-docs.ts"],"names":[],"mappings":"AA4IA,eAAO,MAAM,mBAAmB,itIAe/B,CAAC"}
|
|
@@ -139,7 +139,7 @@ test('multi-user scenario', async ({ page, customContextPageProvider }) => {
|
|
|
139
139
|
- If setVideoLabel is called twice for the same page, the last label will be set
|
|
140
140
|
`;
|
|
141
141
|
exports.playwrightUtilsDocs = `
|
|
142
|
-
You can refer to the following recipes to learn how to write tests for different scenarios.
|
|
142
|
+
You can refer to the following recipes to learn how to write or diagnose tests for different scenarios.
|
|
143
143
|
|
|
144
144
|
<email-automation>
|
|
145
145
|
${emailRecipe}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const traceUtilsDoc = "\n<trace-utils-cli>\n# Trace Utils\n\nCLI and library for inspecting Playwright `trace.zip` files.\n\n## Usage\n\nVia sandbox-cli:\n```bash\nsandbox-cli trace-utils <command> [options]\n```\n\n---\n\n## `steps`\n\nList all test steps from a trace.\n\n```bash\nsandbox-cli trace-utils steps --file <path> [--json]\n```\n\n| Option | Description | Default |\n|--------|-------------|---------|\n| `--file` | Path or URL to trace.zip | *required* |\n| `--json` | Output as JSON | `false` |\n\n---\n\n## `screenshots`\n\nExtract screenshots from a trace. Use either `--step` or `--start`/`--end` (one is required).\n\n```bash\n# By step ID\nsandbox-cli trace-utils screenshots --file <path> --step <id> [options]\n\n# By time range\nsandbox-cli trace-utils screenshots --file <path> --start <time> --end <time> [options]\n```\n\n| Option | Description | Default |\n|--------|-------------|---------|\n| `--file` | Path or URL to trace.zip | *required* |\n| `--step` | Step callId to extract around | - |\n| `--start` | Start time (HH:MM:SS.mmm) | - |\n| `--end` | End time (HH:MM:SS.mmm) | - |\n| `--page` | Page ID to filter by (required for multi-page traces with time-based extraction) | - |\n| `--before` | Milliseconds before step (only with --step) | `2000` |\n| `--after` | Milliseconds after step (only with --step) | `2000` |\n| `--max` | Maximum screenshots | `10` |\n| `--output` | Output directory | auto-generated in `/tmp` |\n\n**Examples:**\n\n```bash\n# 1. List steps to find callId or timestamps\nsandbox-cli trace-utils steps --file ./trace.zip\n\n# Output:\n# [test.step@36] locator.click(getByRole('button', { name: 'Create' })) (page@abc123)\n# 00:02:06.434 \u2192 00:02:06.543 (110ms)\n\n# 2a. Extract by step ID\nsandbox-cli trace-utils screenshots --file ./trace.zip --step \"test.step@36\"\n\n# 2b. Extract by time range (for multi-page traces, --page is required)\nsandbox-cli trace-utils screenshots --file ./trace.zip --start 00:02:06.000 --end 00:02:07.000 --page \"page@abc123\"\n```\n\n---\n\n## `network`\n\nSearch network requests. For multi-page traces, either `--step` or `--page` is required.\n\n```bash\nsandbox-cli trace-utils network --file <path> [filters] [options]\n```\n\n| Option | Description | Default |\n|--------|-------------|---------|\n| `--file` | Path or URL to trace.zip | *required* |\n| `--step <callId>` | Filter to requests during a specific step | - |\n| `--page` | Page ID to filter by (required for multi-page traces without --step) | - |\n| `--before <ms>` | Time before step to include (with --step) | `2000` |\n| `--after <ms>` | Time after step to include (with --step) | `2000` |\n| `--errors` | Show only failed requests (4xx, 5xx, no response) | - |\n| `--url <pattern>` | Filter by URL pattern (regex) | - |\n| `--method <method>` | Filter by HTTP method | - |\n| `--status <codes>` | Filter by status codes (e.g., `404,500`) | - |\n| `--json` | Output as JSON | `false` |\n\n**Examples:**\n\n```bash\n# Show all failed requests (for multi-page traces, specify --page)\nsandbox-cli trace-utils network --file ./trace.zip --errors --page \"page@abc123\"\n\n# Search for specific API calls\nsandbox-cli trace-utils network --file ./trace.zip --url \"/api/v1/users\" --page \"page@abc123\"\n\n# Failed POST requests\nsandbox-cli trace-utils network --file ./trace.zip --errors --method POST --page \"page@abc123\"\n\n# Network requests during a specific step (--page not required)\nsandbox-cli trace-utils network --file ./trace.zip --step \"pw:api@32\"\n```\n\n---\n\n## `console`\n\nView browser console output. For multi-page traces, `--page` is required.\n\n```bash\nsandbox-cli trace-utils console --file <path> [options]\n```\n\n| Option | Description | Default |\n|--------|-------------|---------|\n| `--file` | Path or URL to trace.zip | *required* |\n| `--page` | Page ID to filter by (required for multi-page traces) | - |\n| `--level` | Minimum level: `error`, `warning`, `info`, `debug` | `error` |\n| `--json` | Output as JSON | `false` |\n| `--search` | Filter logs containing text | - |\n\n---\n\n## `dom-snapshot`\n\nExtract DOM snapshot from a trace. Use either `--step` or `--time` (one is required).\n\n```bash\n# By step ID\nsandbox-cli trace-utils dom-snapshot --file <path> --step <id> [options]\n\n# By time (for multi-page traces, --page is required)\nsandbox-cli trace-utils dom-snapshot --file <path> --time <time> --page <pageId> [options]\n```\n\n| Option | Description | Default |\n|--------|-------------|---------|\n| `--file` | Path or URL to trace.zip | *required* |\n| `--step` | Step callId to extract snapshot for | - |\n| `--time` | Time to extract snapshot at (HH:MM:SS.mmm) | - |\n| `--page` | Page ID to filter by (required for multi-page traces with --time) | - |\n| `--type` | Snapshot type: `before`, `after`, `input` (only with --step) | `before` |\n| `--output` | Output file path | - |\n| `--json` | Output as JSON | `false` |\n\n**Snapshot types:**\n\n- `before` - DOM state when the step starts (default)\n- `after` - DOM state when the step completes\n- `input` - DOM state at the moment of user input (for click/fill actions)\n\n> **Tip for assertions:** For `expect` steps like `toBeVisible`, use `--type after` to see the DOM state when the assertion passed. The `before` snapshot may show a loading state if the test was waiting for an element to appear.\n\n**Examples:**\n\n```bash\n# 1. List steps to find callId\nsandbox-cli trace-utils steps --file ./trace.zip\n\n# 2. Extract DOM snapshot before a click step\nsandbox-cli trace-utils dom-snapshot --file ./trace.zip --step \"pw:api@32\" --type before\n\n# 3. Extract DOM snapshot after a step and save to file\nsandbox-cli trace-utils dom-snapshot --file ./trace.zip --step \"pw:api@32\" --type after --output ./snapshot.html\n\n# 4. For assertions, use --type after to see the DOM when assertion passed\nsandbox-cli trace-utils dom-snapshot --file ./trace.zip --step \"expect@43\" --type after\n\n# 5. Extract DOM snapshot at a specific time\nsandbox-cli trace-utils dom-snapshot --file ./trace.zip --time 00:02:06.434\n\n# 6. Get snapshot as JSON\nsandbox-cli trace-utils dom-snapshot --file ./trace.zip --step \"pw:api@32\" --json\n```\n\n**Output (default):**\n```\n# DOM Snapshot: locator.click\n# Step: pw:api@32\n# URL: https://example.com/dashboard\n# Viewport: 1280x720\n# Snapshot type: before\n\n<!DOCTYPE html>\n<html>\n <head>\n <title>Dashboard</title>\n ...\n </head>\n <body>\n ...\n </body>\n</html>\n```\n\n</trace-utils-cli>\n";
|
|
2
|
+
//# sourceMappingURL=trace-utils-docs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-utils-docs.d.ts","sourceRoot":"","sources":["../../../../src/agent/chat/prompt/trace-utils-docs.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,aAAa,w4MA2MzB,CAAC"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.traceUtilsDoc = void 0;
|
|
4
|
+
// TODO: Need a better way to keep this in sync with trace-utils/README.md
|
|
5
|
+
exports.traceUtilsDoc = `
|
|
6
|
+
<trace-utils-cli>
|
|
7
|
+
# Trace Utils
|
|
8
|
+
|
|
9
|
+
CLI and library for inspecting Playwright \`trace.zip\` files.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Via sandbox-cli:
|
|
14
|
+
\`\`\`bash
|
|
15
|
+
sandbox-cli trace-utils <command> [options]
|
|
16
|
+
\`\`\`
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## \`steps\`
|
|
21
|
+
|
|
22
|
+
List all test steps from a trace.
|
|
23
|
+
|
|
24
|
+
\`\`\`bash
|
|
25
|
+
sandbox-cli trace-utils steps --file <path> [--json]
|
|
26
|
+
\`\`\`
|
|
27
|
+
|
|
28
|
+
| Option | Description | Default |
|
|
29
|
+
|--------|-------------|---------|
|
|
30
|
+
| \`--file\` | Path or URL to trace.zip | *required* |
|
|
31
|
+
| \`--json\` | Output as JSON | \`false\` |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## \`screenshots\`
|
|
36
|
+
|
|
37
|
+
Extract screenshots from a trace. Use either \`--step\` or \`--start\`/\`--end\` (one is required).
|
|
38
|
+
|
|
39
|
+
\`\`\`bash
|
|
40
|
+
# By step ID
|
|
41
|
+
sandbox-cli trace-utils screenshots --file <path> --step <id> [options]
|
|
42
|
+
|
|
43
|
+
# By time range
|
|
44
|
+
sandbox-cli trace-utils screenshots --file <path> --start <time> --end <time> [options]
|
|
45
|
+
\`\`\`
|
|
46
|
+
|
|
47
|
+
| Option | Description | Default |
|
|
48
|
+
|--------|-------------|---------|
|
|
49
|
+
| \`--file\` | Path or URL to trace.zip | *required* |
|
|
50
|
+
| \`--step\` | Step callId to extract around | - |
|
|
51
|
+
| \`--start\` | Start time (HH:MM:SS.mmm) | - |
|
|
52
|
+
| \`--end\` | End time (HH:MM:SS.mmm) | - |
|
|
53
|
+
| \`--page\` | Page ID to filter by (required for multi-page traces with time-based extraction) | - |
|
|
54
|
+
| \`--before\` | Milliseconds before step (only with --step) | \`2000\` |
|
|
55
|
+
| \`--after\` | Milliseconds after step (only with --step) | \`2000\` |
|
|
56
|
+
| \`--max\` | Maximum screenshots | \`10\` |
|
|
57
|
+
| \`--output\` | Output directory | auto-generated in \`/tmp\` |
|
|
58
|
+
|
|
59
|
+
**Examples:**
|
|
60
|
+
|
|
61
|
+
\`\`\`bash
|
|
62
|
+
# 1. List steps to find callId or timestamps
|
|
63
|
+
sandbox-cli trace-utils steps --file ./trace.zip
|
|
64
|
+
|
|
65
|
+
# Output:
|
|
66
|
+
# [test.step@36] locator.click(getByRole('button', { name: 'Create' })) (page@abc123)
|
|
67
|
+
# 00:02:06.434 → 00:02:06.543 (110ms)
|
|
68
|
+
|
|
69
|
+
# 2a. Extract by step ID
|
|
70
|
+
sandbox-cli trace-utils screenshots --file ./trace.zip --step "test.step@36"
|
|
71
|
+
|
|
72
|
+
# 2b. Extract by time range (for multi-page traces, --page is required)
|
|
73
|
+
sandbox-cli trace-utils screenshots --file ./trace.zip --start 00:02:06.000 --end 00:02:07.000 --page "page@abc123"
|
|
74
|
+
\`\`\`
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## \`network\`
|
|
79
|
+
|
|
80
|
+
Search network requests. For multi-page traces, either \`--step\` or \`--page\` is required.
|
|
81
|
+
|
|
82
|
+
\`\`\`bash
|
|
83
|
+
sandbox-cli trace-utils network --file <path> [filters] [options]
|
|
84
|
+
\`\`\`
|
|
85
|
+
|
|
86
|
+
| Option | Description | Default |
|
|
87
|
+
|--------|-------------|---------|
|
|
88
|
+
| \`--file\` | Path or URL to trace.zip | *required* |
|
|
89
|
+
| \`--step <callId>\` | Filter to requests during a specific step | - |
|
|
90
|
+
| \`--page\` | Page ID to filter by (required for multi-page traces without --step) | - |
|
|
91
|
+
| \`--before <ms>\` | Time before step to include (with --step) | \`2000\` |
|
|
92
|
+
| \`--after <ms>\` | Time after step to include (with --step) | \`2000\` |
|
|
93
|
+
| \`--errors\` | Show only failed requests (4xx, 5xx, no response) | - |
|
|
94
|
+
| \`--url <pattern>\` | Filter by URL pattern (regex) | - |
|
|
95
|
+
| \`--method <method>\` | Filter by HTTP method | - |
|
|
96
|
+
| \`--status <codes>\` | Filter by status codes (e.g., \`404,500\`) | - |
|
|
97
|
+
| \`--json\` | Output as JSON | \`false\` |
|
|
98
|
+
|
|
99
|
+
**Examples:**
|
|
100
|
+
|
|
101
|
+
\`\`\`bash
|
|
102
|
+
# Show all failed requests (for multi-page traces, specify --page)
|
|
103
|
+
sandbox-cli trace-utils network --file ./trace.zip --errors --page "page@abc123"
|
|
104
|
+
|
|
105
|
+
# Search for specific API calls
|
|
106
|
+
sandbox-cli trace-utils network --file ./trace.zip --url "/api/v1/users" --page "page@abc123"
|
|
107
|
+
|
|
108
|
+
# Failed POST requests
|
|
109
|
+
sandbox-cli trace-utils network --file ./trace.zip --errors --method POST --page "page@abc123"
|
|
110
|
+
|
|
111
|
+
# Network requests during a specific step (--page not required)
|
|
112
|
+
sandbox-cli trace-utils network --file ./trace.zip --step "pw:api@32"
|
|
113
|
+
\`\`\`
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## \`console\`
|
|
118
|
+
|
|
119
|
+
View browser console output. For multi-page traces, \`--page\` is required.
|
|
120
|
+
|
|
121
|
+
\`\`\`bash
|
|
122
|
+
sandbox-cli trace-utils console --file <path> [options]
|
|
123
|
+
\`\`\`
|
|
124
|
+
|
|
125
|
+
| Option | Description | Default |
|
|
126
|
+
|--------|-------------|---------|
|
|
127
|
+
| \`--file\` | Path or URL to trace.zip | *required* |
|
|
128
|
+
| \`--page\` | Page ID to filter by (required for multi-page traces) | - |
|
|
129
|
+
| \`--level\` | Minimum level: \`error\`, \`warning\`, \`info\`, \`debug\` | \`error\` |
|
|
130
|
+
| \`--json\` | Output as JSON | \`false\` |
|
|
131
|
+
| \`--search\` | Filter logs containing text | - |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## \`dom-snapshot\`
|
|
136
|
+
|
|
137
|
+
Extract DOM snapshot from a trace. Use either \`--step\` or \`--time\` (one is required).
|
|
138
|
+
|
|
139
|
+
\`\`\`bash
|
|
140
|
+
# By step ID
|
|
141
|
+
sandbox-cli trace-utils dom-snapshot --file <path> --step <id> [options]
|
|
142
|
+
|
|
143
|
+
# By time (for multi-page traces, --page is required)
|
|
144
|
+
sandbox-cli trace-utils dom-snapshot --file <path> --time <time> --page <pageId> [options]
|
|
145
|
+
\`\`\`
|
|
146
|
+
|
|
147
|
+
| Option | Description | Default |
|
|
148
|
+
|--------|-------------|---------|
|
|
149
|
+
| \`--file\` | Path or URL to trace.zip | *required* |
|
|
150
|
+
| \`--step\` | Step callId to extract snapshot for | - |
|
|
151
|
+
| \`--time\` | Time to extract snapshot at (HH:MM:SS.mmm) | - |
|
|
152
|
+
| \`--page\` | Page ID to filter by (required for multi-page traces with --time) | - |
|
|
153
|
+
| \`--type\` | Snapshot type: \`before\`, \`after\`, \`input\` (only with --step) | \`before\` |
|
|
154
|
+
| \`--output\` | Output file path | - |
|
|
155
|
+
| \`--json\` | Output as JSON | \`false\` |
|
|
156
|
+
|
|
157
|
+
**Snapshot types:**
|
|
158
|
+
|
|
159
|
+
- \`before\` - DOM state when the step starts (default)
|
|
160
|
+
- \`after\` - DOM state when the step completes
|
|
161
|
+
- \`input\` - DOM state at the moment of user input (for click/fill actions)
|
|
162
|
+
|
|
163
|
+
> **Tip for assertions:** For \`expect\` steps like \`toBeVisible\`, use \`--type after\` to see the DOM state when the assertion passed. The \`before\` snapshot may show a loading state if the test was waiting for an element to appear.
|
|
164
|
+
|
|
165
|
+
**Examples:**
|
|
166
|
+
|
|
167
|
+
\`\`\`bash
|
|
168
|
+
# 1. List steps to find callId
|
|
169
|
+
sandbox-cli trace-utils steps --file ./trace.zip
|
|
170
|
+
|
|
171
|
+
# 2. Extract DOM snapshot before a click step
|
|
172
|
+
sandbox-cli trace-utils dom-snapshot --file ./trace.zip --step "pw:api@32" --type before
|
|
173
|
+
|
|
174
|
+
# 3. Extract DOM snapshot after a step and save to file
|
|
175
|
+
sandbox-cli trace-utils dom-snapshot --file ./trace.zip --step "pw:api@32" --type after --output ./snapshot.html
|
|
176
|
+
|
|
177
|
+
# 4. For assertions, use --type after to see the DOM when assertion passed
|
|
178
|
+
sandbox-cli trace-utils dom-snapshot --file ./trace.zip --step "expect@43" --type after
|
|
179
|
+
|
|
180
|
+
# 5. Extract DOM snapshot at a specific time
|
|
181
|
+
sandbox-cli trace-utils dom-snapshot --file ./trace.zip --time 00:02:06.434
|
|
182
|
+
|
|
183
|
+
# 6. Get snapshot as JSON
|
|
184
|
+
sandbox-cli trace-utils dom-snapshot --file ./trace.zip --step "pw:api@32" --json
|
|
185
|
+
\`\`\`
|
|
186
|
+
|
|
187
|
+
**Output (default):**
|
|
188
|
+
\`\`\`
|
|
189
|
+
# DOM Snapshot: locator.click
|
|
190
|
+
# Step: pw:api@32
|
|
191
|
+
# URL: https://example.com/dashboard
|
|
192
|
+
# Viewport: 1280x720
|
|
193
|
+
# Snapshot type: before
|
|
194
|
+
|
|
195
|
+
<!DOCTYPE html>
|
|
196
|
+
<html>
|
|
197
|
+
<head>
|
|
198
|
+
<title>Dashboard</title>
|
|
199
|
+
...
|
|
200
|
+
</head>
|
|
201
|
+
<body>
|
|
202
|
+
...
|
|
203
|
+
</body>
|
|
204
|
+
</html>
|
|
205
|
+
\`\`\`
|
|
206
|
+
|
|
207
|
+
</trace-utils-cli>
|
|
208
|
+
`;
|
|
@@ -4,7 +4,7 @@ import { BaseAgent } from "../base";
|
|
|
4
4
|
import { type CodeReviewResultV0, type CodeReviewResultV1, type CodeReviewResultV2, CodeReviewSeverity, CodeReviewVerdict } from "./types";
|
|
5
5
|
export type { CodeReviewResultV1, CodeReviewResultV0, CodeReviewResultV2 };
|
|
6
6
|
export { CodeReviewVerdict, CodeReviewSeverity };
|
|
7
|
-
export { convertXmlToV2Format } from "./parser";
|
|
7
|
+
export { convertXmlToV2Format } from "./xml-parser";
|
|
8
8
|
export type CodeReviewVersionedResult = CodeReviewResultV0 | CodeReviewResultV1 | CodeReviewResultV2;
|
|
9
9
|
export declare class CodeReviewAgent<T> extends BaseAgent<T> {
|
|
10
10
|
protected getTools(): ToolsForLLM;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/code-review/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,WAAW,EACZ,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAGpE,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/code-review/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,WAAW,EACZ,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAGpE,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAGjB,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,MAAM,yBAAyB,GACjC,kBAAkB,GAClB,kBAAkB,GAClB,kBAAkB,CAAC;AAEvB,qBAAa,eAAe,CAAC,CAAC,CAAE,SAAQ,SAAS,CAAC,CAAC,CAAC;IAClD,SAAS,CAAC,QAAQ,IAAI,WAAW;IAWjC,SAAS,IAAI,yBAAyB,GAAG,SAAS;cAmBlC,iBAAiB,CAC/B,eAAe,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GACvC,OAAO,CAAC,MAAM,CAAC;CAiInB"}
|
|
@@ -5,12 +5,12 @@ const tools_1 = require("../../tools");
|
|
|
5
5
|
const fetch_session_diff_1 = require("../../tools/fetch-session-diff");
|
|
6
6
|
const base_1 = require("../base");
|
|
7
7
|
const repo_1 = require("../chat/prompt/repo");
|
|
8
|
-
const parser_1 = require("./parser");
|
|
9
8
|
const types_1 = require("./types");
|
|
10
9
|
Object.defineProperty(exports, "CodeReviewSeverity", { enumerable: true, get: function () { return types_1.CodeReviewSeverity; } });
|
|
11
10
|
Object.defineProperty(exports, "CodeReviewVerdict", { enumerable: true, get: function () { return types_1.CodeReviewVerdict; } });
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const xml_parser_1 = require("./xml-parser");
|
|
12
|
+
var xml_parser_2 = require("./xml-parser");
|
|
13
|
+
Object.defineProperty(exports, "convertXmlToV2Format", { enumerable: true, get: function () { return xml_parser_2.convertXmlToV2Format; } });
|
|
14
14
|
class CodeReviewAgent extends base_1.BaseAgent {
|
|
15
15
|
getTools() {
|
|
16
16
|
const custom = [
|
|
@@ -35,7 +35,7 @@ class CodeReviewAgent extends base_1.BaseAgent {
|
|
|
35
35
|
if (!text) {
|
|
36
36
|
return undefined;
|
|
37
37
|
}
|
|
38
|
-
return (0,
|
|
38
|
+
return (0, xml_parser_1.convertXmlToV2Format)(text);
|
|
39
39
|
}
|
|
40
40
|
async buildSystemPrompt(repoInfoBuilder) {
|
|
41
41
|
const repoInfo = await repoInfoBuilder();
|
|
@@ -2,4 +2,4 @@ import { type CodeReviewResultV2 } from "./types";
|
|
|
2
2
|
export type { CodeReviewLineComment, CodeReviewResultV0, CodeReviewResultV1, CodeReviewResultV2, } from "./types";
|
|
3
3
|
export { CodeReviewSeverity, CodeReviewVerdict } from "./types";
|
|
4
4
|
export declare function convertXmlToV2Format(output: string): CodeReviewResultV2;
|
|
5
|
-
//# sourceMappingURL=parser.d.ts.map
|
|
5
|
+
//# sourceMappingURL=xml-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xml-parser.d.ts","sourceRoot":"","sources":["../../../src/agent/code-review/xml-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,kBAAkB,EAGxB,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAchE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAmFvE"}
|
|
@@ -41,7 +41,7 @@ function convertXmlToV2Format(output) {
|
|
|
41
41
|
: null;
|
|
42
42
|
if (severity !== null) {
|
|
43
43
|
lineComments.push({
|
|
44
|
-
file: fileMatch[1].trim(),
|
|
44
|
+
file: fileMatch[1].trim().replace(/^\/repo\//, ""),
|
|
45
45
|
line_start: parseInt(lineStartMatch[1].trim(), 10),
|
|
46
46
|
line_end: parseInt(lineEndMatch[1].trim(), 10),
|
|
47
47
|
severity: severity,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/fast-triage/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/fast-triage/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAapE,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC,qBAAa,eAAe,CAAC,CAAC,CAAE,SAAQ,SAAS,CAAC,CAAC,CAAC;IAClD,SAAS,CAAC,QAAQ,IAAI,WAAW;cAkBjB,iBAAiB,CAC/B,eAAe,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GACvC,OAAO,CAAC,MAAM,CAAC;CA+CnB"}
|
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FastTriageAgent = void 0;
|
|
4
4
|
const tools_1 = require("../../tools");
|
|
5
|
-
// import { traceUtils } from "../../tools/definitions/trace-utils";
|
|
6
5
|
// import { grepTool } from "../../tools/definitions/grep";
|
|
7
6
|
const diagnosis_fetcher_1 = require("../../tools/diagnosis-fetcher");
|
|
8
7
|
const fetch_file_1 = require("../../tools/fetch-file");
|
|
9
8
|
const list_environments_1 = require("../../tools/list-environments");
|
|
9
|
+
const publish_markdown_report_1 = require("../../tools/publish-markdown-report");
|
|
10
10
|
const test_run_fetcher_1 = require("../../tools/test-run-fetcher");
|
|
11
11
|
const base_1 = require("../base");
|
|
12
|
+
const trace_utils_docs_1 = require("../chat/prompt/trace-utils-docs");
|
|
12
13
|
class FastTriageAgent extends base_1.BaseAgent {
|
|
13
14
|
getTools() {
|
|
14
15
|
const tools = [
|
|
@@ -16,8 +17,9 @@ class FastTriageAgent extends base_1.BaseAgent {
|
|
|
16
17
|
test_run_fetcher_1.fetchTestRunDetailsTool,
|
|
17
18
|
list_environments_1.listEnvironmentsTool,
|
|
18
19
|
fetch_file_1.fetchFileTool,
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
tools_1.safeBashTool,
|
|
21
|
+
publish_markdown_report_1.publishMarkdownReportTool,
|
|
22
|
+
// TODO: Do we need grep?
|
|
21
23
|
// grepTool,
|
|
22
24
|
...(0, tools_1.textEditorToolsForModel)(this.selectedModel),
|
|
23
25
|
];
|
|
@@ -28,6 +30,7 @@ class FastTriageAgent extends base_1.BaseAgent {
|
|
|
28
30
|
}
|
|
29
31
|
async buildSystemPrompt(repoInfoBuilder) {
|
|
30
32
|
const _repoInfo = await repoInfoBuilder();
|
|
33
|
+
// TODO: Use repo knowledge - can that also replace "issues" as memory?
|
|
31
34
|
return `
|
|
32
35
|
You are a fast triage agent that quickly analyzes test failures. [PLACEHOLDER - to be refined]
|
|
33
36
|
|
|
@@ -44,6 +47,31 @@ Provide a concise summary of:
|
|
|
44
47
|
- Why it failed (root cause)
|
|
45
48
|
- Whether this is an app issue or a test issue
|
|
46
49
|
|
|
50
|
+
Use the bash tool to make use of trace-utils and fetch steps from traces,
|
|
51
|
+
errors in network calls, and screenshots around failures.
|
|
52
|
+
|
|
53
|
+
${trace_utils_docs_1.traceUtilsDoc}
|
|
54
|
+
|
|
55
|
+
# Expected output
|
|
56
|
+
|
|
57
|
+
A well-structured markdown report published via the publishMarkdownReport tool.
|
|
58
|
+
|
|
59
|
+
Your report must include:
|
|
60
|
+
- What failed and why (root cause analysis)
|
|
61
|
+
- Whether this is an app issue or a test issue
|
|
62
|
+
- Evidence from the failure: include screenshots (as file:// URLs), network logs, console logs, etc.
|
|
63
|
+
- Evidence from the last passing run when available: include screenshots showing the expected behavior
|
|
64
|
+
|
|
65
|
+
Use trace-utils to extract screenshots from both failing and passing runs. Reference them in your
|
|
66
|
+
markdown using file:// URLs (e.g. file:///path/to/screenshot.png). The publishMarkdownReport tool
|
|
67
|
+
will upload these files and replace them with public URLs automatically.
|
|
68
|
+
|
|
69
|
+
As your final step, always call the publishMarkdownReport tool with your complete markdown report.
|
|
70
|
+
|
|
71
|
+
# Things to keep in mind
|
|
72
|
+
|
|
73
|
+
Follow the action, not just the assertion - The console showed deletePlayer error. I should have immediately looked at screenshots around the click that triggered it (test.step@126 - the "Yes" click) rather than the failing expect (expect@92).
|
|
74
|
+
|
|
47
75
|
Today's date is ${new Date().toDateString()}
|
|
48
76
|
`;
|
|
49
77
|
}
|