@empiricalrun/playwright-utils 0.22.6 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/bundled/test-gen/actions/assert.d.ts +4 -0
- package/bundled/test-gen/actions/assert.d.ts.map +1 -0
- package/bundled/test-gen/actions/assert.js +50 -0
- package/bundled/test-gen/actions/click.d.ts +4 -0
- package/bundled/test-gen/actions/click.d.ts.map +1 -0
- package/bundled/test-gen/actions/click.js +51 -0
- package/bundled/test-gen/actions/constants/index.d.ts +2 -0
- package/bundled/test-gen/actions/constants/index.d.ts.map +1 -0
- package/bundled/test-gen/actions/constants/index.js +4 -0
- package/bundled/test-gen/actions/done.d.ts +4 -0
- package/bundled/test-gen/actions/done.d.ts.map +1 -0
- package/bundled/test-gen/actions/done.js +30 -0
- package/bundled/test-gen/actions/fill.d.ts +4 -0
- package/bundled/test-gen/actions/fill.d.ts.map +1 -0
- package/bundled/test-gen/actions/fill.js +82 -0
- package/bundled/test-gen/actions/goto.d.ts +4 -0
- package/bundled/test-gen/actions/goto.d.ts.map +1 -0
- package/bundled/test-gen/actions/goto.js +47 -0
- package/bundled/test-gen/actions/hover.d.ts +4 -0
- package/bundled/test-gen/actions/hover.d.ts.map +1 -0
- package/bundled/test-gen/actions/hover.js +51 -0
- package/bundled/test-gen/actions/index.d.ts +30 -0
- package/bundled/test-gen/actions/index.d.ts.map +1 -0
- package/bundled/test-gen/actions/index.js +159 -0
- package/bundled/test-gen/actions/next-task.d.ts +53 -0
- package/bundled/test-gen/actions/next-task.d.ts.map +1 -0
- package/bundled/test-gen/actions/next-task.js +58 -0
- package/bundled/test-gen/actions/press.d.ts +4 -0
- package/bundled/test-gen/actions/press.d.ts.map +1 -0
- package/bundled/test-gen/actions/press.js +56 -0
- package/bundled/test-gen/actions/skill.d.ts +21 -0
- package/bundled/test-gen/actions/skill.d.ts.map +1 -0
- package/bundled/test-gen/actions/skill.js +127 -0
- package/bundled/test-gen/actions/text-content.d.ts +4 -0
- package/bundled/test-gen/actions/text-content.d.ts.map +1 -0
- package/bundled/test-gen/actions/text-content.js +58 -0
- package/bundled/test-gen/actions/utils/index.d.ts +10 -0
- package/bundled/test-gen/actions/utils/index.d.ts.map +1 -0
- package/bundled/test-gen/actions/utils/index.js +109 -0
- package/bundled/test-gen/agent/browsing/index.d.ts +15 -0
- package/bundled/test-gen/agent/browsing/index.d.ts.map +1 -0
- package/bundled/test-gen/agent/browsing/index.js +68 -0
- package/bundled/test-gen/agent/browsing/run.d.ts +19 -0
- package/bundled/test-gen/agent/browsing/run.d.ts.map +1 -0
- package/bundled/test-gen/agent/browsing/run.js +88 -0
- package/bundled/test-gen/agent/browsing/utils.d.ts +41 -0
- package/bundled/test-gen/agent/browsing/utils.d.ts.map +1 -0
- package/bundled/test-gen/agent/browsing/utils.js +406 -0
- package/bundled/test-gen/agent/codegen/create-test-block.d.ts +9 -0
- package/bundled/test-gen/agent/codegen/create-test-block.d.ts.map +1 -0
- package/bundled/test-gen/agent/codegen/create-test-block.js +63 -0
- package/bundled/test-gen/agent/codegen/fix-ts-errors.d.ts +13 -0
- package/bundled/test-gen/agent/codegen/fix-ts-errors.d.ts.map +1 -0
- package/bundled/test-gen/agent/codegen/fix-ts-errors.js +80 -0
- package/bundled/test-gen/agent/codegen/generate-code-apply-changes.d.ts +13 -0
- package/bundled/test-gen/agent/codegen/generate-code-apply-changes.d.ts.map +1 -0
- package/bundled/test-gen/agent/codegen/generate-code-apply-changes.js +381 -0
- package/bundled/test-gen/agent/codegen/lexical-scoped-vars.d.ts +9 -0
- package/bundled/test-gen/agent/codegen/lexical-scoped-vars.d.ts.map +1 -0
- package/bundled/test-gen/agent/codegen/lexical-scoped-vars.js +56 -0
- package/bundled/test-gen/agent/codegen/repo-edit.d.ts +23 -0
- package/bundled/test-gen/agent/codegen/repo-edit.d.ts.map +1 -0
- package/bundled/test-gen/agent/codegen/repo-edit.js +86 -0
- package/bundled/test-gen/agent/codegen/run.d.ts +16 -0
- package/bundled/test-gen/agent/codegen/run.d.ts.map +1 -0
- package/bundled/test-gen/agent/codegen/run.js +119 -0
- package/bundled/test-gen/agent/codegen/skills-retriever.d.ts +26 -0
- package/bundled/test-gen/agent/codegen/skills-retriever.d.ts.map +1 -0
- package/bundled/test-gen/agent/codegen/skills-retriever.js +93 -0
- package/bundled/test-gen/agent/codegen/test-update-feedback.d.ts +12 -0
- package/bundled/test-gen/agent/codegen/test-update-feedback.d.ts.map +1 -0
- package/bundled/test-gen/agent/codegen/test-update-feedback.js +50 -0
- package/bundled/test-gen/agent/codegen/types.d.ts +25 -0
- package/bundled/test-gen/agent/codegen/types.d.ts.map +1 -0
- package/bundled/test-gen/agent/codegen/types.js +8 -0
- package/bundled/test-gen/agent/codegen/update-flow.d.ts +34 -0
- package/bundled/test-gen/agent/codegen/update-flow.d.ts.map +1 -0
- package/bundled/test-gen/agent/codegen/update-flow.js +300 -0
- package/bundled/test-gen/agent/codegen/use-skill.d.ts +11 -0
- package/bundled/test-gen/agent/codegen/use-skill.d.ts.map +1 -0
- package/bundled/test-gen/agent/codegen/use-skill.js +54 -0
- package/bundled/test-gen/agent/codegen/utils.d.ts +126 -0
- package/bundled/test-gen/agent/codegen/utils.d.ts.map +1 -0
- package/bundled/test-gen/agent/codegen/utils.js +416 -0
- package/bundled/test-gen/agent/diagnosis-agent/index.d.ts +18 -0
- package/bundled/test-gen/agent/diagnosis-agent/index.d.ts.map +1 -0
- package/bundled/test-gen/agent/diagnosis-agent/index.js +105 -0
- package/bundled/test-gen/agent/diagnosis-agent/strict-mode-violation.d.ts +9 -0
- package/bundled/test-gen/agent/diagnosis-agent/strict-mode-violation.d.ts.map +1 -0
- package/bundled/test-gen/agent/diagnosis-agent/strict-mode-violation.js +31 -0
- package/bundled/test-gen/agent/enrich-prompt/index.d.ts +12 -0
- package/bundled/test-gen/agent/enrich-prompt/index.d.ts.map +1 -0
- package/bundled/test-gen/agent/enrich-prompt/index.js +81 -0
- package/bundled/test-gen/agent/enrich-prompt/utils.d.ts +6 -0
- package/bundled/test-gen/agent/enrich-prompt/utils.d.ts.map +1 -0
- package/bundled/test-gen/agent/enrich-prompt/utils.js +12 -0
- package/bundled/test-gen/agent/infer-agent/index.d.ts +10 -0
- package/bundled/test-gen/agent/infer-agent/index.d.ts.map +1 -0
- package/bundled/test-gen/agent/infer-agent/index.js +70 -0
- package/bundled/test-gen/agent/master/action-tool-calls.d.ts +42 -0
- package/bundled/test-gen/agent/master/action-tool-calls.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/action-tool-calls.js +87 -0
- package/bundled/test-gen/agent/master/browser-tests/fixtures.d.ts +9 -0
- package/bundled/test-gen/agent/master/browser-tests/fixtures.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/browser-tests/fixtures.js +33 -0
- package/bundled/test-gen/agent/master/browser-tests/index.spec.d.ts +2 -0
- package/bundled/test-gen/agent/master/browser-tests/index.spec.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/browser-tests/index.spec.js +113 -0
- package/bundled/test-gen/agent/master/browser-tests/skills.spec.d.ts +2 -0
- package/bundled/test-gen/agent/master/browser-tests/skills.spec.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/browser-tests/skills.spec.js +109 -0
- package/bundled/test-gen/agent/master/element-annotation.d.ts +30 -0
- package/bundled/test-gen/agent/master/element-annotation.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/element-annotation.js +195 -0
- package/bundled/test-gen/agent/master/execute-browser-action.d.ts +24 -0
- package/bundled/test-gen/agent/master/execute-browser-action.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/execute-browser-action.js +124 -0
- package/bundled/test-gen/agent/master/execute-skill-action.d.ts +11 -0
- package/bundled/test-gen/agent/master/execute-skill-action.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/execute-skill-action.js +25 -0
- package/bundled/test-gen/agent/master/icon-descriptor/index.d.ts +22 -0
- package/bundled/test-gen/agent/master/icon-descriptor/index.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/icon-descriptor/index.js +250 -0
- package/bundled/test-gen/agent/master/icon-descriptor/normalize-svg.d.ts +2 -0
- package/bundled/test-gen/agent/master/icon-descriptor/normalize-svg.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/icon-descriptor/normalize-svg.js +248 -0
- package/bundled/test-gen/agent/master/next-action.d.ts +22 -0
- package/bundled/test-gen/agent/master/next-action.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/next-action.js +104 -0
- package/bundled/test-gen/agent/master/planner.d.ts +15 -0
- package/bundled/test-gen/agent/master/planner.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/planner.js +144 -0
- package/bundled/test-gen/agent/master/run.d.ts +15 -0
- package/bundled/test-gen/agent/master/run.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/run.js +274 -0
- package/bundled/test-gen/agent/master/scroller.d.ts +15 -0
- package/bundled/test-gen/agent/master/scroller.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/scroller.js +375 -0
- package/bundled/test-gen/agent/master/with-hints.d.ts +17 -0
- package/bundled/test-gen/agent/master/with-hints.d.ts.map +1 -0
- package/bundled/test-gen/agent/master/with-hints.js +102 -0
- package/bundled/test-gen/agent/planner/run-time-planner.d.ts +15 -0
- package/bundled/test-gen/agent/planner/run-time-planner.d.ts.map +1 -0
- package/bundled/test-gen/agent/planner/run-time-planner.js +100 -0
- package/bundled/test-gen/agent/planner/run.d.ts +7 -0
- package/bundled/test-gen/agent/planner/run.d.ts.map +1 -0
- package/bundled/test-gen/agent/planner/run.js +127 -0
- package/bundled/test-gen/agent/utils.d.ts +2 -0
- package/bundled/test-gen/agent/utils.d.ts.map +1 -0
- package/bundled/test-gen/agent/utils.js +12 -0
- package/bundled/test-gen/bin/index.d.ts +3 -0
- package/bundled/test-gen/bin/index.d.ts.map +1 -0
- package/bundled/test-gen/bin/index.js +212 -0
- package/bundled/test-gen/bin/logger/index.d.ts +14 -0
- package/bundled/test-gen/bin/logger/index.d.ts.map +1 -0
- package/bundled/test-gen/bin/logger/index.js +57 -0
- package/bundled/test-gen/bin/utils/context.d.ts +13 -0
- package/bundled/test-gen/bin/utils/context.d.ts.map +1 -0
- package/bundled/test-gen/bin/utils/context.js +67 -0
- package/bundled/test-gen/bin/utils/fs/index.d.ts +6 -0
- package/bundled/test-gen/bin/utils/fs/index.d.ts.map +1 -0
- package/bundled/test-gen/bin/utils/fs/index.js +63 -0
- package/bundled/test-gen/bin/utils/index.d.ts +9 -0
- package/bundled/test-gen/bin/utils/index.d.ts.map +1 -0
- package/bundled/test-gen/bin/utils/index.js +64 -0
- package/bundled/test-gen/bin/utils/platform/web/index.d.ts +78 -0
- package/bundled/test-gen/bin/utils/platform/web/index.d.ts.map +1 -0
- package/bundled/test-gen/bin/utils/platform/web/index.js +544 -0
- package/bundled/test-gen/bin/utils/platform/web/test-files/ts-path-import-validate.d.ts +2 -0
- package/bundled/test-gen/bin/utils/platform/web/test-files/ts-path-import-validate.d.ts.map +1 -0
- package/bundled/test-gen/bin/utils/platform/web/test-files/ts-path-import-validate.js +7 -0
- package/bundled/test-gen/bin/utils/scenarios/index.d.ts +6 -0
- package/bundled/test-gen/bin/utils/scenarios/index.d.ts.map +1 -0
- package/bundled/test-gen/bin/utils/scenarios/index.js +57 -0
- package/bundled/test-gen/browser-injected-scripts/annotate-elements.js +615 -0
- package/bundled/test-gen/browser-injected-scripts/annotate-elements.spec.d.ts +2 -0
- package/bundled/test-gen/browser-injected-scripts/annotate-elements.spec.d.ts.map +1 -0
- package/bundled/test-gen/browser-injected-scripts/annotate-elements.spec.js +207 -0
- package/bundled/test-gen/browser-injected-scripts/annotate-elements.spec.ts +332 -0
- package/bundled/test-gen/constants/index.d.ts +7 -0
- package/bundled/test-gen/constants/index.d.ts.map +1 -0
- package/bundled/test-gen/constants/index.js +18 -0
- package/bundled/test-gen/errors/index.d.ts +5 -0
- package/bundled/test-gen/errors/index.d.ts.map +1 -0
- package/bundled/test-gen/errors/index.js +9 -0
- package/bundled/test-gen/evals/add-scenario-agent.evals.d.ts +4 -0
- package/bundled/test-gen/evals/add-scenario-agent.evals.d.ts.map +1 -0
- package/bundled/test-gen/evals/add-scenario-agent.evals.js +44 -0
- package/bundled/test-gen/evals/append-create-test-agent.evals.d.ts +4 -0
- package/bundled/test-gen/evals/append-create-test-agent.evals.d.ts.map +1 -0
- package/bundled/test-gen/evals/append-create-test-agent.evals.js +117 -0
- package/bundled/test-gen/evals/fetch-pom-skills-agent.evals.d.ts +4 -0
- package/bundled/test-gen/evals/fetch-pom-skills-agent.evals.d.ts.map +1 -0
- package/bundled/test-gen/evals/fetch-pom-skills-agent.evals.js +36 -0
- package/bundled/test-gen/evals/infer-master-or-code-agent.evals.d.ts +4 -0
- package/bundled/test-gen/evals/infer-master-or-code-agent.evals.d.ts.map +1 -0
- package/bundled/test-gen/evals/infer-master-or-code-agent.evals.js +22 -0
- package/bundled/test-gen/evals/master-agent.evals.d.ts +4 -0
- package/bundled/test-gen/evals/master-agent.evals.d.ts.map +1 -0
- package/bundled/test-gen/evals/master-agent.evals.js +35 -0
- package/bundled/test-gen/evals/type.d.ts +12 -0
- package/bundled/test-gen/evals/type.d.ts.map +1 -0
- package/bundled/test-gen/evals/type.js +2 -0
- package/bundled/test-gen/evals/update-scenario-agent.evals.d.ts +4 -0
- package/bundled/test-gen/evals/update-scenario-agent.evals.d.ts.map +1 -0
- package/bundled/test-gen/evals/update-scenario-agent.evals.js +47 -0
- package/bundled/test-gen/file/client.d.ts +14 -0
- package/bundled/test-gen/file/client.d.ts.map +1 -0
- package/bundled/test-gen/file/client.js +48 -0
- package/bundled/test-gen/file/server.d.ts +13 -0
- package/bundled/test-gen/file/server.d.ts.map +1 -0
- package/bundled/test-gen/file/server.js +52 -0
- package/bundled/test-gen/human-in-the-loop/cli.d.ts +2 -0
- package/bundled/test-gen/human-in-the-loop/cli.d.ts.map +1 -0
- package/bundled/test-gen/human-in-the-loop/cli.js +24 -0
- package/bundled/test-gen/human-in-the-loop/index.d.ts +12 -0
- package/bundled/test-gen/human-in-the-loop/index.d.ts.map +1 -0
- package/bundled/test-gen/human-in-the-loop/index.js +30 -0
- package/bundled/test-gen/human-in-the-loop/ipc.d.ts +4 -0
- package/bundled/test-gen/human-in-the-loop/ipc.d.ts.map +1 -0
- package/bundled/test-gen/human-in-the-loop/ipc.js +47 -0
- package/bundled/test-gen/index.d.ts +4 -0
- package/bundled/test-gen/index.d.ts.map +1 -0
- package/bundled/test-gen/index.js +55 -0
- package/bundled/test-gen/package.json +106 -0
- package/bundled/test-gen/page/index.d.ts +11 -0
- package/bundled/test-gen/page/index.d.ts.map +1 -0
- package/bundled/test-gen/page/index.js +16 -0
- package/bundled/test-gen/prompts/lib/ts-transformer.d.ts +4 -0
- package/bundled/test-gen/prompts/lib/ts-transformer.d.ts.map +1 -0
- package/bundled/test-gen/prompts/lib/ts-transformer.js +92 -0
- package/bundled/test-gen/reporter/index.d.ts +33 -0
- package/bundled/test-gen/reporter/index.d.ts.map +1 -0
- package/bundled/test-gen/reporter/index.js +161 -0
- package/bundled/test-gen/session/index.d.ts +20 -0
- package/bundled/test-gen/session/index.d.ts.map +1 -0
- package/bundled/test-gen/session/index.js +105 -0
- package/bundled/test-gen/test-build/index.d.ts +10 -0
- package/bundled/test-gen/test-build/index.d.ts.map +1 -0
- package/bundled/test-gen/test-build/index.js +30 -0
- package/bundled/test-gen/types/index.d.ts +69 -0
- package/bundled/test-gen/types/index.d.ts.map +1 -0
- package/bundled/test-gen/types/index.js +2 -0
- package/bundled/test-gen/uploader/index.d.ts +26 -0
- package/bundled/test-gen/uploader/index.d.ts.map +1 -0
- package/bundled/test-gen/uploader/index.js +102 -0
- package/bundled/test-gen/utils/env.d.ts +2 -0
- package/bundled/test-gen/utils/env.d.ts.map +1 -0
- package/bundled/test-gen/utils/env.js +9 -0
- package/bundled/test-gen/utils/exec.d.ts +4 -0
- package/bundled/test-gen/utils/exec.d.ts.map +1 -0
- package/bundled/test-gen/utils/exec.js +45 -0
- package/bundled/test-gen/utils/file.d.ts +2 -0
- package/bundled/test-gen/utils/file.d.ts.map +1 -0
- package/bundled/test-gen/utils/file.js +25 -0
- package/bundled/test-gen/utils/html.d.ts +4 -0
- package/bundled/test-gen/utils/html.d.ts.map +1 -0
- package/bundled/test-gen/utils/html.js +46 -0
- package/bundled/test-gen/utils/index.d.ts +2 -0
- package/bundled/test-gen/utils/index.d.ts.map +1 -0
- package/bundled/test-gen/utils/index.js +5 -0
- package/bundled/test-gen/utils/pw-test.d.ts +3 -0
- package/bundled/test-gen/utils/pw-test.d.ts.map +1 -0
- package/bundled/test-gen/utils/pw-test.js +26 -0
- package/bundled/test-gen/utils/slug.d.ts +2 -0
- package/bundled/test-gen/utils/slug.d.ts.map +1 -0
- package/bundled/test-gen/utils/slug.js +18 -0
- package/bundled/test-gen/utils/string.d.ts +2 -0
- package/bundled/test-gen/utils/string.d.ts.map +1 -0
- package/bundled/test-gen/utils/string.js +9 -0
- package/dist/overlay-tests/click.spec.js +1 -1
- package/package.json +3 -3
- package/scripts/prepare-publish.js +42 -0
|
@@ -0,0 +1,88 @@
|
|
|
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.generateTestsUsingMasterAgent = void 0;
|
|
7
|
+
const detect_port_1 = __importDefault(require("detect-port"));
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const web_1 = require("../../bin/utils/platform/web");
|
|
10
|
+
const server_1 = require("../../file/server");
|
|
11
|
+
const exec_1 = require("../../utils/exec");
|
|
12
|
+
const utils_1 = require("./utils");
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
* Function to generate tests using master agent
|
|
16
|
+
* @export
|
|
17
|
+
* @param {GenerateTestsType} {
|
|
18
|
+
* testFilePath,
|
|
19
|
+
* filePathToUpdate,
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
async function generateTestsUsingMasterAgent({ testFilePath, filePathToUpdate, pwProjectsFilter, testGenToken, repoDir, }) {
|
|
23
|
+
// valiate if the file path and file to update are valid
|
|
24
|
+
// also warn users if they are on older version of test-gen
|
|
25
|
+
(0, utils_1.canRunMasterAgent)(testFilePath);
|
|
26
|
+
// detect available http port on the machine
|
|
27
|
+
const port = await (0, detect_port_1.default)(3030);
|
|
28
|
+
// start a file service to handle file updates from agent
|
|
29
|
+
// - also update the file path with updates when agent is done spitting out code
|
|
30
|
+
const fileService = new server_1.FileService({ port, repoDir });
|
|
31
|
+
await fileService.startFileService();
|
|
32
|
+
fileService.setFilePath(filePathToUpdate);
|
|
33
|
+
// read playwright config from ./playwright.config.ts of source repo
|
|
34
|
+
const playwrightConfig = await (0, utils_1.readPlaywrightConfig)(repoDir);
|
|
35
|
+
// detect the playwright project name for the given test file and playwright config
|
|
36
|
+
const project = await (0, utils_1.detectProjectName)(testFilePath, playwrightConfig, pwProjectsFilter);
|
|
37
|
+
const pageVar = await (0, web_1.getPageVariableNameFromCreateTest)(filePathToUpdate);
|
|
38
|
+
console.log(`Detected playwright project name: ${project}`);
|
|
39
|
+
// run playwright test which will internally run the master agent
|
|
40
|
+
const teardownFileRegex = /.*\.teardown\.ts/;
|
|
41
|
+
const testsDirectory = `${repoDir}/tests`;
|
|
42
|
+
const isTestRunTriggeredForTeardown = teardownFileRegex.test(testFilePath);
|
|
43
|
+
const teardowns = new utils_1.TeardownManager(testsDirectory);
|
|
44
|
+
if (!isTestRunTriggeredForTeardown) {
|
|
45
|
+
await teardowns.skipAll();
|
|
46
|
+
}
|
|
47
|
+
const command = `npx playwright test ${testFilePath} --retries 0 --project ${project} --timeout 0 --headed`;
|
|
48
|
+
let isError = false, error = "";
|
|
49
|
+
try {
|
|
50
|
+
await (0, exec_1.cmd)(command.split(" "), {
|
|
51
|
+
env: {
|
|
52
|
+
APP_PORT: port.toString(),
|
|
53
|
+
PW_TEST_HTML_REPORT_OPEN: "never",
|
|
54
|
+
// pass the test gen token so that the agent has the same configuration as cli
|
|
55
|
+
TEST_GEN_TOKEN: testGenToken,
|
|
56
|
+
PAGE_VAR_NAME: pageVar || "page",
|
|
57
|
+
DISPLAY: ":99",
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
error = `Failed to generate test using master agent ${e}`;
|
|
63
|
+
console.error(error);
|
|
64
|
+
isError = true;
|
|
65
|
+
}
|
|
66
|
+
if (!isTestRunTriggeredForTeardown) {
|
|
67
|
+
teardowns.unskipAll();
|
|
68
|
+
}
|
|
69
|
+
// clean up the file if there is any error
|
|
70
|
+
if (isError) {
|
|
71
|
+
try {
|
|
72
|
+
const fileContent = await fs_extra_1.default.readFile(filePathToUpdate, "utf-8");
|
|
73
|
+
const updatedContent = (0, web_1.replaceCreateTestWithNewCode)(filePathToUpdate, fileContent, "");
|
|
74
|
+
await fs_extra_1.default.writeFile(filePathToUpdate, updatedContent, "utf-8");
|
|
75
|
+
await (0, web_1.lintErrors)(filePathToUpdate);
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
console.error("Failed to remove extra scripts from files post test gen error", e);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// remove the test only from the file
|
|
82
|
+
await (0, web_1.removeTestOnly)(testFilePath);
|
|
83
|
+
if (isError) {
|
|
84
|
+
// throw the error because of which test gen failed
|
|
85
|
+
throw Error(error);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.generateTestsUsingMasterAgent = generateTestsUsingMasterAgent;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { TraceClient } from "@empiricalrun/llm";
|
|
2
|
+
import type { TestGenConfig } from "@empiricalrun/shared-types";
|
|
3
|
+
import { Page } from "playwright";
|
|
4
|
+
import { PlaywrightTestConfig } from "playwright/test";
|
|
5
|
+
export declare function isRegExp(obj: any): obj is RegExp;
|
|
6
|
+
export declare function prepareBrowsingAgentTask(steps: string[]): string;
|
|
7
|
+
/**
|
|
8
|
+
* Function to prepare test file for master agent to run
|
|
9
|
+
* @param {TestGenConfig} genConfig
|
|
10
|
+
* @return {*} {Promise<string>}
|
|
11
|
+
*/
|
|
12
|
+
export declare function prepareFileForMasterAgent(genConfig: TestGenConfig, trace?: TraceClient): Promise<string>;
|
|
13
|
+
export declare function injectPwLocatorGenerator(page: Page): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Function to validate if the test file path are valid.
|
|
16
|
+
* @throws if there are any missing dependencies for master agent to run.
|
|
17
|
+
* @param {string} filePath
|
|
18
|
+
*/
|
|
19
|
+
export declare function canRunMasterAgent(filePath: string): void;
|
|
20
|
+
/**
|
|
21
|
+
* function to read playwright config from the source repo
|
|
22
|
+
* @return {*} {Promise<PlaywrightTestConfig>}
|
|
23
|
+
*/
|
|
24
|
+
export declare function readPlaywrightConfig(repoDir: string): Promise<PlaywrightTestConfig>;
|
|
25
|
+
/**
|
|
26
|
+
* detect the project name for the given file in playwright test repo
|
|
27
|
+
* if project and test file path for running test don't match, then playwright throws error
|
|
28
|
+
* @param testFilePath
|
|
29
|
+
* @returns
|
|
30
|
+
*/
|
|
31
|
+
export declare function detectProjectName(testFilePath: string, playwrightConfig: PlaywrightTestConfig, pwProjectsFilter?: string[]): Promise<string>;
|
|
32
|
+
export declare class TeardownManager {
|
|
33
|
+
private directory;
|
|
34
|
+
constructor(directory: string);
|
|
35
|
+
private teardownFiles;
|
|
36
|
+
private getAllTeardownFiles;
|
|
37
|
+
private skipTeardownFile;
|
|
38
|
+
skipAll(): Promise<void>;
|
|
39
|
+
unskipAll(): void;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAI7E,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAsBvD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,MAAM,CAKhD;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,UAIvD;AA8FD;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,aAAa,EACxB,KAAK,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,CAAC,CA0DjB;AAyBD,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,IAAI,iBA2HxD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,QAIjD;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,oBAAoB,CAAC,CAM/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;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM;IACrC,OAAO,CAAC,aAAa,CAAqB;YAE5B,mBAAmB;YAUnB,gBAAgB;IAsBjB,OAAO;IAuBb,SAAS;CAKjB"}
|
|
@@ -0,0 +1,406 @@
|
|
|
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.TeardownManager = exports.detectProjectName = exports.readPlaywrightConfig = exports.canRunMasterAgent = exports.injectPwLocatorGenerator = exports.prepareFileForMasterAgent = exports.prepareBrowsingAgentTask = exports.isRegExp = void 0;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const minimatch_1 = require("minimatch");
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const ts_morph_1 = require("ts-morph");
|
|
11
|
+
const api_1 = __importDefault(require("tsx/cjs/api"));
|
|
12
|
+
const logger_1 = require("../../bin/logger");
|
|
13
|
+
const context_1 = require("../../bin/utils/context");
|
|
14
|
+
const fs_1 = require("../../bin/utils/fs");
|
|
15
|
+
const web_1 = require("../../bin/utils/platform/web");
|
|
16
|
+
const create_test_block_1 = require("../codegen/create-test-block");
|
|
17
|
+
const fix_ts_errors_1 = require("../codegen/fix-ts-errors");
|
|
18
|
+
const lexical_scoped_vars_1 = require("../codegen/lexical-scoped-vars");
|
|
19
|
+
const update_flow_1 = require("../codegen/update-flow");
|
|
20
|
+
function isRegExp(obj) {
|
|
21
|
+
return (obj instanceof RegExp ||
|
|
22
|
+
Object.prototype.toString.call(obj) === "[object RegExp]");
|
|
23
|
+
}
|
|
24
|
+
exports.isRegExp = isRegExp;
|
|
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
|
+
exports.prepareBrowsingAgentTask = prepareBrowsingAgentTask;
|
|
31
|
+
/**
|
|
32
|
+
* Function to prepare test file for update scenarios for master agent to run
|
|
33
|
+
* @param {TestGenConfig} genConfig
|
|
34
|
+
*/
|
|
35
|
+
async function prepareFileForUpdateScenario(genConfig, trace) {
|
|
36
|
+
const { specPath, testCase } = genConfig;
|
|
37
|
+
const { name, suites } = testCase;
|
|
38
|
+
await (0, web_1.addUserContextFixture)({
|
|
39
|
+
scenarioName: name,
|
|
40
|
+
filePath: specPath,
|
|
41
|
+
suites,
|
|
42
|
+
});
|
|
43
|
+
// update the test case with appropriate location for createTest
|
|
44
|
+
const [suggestion] = await (0, update_flow_1.appendCreateTestBlock)({
|
|
45
|
+
trace,
|
|
46
|
+
testCase,
|
|
47
|
+
file: specPath,
|
|
48
|
+
validateTypes: false,
|
|
49
|
+
options: genConfig.options,
|
|
50
|
+
});
|
|
51
|
+
const createTestFilePath = suggestion?.updatedFiles[0] || "";
|
|
52
|
+
console.log("appending to existing test block");
|
|
53
|
+
console.log("updated test file path", createTestFilePath);
|
|
54
|
+
const fetchScopeVariablesSpan = trace?.span({
|
|
55
|
+
name: "fetch-scope-variables",
|
|
56
|
+
input: {
|
|
57
|
+
createTestFilePath,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
const scopeVariables = await (0, lexical_scoped_vars_1.getLexicalScopedVars)({
|
|
61
|
+
file: await fs_extra_1.default.readFile(createTestFilePath, "utf-8"),
|
|
62
|
+
referencePoint: "await createTest",
|
|
63
|
+
trace: fetchScopeVariablesSpan,
|
|
64
|
+
});
|
|
65
|
+
fetchScopeVariablesSpan?.end({
|
|
66
|
+
name: "fetch-scope-variables",
|
|
67
|
+
output: {
|
|
68
|
+
variables: scopeVariables,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
await (0, web_1.appendScopeToCreateTest)(createTestFilePath, scopeVariables);
|
|
72
|
+
// extract the createTest function and pass the scoped vars
|
|
73
|
+
const updateFileSpan = trace?.span({
|
|
74
|
+
name: "update-file-span",
|
|
75
|
+
input: {
|
|
76
|
+
createTestFilePath,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
await fs_extra_1.default.writeFile(createTestFilePath, (0, web_1.addNewImport)(await fs_extra_1.default.readFile(createTestFilePath, "utf-8"), ["createTest"], "@empiricalrun/test-gen"));
|
|
80
|
+
updateFileSpan?.end();
|
|
81
|
+
const { pomPrompt, nonSpecFilePrompt } = await (0, context_1.contextForGeneration)(createTestFilePath);
|
|
82
|
+
await (0, fix_ts_errors_1.validateAndFixTypescriptErrors)({
|
|
83
|
+
trace,
|
|
84
|
+
file: createTestFilePath,
|
|
85
|
+
pomCode: pomPrompt,
|
|
86
|
+
nonSpecFileCode: nonSpecFilePrompt,
|
|
87
|
+
testCase: testCase,
|
|
88
|
+
options: genConfig.options,
|
|
89
|
+
});
|
|
90
|
+
const testFileContent = await fs_extra_1.default.readFile(specPath, "utf-8");
|
|
91
|
+
const { testBlock, testNode } = (0, web_1.getTypescriptTestBlock)({
|
|
92
|
+
scenarioName: name,
|
|
93
|
+
content: testFileContent,
|
|
94
|
+
suites,
|
|
95
|
+
});
|
|
96
|
+
const parentDescribe = (0, web_1.findFirstSerialDescribeBlock)(testNode);
|
|
97
|
+
const isFileMarkedSerial = await (0, web_1.hasTopLevelDescribeConfigureWithSerialMode)(specPath);
|
|
98
|
+
// add test.only / describe.only to the spec file so that only that block is executed
|
|
99
|
+
if (!isFileMarkedSerial) {
|
|
100
|
+
const updatedTestFileContent = newContentsWithTestOnly(testFileContent, testBlock, testBlock, parentDescribe?.getText() || "");
|
|
101
|
+
await fs_extra_1.default.writeFile(specPath, updatedTestFileContent);
|
|
102
|
+
}
|
|
103
|
+
return createTestFilePath;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Function to prepare test file for master agent to run
|
|
107
|
+
* @param {TestGenConfig} genConfig
|
|
108
|
+
* @return {*} {Promise<string>}
|
|
109
|
+
*/
|
|
110
|
+
async function prepareFileForMasterAgent(genConfig, trace) {
|
|
111
|
+
const prepareFileSpan = trace?.span({
|
|
112
|
+
name: "prepare-file-for-master-agent",
|
|
113
|
+
});
|
|
114
|
+
new logger_1.CustomLogger({ useReporter: true }).log(`Preparing file for master agent. [view trace](${trace?.getTraceUrl()})`);
|
|
115
|
+
const { specPath, testCase } = genConfig;
|
|
116
|
+
const { name, suites } = testCase;
|
|
117
|
+
// check if the spec file exists
|
|
118
|
+
// if no then create a new file with test and expect imports
|
|
119
|
+
if (!fs_extra_1.default.existsSync(specPath)) {
|
|
120
|
+
const fileCreateSpan = prepareFileSpan?.span({
|
|
121
|
+
name: "create-file",
|
|
122
|
+
input: { specPath },
|
|
123
|
+
});
|
|
124
|
+
await fs_extra_1.default.createFile(specPath);
|
|
125
|
+
const fileContentWithImports = (0, web_1.addNewImport)("", ["test", "expect"], (0, web_1.getFixtureImportPath)(specPath));
|
|
126
|
+
await fs_extra_1.default.writeFile(specPath, fileContentWithImports, "utf-8");
|
|
127
|
+
fileCreateSpan?.end({ output: { specPath, fileContentWithImports } });
|
|
128
|
+
}
|
|
129
|
+
const existingContents = await fs_extra_1.default.readFile(specPath, "utf-8");
|
|
130
|
+
const { testBlock } = (0, web_1.getTypescriptTestBlock)({
|
|
131
|
+
scenarioName: name,
|
|
132
|
+
suites,
|
|
133
|
+
content: existingContents,
|
|
134
|
+
});
|
|
135
|
+
if (!testBlock) {
|
|
136
|
+
const newTestBlock = await (0, create_test_block_1.createEmptyTestCaseBlock)({
|
|
137
|
+
trace: prepareFileSpan,
|
|
138
|
+
testCase: genConfig.testCase,
|
|
139
|
+
file: specPath,
|
|
140
|
+
options: genConfig.options,
|
|
141
|
+
});
|
|
142
|
+
await fs_extra_1.default.writeFile(specPath, `${existingContents} \n\n ${newTestBlock}`, "utf-8");
|
|
143
|
+
const updatedContent = (0, web_1.injectCodeSnippetBySuiteChain)({
|
|
144
|
+
testFileContent: existingContents,
|
|
145
|
+
suites: testCase.suites,
|
|
146
|
+
codeSnippet: `\n\n${newTestBlock}`,
|
|
147
|
+
});
|
|
148
|
+
await fs_extra_1.default.writeFile(specPath, updatedContent, "utf-8");
|
|
149
|
+
}
|
|
150
|
+
const updatePath = await prepareFileForUpdateScenario(genConfig, prepareFileSpan);
|
|
151
|
+
return updatePath;
|
|
152
|
+
}
|
|
153
|
+
exports.prepareFileForMasterAgent = prepareFileForMasterAgent;
|
|
154
|
+
function newContentsWithTestOnly(existingContents, originalTestBlock, updatedTestBlock, parentDescribeBlock) {
|
|
155
|
+
if (!parentDescribeBlock) {
|
|
156
|
+
const testMarkedAsOnly = updatedTestBlock.replace("test(", "test.only(");
|
|
157
|
+
return existingContents.replace(originalTestBlock, testMarkedAsOnly);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
const updatedDescribeBlock = parentDescribeBlock.replace(originalTestBlock, updatedTestBlock);
|
|
161
|
+
// TODO: this should only happen when the describe block has "serial" execution
|
|
162
|
+
const describeMarkedAsOnly = updatedDescribeBlock.replace("test.describe(", "test.describe.only(");
|
|
163
|
+
return existingContents.replace(parentDescribeBlock, describeMarkedAsOnly);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async function injectPwLocatorGenerator(page) {
|
|
167
|
+
let pathToInstalledTestGen = require.resolve(".").split("dist")[0];
|
|
168
|
+
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
169
|
+
if (process.env.RUNNING_BROWSER_TESTS_FOR_TEST_GEN) {
|
|
170
|
+
pathToInstalledTestGen = process.cwd();
|
|
171
|
+
}
|
|
172
|
+
const annotateElementPath = path_1.default.join(pathToInstalledTestGen, "dist", "browser-injected-scripts", "annotate-elements.js");
|
|
173
|
+
if (!fs_extra_1.default.existsSync(annotateElementPath)) {
|
|
174
|
+
throw new Error(`annotate-elements.js not found at path: ${annotateElementPath}`);
|
|
175
|
+
}
|
|
176
|
+
const remoteScriptResponses = await Promise.all([
|
|
177
|
+
"https://assets-test.empirical.run/pw-selector.js",
|
|
178
|
+
"https://code.jquery.com/jquery-3.7.1.min.js",
|
|
179
|
+
].map((url) => fetch(url)));
|
|
180
|
+
const scripts = await Promise.all([
|
|
181
|
+
...remoteScriptResponses.map((r) => r.text()),
|
|
182
|
+
fs_extra_1.default.readFile(annotateElementPath, "utf-8"),
|
|
183
|
+
]);
|
|
184
|
+
page.on("load", async () => {
|
|
185
|
+
try {
|
|
186
|
+
await Promise.all(scripts.map((s) => page.addScriptTag({ content: s })));
|
|
187
|
+
await page.evaluate(async () => {
|
|
188
|
+
//@ts-ignore
|
|
189
|
+
//https://developer.mozilla.org/en-US/docs/Web/API/TrustedScriptURL
|
|
190
|
+
const trustedPolicy = window.trustedTypes?.createPolicy(crypto.randomUUID(), {
|
|
191
|
+
createScriptURL: (url) => url,
|
|
192
|
+
});
|
|
193
|
+
//@ts-ignore
|
|
194
|
+
const injectScriptInIframe = (iframeDoc) => {
|
|
195
|
+
try {
|
|
196
|
+
[
|
|
197
|
+
"https://assets-test.empirical.run/pw-selector.js",
|
|
198
|
+
"https://code.jquery.com/jquery-3.7.1.min.js",
|
|
199
|
+
].forEach((url) => {
|
|
200
|
+
const script = iframeDoc.createElement("script");
|
|
201
|
+
script.src = trustedPolicy.createScriptURL(url);
|
|
202
|
+
iframeDoc.head.appendChild(script);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
catch (e) {
|
|
206
|
+
console.warn("Error injecting script in iframe.");
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
const iframes = document.getElementsByTagName("iframe");
|
|
210
|
+
for (const iframe of iframes) {
|
|
211
|
+
iframe.getBoundingClientRect();
|
|
212
|
+
const rect = iframe.getBoundingClientRect();
|
|
213
|
+
const isVisible = rect.width > 0 && rect.height > 0;
|
|
214
|
+
if (isVisible) {
|
|
215
|
+
//@ts-ignore
|
|
216
|
+
const iframeContent = iframe.contentDocument || iframe.contentWindow?.document;
|
|
217
|
+
const isScriptInjected = !!iframe.contentWindow?.playwright;
|
|
218
|
+
if (iframeContent && !isScriptInjected) {
|
|
219
|
+
injectScriptInIframe(iframeContent);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
catch (e) {
|
|
226
|
+
console.warn("Error during script injection on page load:", e);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
try {
|
|
230
|
+
await Promise.all(scripts.map((s) => page.addScriptTag({ content: s })));
|
|
231
|
+
await page.evaluate(async () => {
|
|
232
|
+
//@ts-ignore
|
|
233
|
+
const injectScriptInIframe = (iframeDoc) => {
|
|
234
|
+
try {
|
|
235
|
+
//@ts-ignore
|
|
236
|
+
//https://developer.mozilla.org/en-US/docs/Web/API/TrustedScriptURL
|
|
237
|
+
const trustedPolicy = window.trustedTypes.createPolicy(crypto.randomUUID(), {
|
|
238
|
+
createScriptURL: (url) => url,
|
|
239
|
+
});
|
|
240
|
+
[
|
|
241
|
+
"https://assets-test.empirical.run/pw-selector.js",
|
|
242
|
+
"https://code.jquery.com/jquery-3.7.1.min.js",
|
|
243
|
+
].forEach((url) => {
|
|
244
|
+
const scr = iframeDoc.createElement("script");
|
|
245
|
+
scr.src = trustedPolicy.createScriptURL(url);
|
|
246
|
+
iframeDoc.head.appendChild(scr);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
catch (e) {
|
|
250
|
+
console.warn("Error injecting script in iframe.");
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
const iframes = document.getElementsByTagName("iframe");
|
|
254
|
+
for (const iframe of iframes) {
|
|
255
|
+
iframe.getBoundingClientRect();
|
|
256
|
+
const rect = iframe.getBoundingClientRect();
|
|
257
|
+
const isVisible = rect.width > 0 && rect.height > 0;
|
|
258
|
+
if (isVisible) {
|
|
259
|
+
//@ts-ignore
|
|
260
|
+
const iframeContent = iframe.contentDocument || iframe.contentWindow?.document;
|
|
261
|
+
const isScriptInjected = !!iframe.contentWindow?.playwright;
|
|
262
|
+
if (iframeContent && !isScriptInjected) {
|
|
263
|
+
injectScriptInIframe(iframeContent);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
catch (e) {
|
|
270
|
+
console.warn("Error injecting script in iframe.");
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
exports.injectPwLocatorGenerator = injectPwLocatorGenerator;
|
|
274
|
+
/**
|
|
275
|
+
* Function to validate if the test file path are valid.
|
|
276
|
+
* @throws if there are any missing dependencies for master agent to run.
|
|
277
|
+
* @param {string} filePath
|
|
278
|
+
*/
|
|
279
|
+
function canRunMasterAgent(filePath) {
|
|
280
|
+
if (!fs_extra_1.default.existsSync(filePath)) {
|
|
281
|
+
throw new Error(`File for master agent to run not found: ${filePath}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
exports.canRunMasterAgent = canRunMasterAgent;
|
|
285
|
+
/**
|
|
286
|
+
* function to read playwright config from the source repo
|
|
287
|
+
* @return {*} {Promise<PlaywrightTestConfig>}
|
|
288
|
+
*/
|
|
289
|
+
async function readPlaywrightConfig(repoDir) {
|
|
290
|
+
const [lastDir] = repoDir.split("/").reverse();
|
|
291
|
+
const playwrightConfig = (await api_1.default.require("./playwright.config.ts", `${repoDir}/${lastDir}`)).default;
|
|
292
|
+
return playwrightConfig;
|
|
293
|
+
}
|
|
294
|
+
exports.readPlaywrightConfig = readPlaywrightConfig;
|
|
295
|
+
function matchAgainstPattern(pattern, filePathToTest) {
|
|
296
|
+
if (isRegExp(pattern)) {
|
|
297
|
+
const regExp = pattern;
|
|
298
|
+
return regExp.test(filePathToTest);
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
return (0, minimatch_1.minimatch)(filePathToTest, pattern);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* detect the project name for the given file in playwright test repo
|
|
306
|
+
* if project and test file path for running test don't match, then playwright throws error
|
|
307
|
+
* @param testFilePath
|
|
308
|
+
* @returns
|
|
309
|
+
*/
|
|
310
|
+
async function detectProjectName(testFilePath, playwrightConfig, pwProjectsFilter = ["*"]) {
|
|
311
|
+
const filePath = testFilePath.replace("./tests/", "");
|
|
312
|
+
if (!playwrightConfig.projects || playwrightConfig.projects.length === 0) {
|
|
313
|
+
throw new Error(`No projects found in playwright config.`);
|
|
314
|
+
}
|
|
315
|
+
const filteredProjectNames = playwrightConfig.projects
|
|
316
|
+
.map((p) => {
|
|
317
|
+
const testIgnore = p.testIgnore;
|
|
318
|
+
const testMatch = p.testMatch || "**";
|
|
319
|
+
let ignoreFile = false;
|
|
320
|
+
if (testIgnore) {
|
|
321
|
+
if (typeof testIgnore === "string" || isRegExp(testIgnore)) {
|
|
322
|
+
ignoreFile = matchAgainstPattern(testIgnore, filePath);
|
|
323
|
+
}
|
|
324
|
+
else if (typeof testIgnore === "object") {
|
|
325
|
+
ignoreFile = testIgnore.some((ignore) => matchAgainstPattern(ignore, filePath));
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// if test file path is in ignore list then skip it
|
|
329
|
+
if (ignoreFile) {
|
|
330
|
+
return "";
|
|
331
|
+
}
|
|
332
|
+
let isMatch = false;
|
|
333
|
+
if (typeof testMatch === "string" || isRegExp(testMatch)) {
|
|
334
|
+
isMatch = matchAgainstPattern(testMatch, filePath);
|
|
335
|
+
}
|
|
336
|
+
else if (typeof testMatch === "object") {
|
|
337
|
+
isMatch = testMatch.some((match) => matchAgainstPattern(match, filePath));
|
|
338
|
+
}
|
|
339
|
+
if (isMatch && p.use?.defaultBrowserType === "chromium") {
|
|
340
|
+
return p.name || "";
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
return "";
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
.filter((p) => !!p)
|
|
347
|
+
.filter((p) => pwProjectsFilter.some((f) => matchAgainstPattern(f, p)));
|
|
348
|
+
if (filteredProjectNames.length === 0) {
|
|
349
|
+
throw new Error(`No project found for the test file: ${testFilePath} in playwright config.`);
|
|
350
|
+
}
|
|
351
|
+
return filteredProjectNames[0];
|
|
352
|
+
}
|
|
353
|
+
exports.detectProjectName = detectProjectName;
|
|
354
|
+
class TeardownManager {
|
|
355
|
+
directory;
|
|
356
|
+
constructor(directory) {
|
|
357
|
+
this.directory = directory;
|
|
358
|
+
}
|
|
359
|
+
teardownFiles = [];
|
|
360
|
+
async getAllTeardownFiles() {
|
|
361
|
+
const teardownFileRegex = /.*\.teardown\.ts/;
|
|
362
|
+
const teardownFiles = await (0, fs_1.readFilesInDirectory)(this.directory, (fileName) => teardownFileRegex.test(fileName));
|
|
363
|
+
return teardownFiles;
|
|
364
|
+
}
|
|
365
|
+
async skipTeardownFile(filePath) {
|
|
366
|
+
const project = new ts_morph_1.Project();
|
|
367
|
+
const sourceFile = project.addSourceFileAtPath(filePath);
|
|
368
|
+
sourceFile
|
|
369
|
+
.getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression)
|
|
370
|
+
.forEach((callExpression) => {
|
|
371
|
+
const expression = callExpression.getExpression();
|
|
372
|
+
if (expression.getText() === "teardown") {
|
|
373
|
+
expression.replaceWithText("teardown.skip");
|
|
374
|
+
}
|
|
375
|
+
else if (expression.getText() === "test") {
|
|
376
|
+
expression.replaceWithText("test.skip");
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
// Save the modified file
|
|
380
|
+
sourceFile.save().catch((error) => {
|
|
381
|
+
console.error(`Error updating the file: ${filePath}`, error);
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
async skipAll() {
|
|
385
|
+
this.teardownFiles = await this.getAllTeardownFiles();
|
|
386
|
+
await Promise.all(this.teardownFiles.map(async ({ filePath }) => await this.skipTeardownFile(filePath)));
|
|
387
|
+
process.on("beforeExit", () => {
|
|
388
|
+
this.unskipAll();
|
|
389
|
+
});
|
|
390
|
+
process.on("exit", () => {
|
|
391
|
+
this.unskipAll();
|
|
392
|
+
});
|
|
393
|
+
process.on("SIGINT", () => {
|
|
394
|
+
this.unskipAll();
|
|
395
|
+
});
|
|
396
|
+
process.on("SIGTERM", () => {
|
|
397
|
+
this.unskipAll();
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
unskipAll() {
|
|
401
|
+
this.teardownFiles.forEach(({ filePath, content }) => {
|
|
402
|
+
fs_extra_1.default.writeFileSync(filePath, content, "utf-8");
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
exports.TeardownManager = TeardownManager;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { TraceClient } from "@empiricalrun/llm";
|
|
2
|
+
import type { TestCase, TestGenConfigOptions } from "@empiricalrun/shared-types";
|
|
3
|
+
export declare function createEmptyTestCaseBlock({ testCase, file, options, trace, }: {
|
|
4
|
+
testCase: TestCase;
|
|
5
|
+
file: string;
|
|
6
|
+
options?: TestGenConfigOptions;
|
|
7
|
+
trace?: TraceClient;
|
|
8
|
+
}): Promise<string | undefined>;
|
|
9
|
+
//# sourceMappingURL=create-test-block.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-test-block.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/create-test-block.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,QAAQ,EACR,oBAAoB,EACrB,MAAM,4BAA4B,CAAC;AAcpC,wBAAsB,wBAAwB,CAAC,EAC7C,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,KAAK,GACN,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,+BAqDA"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createEmptyTestCaseBlock = void 0;
|
|
4
|
+
const llm_1 = require("@empiricalrun/llm");
|
|
5
|
+
const logger_1 = require("../../bin/logger");
|
|
6
|
+
const context_1 = require("../../bin/utils/context");
|
|
7
|
+
const web_1 = require("../../bin/utils/platform/web");
|
|
8
|
+
const constants_1 = require("../../constants");
|
|
9
|
+
const promptTemplate_0 = "{{#section \"system\"}}\nYou are a software test engineer who is given a task to write an empty test block.\nBased on the inputs you need to create an empty playwright test block with correctly imported fixture.\n\nThe test will contain a test name which you will need to use to build the empty test case block.\n\nYou will be provided with current tests, fixtures and page object models for you to use and create test case block as\nper the task provided to you.\n\nBefore responding you need to ensure that the code change is minimal and the change is reusable across tests. You need\nto ensure the code follows DRY principle.\n\nHere is the list of current tests and fixtures:\n\n{{testFiles}}\n\nHere is the list of current page object models:\n\n{{pageFiles}}\n{{/section}}\n\n{{#section \"user\"}}\nFollowing is the test scenario for which you need to write the empty test case block:\ntest name:\n{{scenarioName}}\n\ntask:\ncreate an empty test case block for the following test steps:\n{{scenario}}\n\ntest file path: {{scenarioFile}}\n\n------\n\nYou also need to ensure that the empty test case block has a starting page to begin test.\n\nIn order to identify the right page with which the test should start, follow the steps:\n- based on the similarities with other test cases mentioned in the file, identify the right page fixture to be imported\n- Read the page fixture methods step by step. Identify whether the fixture handles navigating to a page.\n- Identify whether other tests using the page fixture had to add separate steps for navigation or not\n- Based on the above analysis there will be following cases and choose either for the given test scenario:\n-- Case 1: if the test case scenario provided inside the task mentions about page navigation, then use that page\nnavigation. skip other cases if this case is satisfied.\n-- Case 2: refer other test cases which import similar fixtures and infer the first page navigation of this test case.\nYou should prefer tests which are in the same file. Tests within same file have higher overlaps in first page\nnavigation.\n- Once the page fixture is decided, look for userContext fixture in files. If its available then add \"userContext\" to\nthe test case block\n\n\n\nFollow these instructions before responding with output:\n- Read the code line by line and achieve the task provided to you\n- Read the dependencies of the code block by scanning through file paths and file provided to you. refer the same file\npath while responding with update\n- Focus only on the test case provided and associated JS methods called from the test case.\n- Respond only with the new empty test case block to be created and nothing else.\n- DO NOT respond with any backticks or markdown syntax\n- If \"userContext\" fixture is available in fixtures file, ensure importing that fixture in the test case block.\n- Provide a reason based on the test steps provided to you on why you chose the fixture or page.goto statement. The\nreason should be one of the list steps provided to you and mention why the case was chosen\n{{/section}}";
|
|
10
|
+
const session_1 = require("../../session");
|
|
11
|
+
async function createEmptyTestCaseBlock({ testCase, file, options, trace, }) {
|
|
12
|
+
const logger = new logger_1.CustomLogger({ useReporter: false });
|
|
13
|
+
logger.log("Creating new test block");
|
|
14
|
+
const context = await (0, context_1.contextForGeneration)(file);
|
|
15
|
+
// TODO: move this to a common place
|
|
16
|
+
const session = (0, session_1.getSessionDetails)();
|
|
17
|
+
trace =
|
|
18
|
+
trace ||
|
|
19
|
+
llm_1.langfuseInstance?.trace({
|
|
20
|
+
name: "create-empty-test-block",
|
|
21
|
+
id: crypto.randomUUID(),
|
|
22
|
+
release: session.version,
|
|
23
|
+
tags: [
|
|
24
|
+
options?.metadata.projectName || "",
|
|
25
|
+
options?.metadata.environment || "",
|
|
26
|
+
].filter((s) => !!s),
|
|
27
|
+
});
|
|
28
|
+
const promptSpan = trace?.span({
|
|
29
|
+
name: "build-create-empty-test-case-prompt",
|
|
30
|
+
});
|
|
31
|
+
const prompt = (0, llm_1.compilePrompt)(promptTemplate_0, {
|
|
32
|
+
testFiles: context.codePrompt,
|
|
33
|
+
pageFiles: context.pomPrompt,
|
|
34
|
+
scenarioName: testCase.name,
|
|
35
|
+
scenario: testCase.steps.join("\n"),
|
|
36
|
+
scenarioFile: file,
|
|
37
|
+
});
|
|
38
|
+
promptSpan?.end({ output: { prompt } });
|
|
39
|
+
const llm = new llm_1.LLM({
|
|
40
|
+
trace,
|
|
41
|
+
provider: options?.modelProvider || constants_1.DEFAULT_MODEL_PROVIDER,
|
|
42
|
+
defaultModel: options?.model || constants_1.DEFAULT_MODEL,
|
|
43
|
+
providerApiKey: constants_1.MODEL_API_KEYS[options?.modelProvider || constants_1.DEFAULT_MODEL_PROVIDER],
|
|
44
|
+
});
|
|
45
|
+
const firstShotMessage = await llm.createChatCompletion({
|
|
46
|
+
messages: prompt,
|
|
47
|
+
modelParameters: {
|
|
48
|
+
...constants_1.DEFAULT_MODEL_PARAMETERS,
|
|
49
|
+
...options?.modelParameters,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
const markdownRemoverSpan = trace?.span({
|
|
53
|
+
name: "remove-markdown-span",
|
|
54
|
+
});
|
|
55
|
+
let response = firstShotMessage?.content || "";
|
|
56
|
+
markdownRemoverSpan?.end({ output: { response } });
|
|
57
|
+
const { testBlock } = (0, web_1.getTypescriptTestBlock)({
|
|
58
|
+
scenarioName: testCase.name,
|
|
59
|
+
content: response,
|
|
60
|
+
});
|
|
61
|
+
return testBlock;
|
|
62
|
+
}
|
|
63
|
+
exports.createEmptyTestCaseBlock = createEmptyTestCaseBlock;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TraceClient } from "@empiricalrun/llm";
|
|
2
|
+
import type { TestCase, TestGenConfigOptions } from "@empiricalrun/shared-types";
|
|
3
|
+
import { CustomLogger } from "../../bin/logger";
|
|
4
|
+
export declare function validateAndFixTypescriptErrors({ trace, logger, file, pomCode, nonSpecFileCode, testCase, options, }: {
|
|
5
|
+
trace?: TraceClient;
|
|
6
|
+
logger?: CustomLogger;
|
|
7
|
+
file: string;
|
|
8
|
+
pomCode: string;
|
|
9
|
+
nonSpecFileCode: string;
|
|
10
|
+
testCase: TestCase;
|
|
11
|
+
options?: TestGenConfigOptions;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=fix-ts-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix-ts-errors.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/fix-ts-errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EACV,QAAQ,EACR,oBAAoB,EACrB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAUhD,wBAAsB,8BAA8B,CAAC,EACnD,KAAK,EACL,MAA2B,EAC3B,IAAI,EACJ,OAAO,EACP,eAAe,EACf,QAAQ,EACR,OAAO,GACR,EAAE;IACD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC,iBAwEA"}
|