@empiricalrun/test-gen 0.16.13 → 0.17.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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # @empiricalrun/test-gen
2
2
 
3
+ ## 0.17.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 914b207: fix: remove google sheet support in test gen
8
+
9
+ ### Patch Changes
10
+
11
+ - 74eefc4: fix: remove comments of browser agent
12
+
3
13
  ## 0.16.13
4
14
 
5
15
  ### Patch Changes
@@ -2,7 +2,7 @@ import { Page } from "playwright";
2
2
  import { PlaywrightTestConfig } from "playwright/test";
3
3
  import { TestGenConfig } from "../../types";
4
4
  export declare function isRegExp(obj: any): obj is RegExp;
5
- export declare function prepareBrowsingAgentTask(steps: string[], assert?: string): string;
5
+ export declare function prepareBrowsingAgentTask(steps: string[]): string;
6
6
  export declare function prepareFileForBrowsingAgent(genConfig: TestGenConfig): Promise<void>;
7
7
  export declare function injectPwLocatorGenerator(page: Page): Promise<void>;
8
8
  export declare function canRunBrowsingAgent(filePath: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/utils.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AASvD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,MAAM,CAKhD;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,UAIxE;AAED,wBAAsB,2BAA2B,CAAC,SAAS,EAAE,aAAa,iBAqCzE;AAiBD,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,IAAI,iBASxD;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,QA4BnD;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAM1E;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,oBAAoB,GACrC,OAAO,CAAC,MAAM,CAAC,CAkDjB;AAED,wBAAsB,sBAAsB,CAAC,EAC3C,YAAiB,EACjB,IAAS,EACT,eAAoB,EACpB,gBAAqB,GACtB,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,8EASA"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/utils.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AASvD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,MAAM,CAKhD;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,UAIvD;AAED,wBAAsB,2BAA2B,CAAC,SAAS,EAAE,aAAa,iBAqCzE;AAiBD,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,IAAI,iBASxD;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,QA4BnD;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAM1E;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,oBAAoB,GACrC,OAAO,CAAC,MAAM,CAAC,CAkDjB;AAED,wBAAsB,sBAAsB,CAAC,EAC3C,YAAiB,EACjB,IAAS,EACT,eAAoB,EACpB,gBAAqB,GACtB,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,8EASA"}
@@ -16,15 +16,15 @@ function isRegExp(obj) {
16
16
  Object.prototype.toString.call(obj) === "[object RegExp]");
17
17
  }
18
18
  exports.isRegExp = isRegExp;
19
- function prepareBrowsingAgentTask(steps, assert) {
19
+ function prepareBrowsingAgentTask(steps) {
20
20
  const sanitizedSteps = steps.map((step) => step.replace(/`/g, "\\`"));
21
- const task = `${sanitizedSteps.join("\n")}\n${assert || ""}`;
21
+ const task = `${sanitizedSteps.join("\n")}\n`;
22
22
  return task;
23
23
  }
24
24
  exports.prepareBrowsingAgentTask = prepareBrowsingAgentTask;
25
25
  async function prepareFileForBrowsingAgent(genConfig) {
26
- const { specPath, scenarios } = genConfig;
27
- const { name, steps, assert } = scenarios[0];
26
+ const { specPath, testCase } = genConfig;
27
+ const { name, steps } = testCase;
28
28
  const logger = new logger_1.CustomLogger();
29
29
  if (!fs_extra_1.default.existsSync(specPath)) {
30
30
  await fs_extra_1.default.createFile(specPath);
@@ -33,7 +33,7 @@ async function prepareFileForBrowsingAgent(genConfig) {
33
33
  if (name && steps && steps.length) {
34
34
  const existingContents = await fs_extra_1.default.readFile(specPath, "utf-8");
35
35
  const testBlock = (0, web_1.getTypescriptTestBlock)(name, existingContents);
36
- const mergedSteps = prepareBrowsingAgentTask(steps, assert);
36
+ const mergedSteps = prepareBrowsingAgentTask(steps);
37
37
  let newContents = existingContents;
38
38
  if (testBlock) {
39
39
  logger.log("appending to existing test block");
@@ -1,3 +1,3 @@
1
- import { Scenario, TestGenConfigOptions } from "../../types";
2
- export declare function generateTest(scenarios: Scenario[], file: string, isUpdate: boolean, options: TestGenConfigOptions): Promise<Scenario[]>;
1
+ import { TestCase, TestGenConfigOptions } from "../../types";
2
+ export declare function generateTest(testCase: TestCase, file: string, options: TestGenConfigOptions): Promise<TestCase[]>;
3
3
  //# sourceMappingURL=run.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/run.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAE7D,wBAAsB,YAAY,CAChC,SAAS,EAAE,QAAQ,EAAE,EACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,QAAQ,EAAE,CAAC,CAwJrB"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/run.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAE7D,wBAAsB,YAAY,CAChC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,QAAQ,EAAE,CAAC,CA+IrB"}
@@ -11,7 +11,7 @@ const context_1 = require("../../bin/utils/context");
11
11
  const web_1 = require("../../bin/utils/platform/web");
12
12
  const constants_1 = require("../../constants");
13
13
  const session_1 = require("../../session");
14
- async function generateTest(scenarios, file, isUpdate, options) {
14
+ async function generateTest(testCase, file, options) {
15
15
  const logger = new logger_1.CustomLogger();
16
16
  if (!fs_extra_1.default.existsSync(file)) {
17
17
  logger.log(`Creating a new spec file: ${file}`);
@@ -19,42 +19,97 @@ async function generateTest(scenarios, file, isUpdate, options) {
19
19
  }
20
20
  const context = await (0, context_1.contextForGeneration)(file);
21
21
  const { codePrompt, pomPrompt, testFileContent } = context;
22
- const generatedScenarios = [];
23
- for (const i in scenarios) {
24
- logger.logEmptyLine();
25
- const trace = new llm_1.LLMTracing({
26
- name: "generate-test",
27
- sessionDetails: (0, session_1.getSessionDetails)(),
28
- tags: [options.metadata.projectName, options.metadata.environment].filter((s) => !!s),
29
- });
30
- trace.event({
31
- name: "collate-files-as-text",
32
- output: {
33
- codePrompt,
34
- pomPrompt,
35
- testFileContent,
36
- },
37
- });
38
- const scenario = scenarios[i];
39
- trace.update({ input: { scenario } });
40
- logger.log("Generating test for scenario:", scenario?.name);
41
- if (!isUpdate && testFileContent.includes(`test("${scenario?.name}"`)) {
42
- logger.success("Test already exists for this scenario");
43
- trace.event({ name: "test-already-exists" });
44
- continue;
22
+ const generatedTestCases = [];
23
+ logger.logEmptyLine();
24
+ const trace = new llm_1.LLMTracing({
25
+ name: "generate-test",
26
+ sessionDetails: (0, session_1.getSessionDetails)(),
27
+ tags: [options.metadata.projectName, options.metadata.environment].filter((s) => !!s),
28
+ });
29
+ trace.event({
30
+ name: "collate-files-as-text",
31
+ output: {
32
+ codePrompt,
33
+ pomPrompt,
34
+ testFileContent,
35
+ },
36
+ });
37
+ trace.update({ input: { testCase } });
38
+ logger.log("Generating test for scenario:", testCase?.name);
39
+ const isUpdate = testFileContent.includes(`test("${testCase?.name}"`);
40
+ const promptSpan = trace.startSpan(isUpdate ? "update-scenario-prompt" : "add-scenario-prompt");
41
+ const promptName = isUpdate ? "update-scenario" : "add-scenario";
42
+ const instruction = await (0, llm_1.getPrompt)(promptName, {
43
+ testFiles: codePrompt,
44
+ pageFiles: pomPrompt,
45
+ scenarioName: testCase.name,
46
+ scenarioSteps: testCase.steps.join("\n"),
47
+ scenarioFile: file,
48
+ });
49
+ promptSpan.end({ output: { instruction } });
50
+ const firstShotMessage = await (0, llm_1.getLLMResult)({
51
+ messages: instruction,
52
+ trace,
53
+ model: options.model || constants_1.DEFAULT_MODEL,
54
+ provider: options.modelProvider || constants_1.DEFAULT_MODEL_PROVIDER,
55
+ providerApiKey: constants_1.MODEL_API_KEYS[options.modelProvider || constants_1.DEFAULT_MODEL_PROVIDER],
56
+ modelParameters: {
57
+ ...constants_1.DEFAULT_MODEL_PARAMETERS,
58
+ ...options.modelParameters,
59
+ },
60
+ });
61
+ let response = firstShotMessage?.content || "";
62
+ logger.success("Test generated successfully!");
63
+ const readWriteFileSpan = trace.startSpan("write-to-file");
64
+ let contents = fs_extra_1.default.readFileSync(file, "utf-8");
65
+ const [prependContent, strippedContent] = await (0, web_1.stripAndPrependImports)(response);
66
+ let updatedContent = prependContent + contents + `\n\n${strippedContent}`;
67
+ if (isUpdate) {
68
+ const testBlock = (0, web_1.getTypescriptTestBlock)(testCase?.name, contents);
69
+ contents = contents.replace(testBlock, `\n\n${strippedContent}`);
70
+ updatedContent = prependContent + contents;
71
+ }
72
+ await fs_extra_1.default.writeFile(file, updatedContent, "utf-8");
73
+ readWriteFileSpan.end({ output: { updatedContent } });
74
+ logger.log("Linting generated code...");
75
+ trace.event({ name: "lint-file" });
76
+ await (0, web_1.lintErrors)(file);
77
+ const validateTypesSpan = trace.startSpan("detect-type-errors-in-file");
78
+ logger.log("Validating types...");
79
+ let errors = (0, web_1.validateTypescript)(file);
80
+ validateTypesSpan.end({ output: { errors } });
81
+ if (!errors.length) {
82
+ logger.success("Found no type issues!");
83
+ }
84
+ const maxIteration = 2;
85
+ let counter = 0;
86
+ while (errors.length > 0) {
87
+ const fileContent = fs_extra_1.default.readFileSync(file, "utf-8");
88
+ counter += 1;
89
+ if (counter > maxIteration) {
90
+ trace.event({ name: "code-fix-iteration-max-out" });
91
+ logger.error([
92
+ `Unable to fix typescript errors. Please review ${file} manually and fix the typescript errors.`,
93
+ `Run the test-gen command again, once errors are fixed.`,
94
+ `Trace: ${trace.url}`,
95
+ ].join("\n"));
96
+ break;
45
97
  }
46
- const promptSpan = trace.startSpan(isUpdate ? "update-scenario-prompt" : "add-scenario-prompt");
47
- const promptName = isUpdate ? "update-scenario" : "add-scenario";
48
- const instruction = await (0, llm_1.getPrompt)(promptName, {
49
- testFiles: codePrompt,
50
- pageFiles: pomPrompt,
51
- scenarioName: scenario.name,
52
- scenarioSteps: scenario.steps.join("\n"),
53
- assert: scenario.assert,
98
+ trace.event({ name: "Found errors fixing" });
99
+ logger.warn("Found few errors while validating types:");
100
+ errors.forEach((e) => logger.warn(e));
101
+ logger.log("Trying to fix above errors...");
102
+ const promptSpan = trace.startSpan("fix-type-errors-prompt");
103
+ const instruction = await (0, llm_1.getPrompt)("fix-file-errors-ts", {
104
+ testFiles: codePrompt || "",
105
+ pageFiles: pomPrompt || "",
54
106
  scenarioFile: file,
107
+ errors: errors,
108
+ fileContent: fileContent,
109
+ scenaioName: testCase.name,
55
110
  });
56
111
  promptSpan.end({ output: { instruction } });
57
- const firstShotMessage = await (0, llm_1.getLLMResult)({
112
+ const message = await (0, llm_1.getLLMResult)({
58
113
  messages: instruction,
59
114
  trace,
60
115
  model: options.model || constants_1.DEFAULT_MODEL,
@@ -65,88 +120,25 @@ async function generateTest(scenarios, file, isUpdate, options) {
65
120
  ...options.modelParameters,
66
121
  },
67
122
  });
68
- let response = firstShotMessage?.content || "";
69
- logger.success("Test generated successfully!");
123
+ response = message?.content || "";
70
124
  const readWriteFileSpan = trace.startSpan("write-to-file");
71
- let contents = fs_extra_1.default.readFileSync(file, "utf-8");
72
- const [prependContent, strippedContent] = await (0, web_1.stripAndPrependImports)(response);
73
- let updatedContent = prependContent + contents + `\n\n${strippedContent}`;
74
- if (isUpdate) {
75
- const testBlock = (0, web_1.getTypescriptTestBlock)(scenario?.name, contents);
76
- contents = contents.replace(testBlock, `\n\n${strippedContent}`);
77
- updatedContent = prependContent + contents;
78
- }
79
- await fs_extra_1.default.writeFile(file, updatedContent, "utf-8");
80
- readWriteFileSpan.end({ output: { updatedContent } });
81
- logger.log("Linting generated code...");
125
+ await fs_extra_1.default.writeFile(file, response, "utf-8");
126
+ readWriteFileSpan.end({ output: { response } });
82
127
  trace.event({ name: "lint-file" });
83
128
  await (0, web_1.lintErrors)(file);
84
129
  const validateTypesSpan = trace.startSpan("detect-type-errors-in-file");
85
- logger.log("Validating types...");
86
- let errors = (0, web_1.validateTypescript)(file);
130
+ errors = (0, web_1.validateTypescript)(file);
87
131
  validateTypesSpan.end({ output: { errors } });
88
132
  if (!errors.length) {
89
133
  logger.success("Found no type issues!");
90
134
  }
91
- const maxIteration = 2;
92
- let counter = 0;
93
- while (errors.length > 0) {
94
- const fileContent = fs_extra_1.default.readFileSync(file, "utf-8");
95
- counter += 1;
96
- if (counter > maxIteration) {
97
- trace.event({ name: "code-fix-iteration-max-out" });
98
- logger.error([
99
- `Unable to fix typescript errors. Please review ${file} manually and fix the typescript errors.`,
100
- `Run the test-gen command again, once errors are fixed.`,
101
- `Trace: ${trace.url}`,
102
- ].join("\n"));
103
- break;
104
- }
105
- trace.event({ name: "Found errors fixing" });
106
- logger.warn("Found few errors while validating types:");
107
- errors.forEach((e) => logger.warn(e));
108
- logger.log("Trying to fix above errors...");
109
- const promptSpan = trace.startSpan("fix-type-errors-prompt");
110
- const instruction = await (0, llm_1.getPrompt)("fix-file-errors-ts", {
111
- testFiles: codePrompt || "",
112
- pageFiles: pomPrompt || "",
113
- scenarioFile: file,
114
- errors: errors,
115
- fileContent: fileContent,
116
- scenaioName: scenario.name,
117
- });
118
- promptSpan.end({ output: { instruction } });
119
- const message = await (0, llm_1.getLLMResult)({
120
- messages: instruction,
121
- trace,
122
- model: options.model || constants_1.DEFAULT_MODEL,
123
- provider: options.modelProvider || constants_1.DEFAULT_MODEL_PROVIDER,
124
- providerApiKey: constants_1.MODEL_API_KEYS[options.modelProvider || constants_1.DEFAULT_MODEL_PROVIDER],
125
- modelParameters: {
126
- ...constants_1.DEFAULT_MODEL_PARAMETERS,
127
- ...options.modelParameters,
128
- },
129
- });
130
- response = message?.content || "";
131
- const readWriteFileSpan = trace.startSpan("write-to-file");
132
- await fs_extra_1.default.writeFile(file, response, "utf-8");
133
- readWriteFileSpan.end({ output: { response } });
134
- trace.event({ name: "lint-file" });
135
- await (0, web_1.lintErrors)(file);
136
- const validateTypesSpan = trace.startSpan("detect-type-errors-in-file");
137
- errors = (0, web_1.validateTypescript)(file);
138
- validateTypesSpan.end({ output: { errors } });
139
- if (!errors.length) {
140
- logger.success("Found no type issues!");
141
- }
142
- }
143
- trace.event({ name: "format-file" });
144
- await (0, web_1.formatCode)(file);
145
- logger.success("File formatted successfully!");
146
- logger.log(`Trace: ${trace.url}`);
147
- generatedScenarios.push(scenario);
148
- trace.update({ input: { scenario }, output: { response } });
149
135
  }
150
- return generatedScenarios;
136
+ trace.event({ name: "format-file" });
137
+ await (0, web_1.formatCode)(file);
138
+ logger.success("File formatted successfully!");
139
+ logger.log(`Trace: ${trace.url}`);
140
+ generatedTestCases.push(testCase);
141
+ trace.update({ input: { testCase }, output: { response } });
142
+ return generatedTestCases;
151
143
  }
152
144
  exports.generateTest = generateTest;
package/dist/bin/index.js CHANGED
@@ -19,29 +19,22 @@ dotenv_1.default.config({
19
19
  process.on("exit", async () => await (0, llm_1.flushAllTraces)());
20
20
  process.on("SIGINT", async () => await (0, llm_1.flushAllTraces)());
21
21
  process.on("SIGTERM", async () => await (0, llm_1.flushAllTraces)());
22
- async function runAgent(sourceFile, isUpdate, testGenConfigs) {
22
+ async function runAgent(sourceFile, testGenConfig) {
23
23
  const logger = new logger_1.CustomLogger();
24
- const generatedTestScenarios = [];
25
- const compatibleWithBrowsing = !sourceFile.startsWith("https://docs.google.com/spreadsheets");
26
- for (const testGenConfig of testGenConfigs) {
27
- const { specPath, scenarios } = testGenConfig;
28
- if (compatibleWithBrowsing && testGenConfig.options?.agent !== "code") {
29
- // this assumes we have only one scenario in test config
30
- logger.success("Generating test using browsing agent");
31
- await (0, utils_1.prepareFileForBrowsingAgent)(testGenConfig);
32
- await (0, run_1.generateTestsUsingBrowsingAgent)(specPath);
33
- await (0, reporter_1.reportTestGenVideos)({
34
- projectRepoName: testGenConfig.options.metadata.projectRepoName,
35
- });
36
- generatedTestScenarios.push(...testGenConfig.scenarios);
37
- }
38
- else {
39
- logger.success("Generating test using coding agent");
40
- const gen = await (0, run_2.generateTest)(scenarios, specPath, isUpdate, testGenConfig.options);
41
- generatedTestScenarios.push(...gen);
42
- }
24
+ const { specPath, testCase } = testGenConfig;
25
+ if (testGenConfig.options?.agent !== "code") {
26
+ // this assumes we have only one scenario in test config
27
+ logger.success("Generating test using browsing agent");
28
+ await (0, utils_1.prepareFileForBrowsingAgent)(testGenConfig);
29
+ await (0, run_1.generateTestsUsingBrowsingAgent)(specPath);
30
+ await (0, reporter_1.reportTestGenVideos)({
31
+ projectRepoName: testGenConfig.options.metadata.projectRepoName,
32
+ });
33
+ }
34
+ else {
35
+ logger.success("Generating test using coding agent");
36
+ await (0, run_2.generateTest)(testCase, specPath, testGenConfig.options);
43
37
  }
44
- return generatedTestScenarios;
45
38
  }
46
39
  (async function main() {
47
40
  const logger = new logger_1.CustomLogger({ useReporter: false });
@@ -49,10 +42,10 @@ async function runAgent(sourceFile, isUpdate, testGenConfigs) {
49
42
  logger.error("Please provide path to scenarios using command:", "npx @empiricalrun/test-gen <SCENARIOS_FILE_PATH> -u");
50
43
  process.exit(1);
51
44
  }
52
- const { sourceFile, testGenConfigs, isUpdate } = await (0, utils_2.parseCliArgs)();
53
- (0, reporter_1.setReporterConfig)(testGenConfigs[0]?.options?.metadata);
54
- const generated = await runAgent(sourceFile, isUpdate, testGenConfigs);
45
+ const { sourceFile, testGenConfig } = await (0, utils_2.parseCliArgs)();
46
+ (0, reporter_1.setReporterConfig)(testGenConfig?.options?.metadata);
47
+ await runAgent(sourceFile, testGenConfig);
55
48
  // TODO: move these reporters to a better lifecycle
56
- await (0, ci_1.reportOnCI)(generated);
49
+ await (0, ci_1.reportOnCI)(testGenConfig.testCase);
57
50
  process.exit(0);
58
51
  })();
@@ -1,8 +1,7 @@
1
1
  import { TestGenConfig } from "../../types";
2
2
  export declare function parseCliArgs(scenarioOrScenariosPath?: string): Promise<{
3
3
  sourceFile: string;
4
- testGenConfigs: TestGenConfig[];
5
- isUpdate: boolean;
4
+ testGenConfig: TestGenConfig;
6
5
  }>;
7
6
  export declare function getTestConfigCliArg(): string;
8
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bin/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,wBAAsB,YAAY,CAChC,uBAAuB,GAAE,MAA8B;;;;GAWxD;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bin/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,wBAAsB,YAAY,CAChC,uBAAuB,GAAE,MAA8B;;;GASxD;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C"}
@@ -3,12 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getTestConfigCliArg = exports.parseCliArgs = void 0;
4
4
  const scenarios_1 = require("./scenarios");
5
5
  async function parseCliArgs(scenarioOrScenariosPath = getTestConfigCliArg()) {
6
- const isUpdate = process.argv.includes("-u");
7
- const testGenConfigs = await (0, scenarios_1.loadTestConfigs)(scenarioOrScenariosPath);
6
+ const testGenConfig = await (0, scenarios_1.loadTestConfigs)(scenarioOrScenariosPath);
8
7
  return {
9
8
  sourceFile: scenarioOrScenariosPath,
10
- testGenConfigs,
11
- isUpdate,
9
+ testGenConfig,
12
10
  };
13
11
  }
14
12
  exports.parseCliArgs = parseCliArgs;
@@ -1,4 +1,4 @@
1
1
  import { TestGenConfig } from "../../../types";
2
- declare function loadTestConfigs(scenariosPath: string): Promise<TestGenConfig[]>;
2
+ declare function loadTestConfigs(scenariosPath: string): Promise<TestGenConfig>;
3
3
  export { loadTestConfigs };
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/bin/utils/scenarios/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAY,aAAa,EAAwB,MAAM,gBAAgB,CAAC;AAkF/E,iBAAe,eAAe,CAC5B,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,aAAa,EAAE,CAAC,CAiC1B;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/bin/utils/scenarios/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAwB,MAAM,gBAAgB,CAAC;AAUrE,iBAAe,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAY5E;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -1,112 +1,17 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.loadTestConfigs = void 0;
7
- const google_auth_library_1 = require("google-auth-library");
8
- const slugify_1 = __importDefault(require("slugify"));
9
- function isValidJSON(str) {
10
- try {
11
- JSON.parse(str);
12
- return true;
13
- }
14
- catch (e) {
15
- return false;
16
- }
17
- }
18
- /**
19
- * Method to update / add scenarios to the repo.
20
- * @param path
21
- * @returns updated paths of scenarios
22
- */
23
- async function loadScenariosFromGsheet(path) {
24
- const { GoogleSpreadsheet } = await import("google-spreadsheet");
25
- const url = new URL(path);
26
- const docId = url.pathname.split("/")[3];
27
- const searchParams = new URLSearchParams(url.hash.split("#")[1]);
28
- const sheetId = Number(searchParams.get("gid")) || 0;
29
- // TODO: use oauth 2
30
- const serviceAccountAuth = new google_auth_library_1.JWT({
31
- email: process.env.GOOGLE_SERVICE_EMAIL,
32
- key: Buffer.from(process.env.GOOGLE_SERVICE_EMAIL_PRIVATE_KEY, "base64").toString(),
33
- scopes: ["https://www.googleapis.com/auth/spreadsheets"],
34
- });
35
- const doc = new GoogleSpreadsheet(docId, serviceAccountAuth);
36
- await doc.loadInfo();
37
- const sheet = doc.sheetsById[sheetId];
38
- const rows = await sheet.getRows();
39
- const map = new Map();
40
- rows.forEach((r) => {
41
- // TODO: fix for case insensitive
42
- const category = r.get("Category");
43
- const name = r.get("Scenario");
44
- const steps = r
45
- .get("Steps")
46
- .split("\n")
47
- .map((s) => s.trim())
48
- .filter((s) => !!s.length);
49
- const assert = r.get("Assert");
50
- const specPath = category
51
- ? `./tests/${category}.spec.ts`
52
- : `./tests/${(0, slugify_1.default)(name)}.spec.ts`;
53
- const scenario = {
54
- steps,
55
- name,
56
- assert,
57
- };
58
- if (!map.get(specPath)) {
59
- map.set(specPath, [scenario]);
60
- }
61
- else {
62
- const scenarios = map.get(specPath);
63
- scenarios.push(scenario);
64
- map.set(specPath, scenarios);
65
- }
66
- });
67
- const results = [];
68
- for (const [specPath, scenarios] of map.entries()) {
69
- results.push({
70
- specPath,
71
- scenarios,
72
- });
73
- }
74
- return results;
75
- }
76
4
  async function loadTestConfigs(scenariosPath) {
77
- // google sheets generation flow
78
- // TODO: remove this whenever we are comfortable demoing using dashboard
79
- if (scenariosPath.startsWith("https://docs.google.com/spreadsheets")) {
80
- return await loadScenariosFromGsheet(scenariosPath);
81
- // dev testing flow
82
- }
83
- else if (scenariosPath.endsWith(".ts")) {
84
- return [
85
- {
86
- specPath: scenariosPath,
87
- scenarios: [],
88
- },
89
- ];
90
- // api flow
91
- }
92
- else if (isValidJSON(atob(scenariosPath))) {
93
- const str = atob(scenariosPath);
94
- const config = JSON.parse(str);
95
- const specPath = `./tests/${config.group || "index"}.spec.ts`;
96
- return [
97
- {
98
- specPath,
99
- scenarios: [
100
- {
101
- name: config.name,
102
- steps: config.steps.filter((s) => !!s),
103
- assert: config.assert,
104
- },
105
- ],
106
- options: config.options,
107
- },
108
- ];
109
- }
110
- throw Error("Invalid path for test scenarios");
5
+ const str = atob(scenariosPath);
6
+ const config = JSON.parse(str);
7
+ const specPath = `./tests/${config.group || "index"}.spec.ts`;
8
+ return {
9
+ specPath,
10
+ testCase: {
11
+ name: config.name,
12
+ steps: config.steps.filter((s) => !!s),
13
+ },
14
+ options: config.options,
15
+ };
111
16
  }
112
17
  exports.loadTestConfigs = loadTestConfigs;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/file/server.ts"],"names":[],"mappings":"AAOA,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,IAAI,CAAa;gBACb,EAAE,IAAI,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAGtC,WAAW,CAAC,QAAQ,EAAE,MAAM;IAGtB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;CAmC1C;AAED,wBAAsB,gBAAgB,kBAAK"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/file/server.ts"],"names":[],"mappings":"AAMA,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,IAAI,CAAa;gBACb,EAAE,IAAI,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAGtC,WAAW,CAAC,QAAQ,EAAE,MAAM;IAGtB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;CAkC1C;AAED,wBAAsB,gBAAgB,kBAAK"}
@@ -8,7 +8,6 @@ const express_1 = __importDefault(require("express"));
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const web_1 = require("../bin/utils/platform/web");
11
- const string_1 = require("../utils/string");
12
11
  class FileService {
13
12
  filePath = "";
14
13
  port = 0;
@@ -21,17 +20,16 @@ class FileService {
21
20
  async startFileService() {
22
21
  const app = (0, express_1.default)();
23
22
  app.use(express_1.default.json());
24
- app.post("/test", (req, res) => {
25
- const { generatedCode, task } = req.body;
23
+ app.post("/test", async (req, res) => {
24
+ const { generatedCode } = req.body;
26
25
  try {
27
26
  const testFilePath = path_1.default.resolve(process.cwd(), this.filePath);
28
27
  if (testFilePath) {
29
28
  const testFile = fs_1.default.readFileSync(testFilePath, "utf-8");
30
- const jsComments = (0, string_1.convertTextToJsComments)(task);
31
- const updatedTestFile = testFile.replace(/await createTest\([\s\S]*?\);\n/, jsComments + "\n" + generatedCode);
29
+ const updatedTestFile = testFile.replace(/await createTest\([\s\S]*?\);\n/, "\n" + generatedCode);
32
30
  const importStatement = `import { test, expect } from "@playwright/test";`;
33
31
  fs_1.default.writeFileSync(testFilePath, importStatement + "\n" + updatedTestFile, "utf-8");
34
- (0, web_1.lintErrors)(testFilePath);
32
+ await (0, web_1.lintErrors)(testFilePath);
35
33
  return res.send({ success: true });
36
34
  }
37
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAWlC,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,iBAkBnE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAWlC,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,iBAiBnE"}
package/dist/index.js CHANGED
@@ -15,8 +15,7 @@ process.on("SIGTERM", async () => await (0, llm_1.flushAllTraces)());
15
15
  async function createTest(task, page, test) {
16
16
  const port = process.env.APP_PORT || 3030;
17
17
  const testConfigArg = process.env.TEST_GEN_TOKEN;
18
- const { testGenConfigs } = await (0, utils_1.parseCliArgs)(testConfigArg);
19
- const [testGenConfig] = testGenConfigs;
18
+ const { testGenConfig } = await (0, utils_1.parseCliArgs)(testConfigArg);
20
19
  (0, reporter_1.setReporterConfig)(testGenConfig.options?.metadata);
21
20
  const fileService = new client_1.default(Number(port));
22
21
  test.setTimeout(900000);
@@ -1,3 +1,3 @@
1
- import { Scenario } from "../types";
2
- export declare function reportOnCI(scenarios: Scenario[]): Promise<Scenario[]>;
1
+ import { TestCase } from "../types";
2
+ export declare function reportOnCI(testCase: TestCase): Promise<TestCase>;
3
3
  //# sourceMappingURL=ci.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ci.d.ts","sourceRoot":"","sources":["../../src/reporter/ci.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,wBAAsB,UAAU,CAAC,SAAS,EAAE,QAAQ,EAAE,uBAYrD"}
1
+ {"version":3,"file":"ci.d.ts","sourceRoot":"","sources":["../../src/reporter/ci.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,wBAAsB,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAOtE"}
@@ -25,17 +25,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.reportOnCI = void 0;
27
27
  const core = __importStar(require("@actions/core"));
28
- async function reportOnCI(scenarios) {
28
+ async function reportOnCI(testCase) {
29
29
  if ("true") {
30
- const testNames = scenarios.map((s) => s.name).join(" ");
31
- const scenariosOutput = scenarios
32
- .map((s) => {
33
- return `**Scenario:** ${s.name} \n\n**Steps:**\n - ${s.steps.join("\n - ")}`;
34
- })
35
- .join("\n ----- \n");
30
+ const scenariosOutput = `**Scenario:** ${testCase.name} \n\n**Steps:**\n - ${testCase.steps.join("\n - ")}`;
36
31
  core.setOutput("summary", scenariosOutput);
37
- core.setOutput("test_names", testNames);
32
+ core.setOutput("test_names", testCase.name);
38
33
  }
39
- return scenarios;
34
+ return testCase;
40
35
  }
41
36
  exports.reportOnCI = reportOnCI;
@@ -20,13 +20,12 @@ export type TestGenConfigOptions = {
20
20
  };
21
21
  export type TestGenConfig = {
22
22
  specPath: string;
23
- scenarios: Scenario[];
23
+ testCase: TestCase;
24
24
  options?: TestGenConfigOptions;
25
25
  };
26
- export type Scenario = {
26
+ export type TestCase = {
27
27
  name: string;
28
28
  steps: string[];
29
- assert: string;
30
29
  };
31
30
  export type PlaywrightActionGenerator = (page: Page) => Action;
32
31
  export type ActionSchema = OpenAI.Chat.Completions.ChatCompletionTool;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,EAAE,QAAQ,CAAC;IAChB,aAAa,EAAE,WAAW,CAAC;IAC3B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,QAAQ,EAAE;QACR,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,MAAM,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,aAAa,GAAG,YAAY,CAAC;KAC3C,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC;AAE/D,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC;AAEtE,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC5E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CAC/E,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,EAAE,QAAQ,CAAC;IAChB,aAAa,EAAE,WAAW,CAAC;IAC3B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,QAAQ,EAAE;QACR,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,MAAM,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,aAAa,GAAG,YAAY,CAAC;KAC3C,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC;AAE/D,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC;AAEtE,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC5E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CAC/E,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/test-gen",
3
- "version": "0.16.13",
3
+ "version": "0.17.0",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"