@dev-blinq/cucumber_client 1.0.1197-dev → 1.0.1197-stage
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/bin/assets/bundled_scripts/recorder.js +220 -0
- package/bin/assets/preload/find_context.js +1 -1
- package/bin/assets/preload/recorderv3.js +75 -5
- package/bin/assets/preload/unique_locators.js +24 -3
- package/bin/assets/scripts/aria_snapshot.js +235 -0
- package/bin/assets/scripts/dom_attr.js +372 -0
- package/bin/assets/scripts/dom_element.js +0 -0
- package/bin/assets/scripts/dom_parent.js +185 -0
- package/bin/assets/scripts/event_utils.js +105 -0
- package/bin/assets/scripts/pw.js +7886 -0
- package/bin/assets/scripts/recorder.js +1147 -0
- package/bin/assets/scripts/snapshot_capturer.js +155 -0
- package/bin/assets/scripts/unique_locators.js +841 -0
- package/bin/assets/scripts/yaml.js +4770 -0
- package/bin/assets/templates/page_template.txt +2 -16
- package/bin/assets/templates/utils_template.txt +59 -7
- package/bin/client/cli_helpers.js +11 -13
- package/bin/client/code_cleanup/utils.js +42 -14
- package/bin/client/code_gen/code_inversion.js +48 -11
- package/bin/client/code_gen/index.js +3 -0
- package/bin/client/code_gen/page_reflection.js +37 -20
- package/bin/client/code_gen/playwright_codeget.js +153 -25
- package/bin/client/cucumber/feature.js +92 -35
- package/bin/client/cucumber/steps_definitions.js +109 -83
- package/bin/client/local_agent.js +6 -2
- package/bin/client/project.js +6 -2
- package/bin/client/recorderv3/bvt_recorder.js +272 -76
- package/bin/client/recorderv3/implemented_steps.js +69 -14
- package/bin/client/recorderv3/index.js +49 -7
- package/bin/client/recorderv3/network.js +299 -0
- package/bin/client/recorderv3/step_runner.js +183 -13
- package/bin/client/recorderv3/step_utils.js +155 -8
- package/bin/client/recorderv3/update_feature.js +58 -30
- package/bin/client/recording.js +7 -0
- package/bin/client/run_cucumber.js +16 -2
- package/bin/client/scenario_report.js +35 -8
- package/bin/client/test_scenario.js +0 -1
- package/bin/index.js +1 -0
- package/package.json +15 -8
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
|
1
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import fs from "fs";
|
|
4
3
|
import { generatePageName } from "../code_gen/playwright_codeget.js";
|
|
5
4
|
import {
|
|
6
5
|
executeStep,
|
|
@@ -9,26 +8,36 @@ import {
|
|
|
9
8
|
getUtilsCodePage,
|
|
10
9
|
loadStepDefinitions,
|
|
11
10
|
saveRecording,
|
|
11
|
+
saveRoutes,
|
|
12
12
|
} from "./step_utils.js";
|
|
13
13
|
import { escapeString, getExamplesContent } from "./update_feature.js";
|
|
14
|
+
import fs from "fs";
|
|
15
|
+
import { locateDefinitionPath } from "../cucumber/steps_definitions.js";
|
|
16
|
+
import { tmpdir } from "os";
|
|
14
17
|
|
|
15
18
|
// let copiedCodeToTemp = false;
|
|
16
19
|
async function withAbort(fn, signal) {
|
|
17
20
|
if (!signal) {
|
|
18
21
|
return await fn();
|
|
19
22
|
}
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
const abortHandler = () => reject(new Error("Aborted"));
|
|
25
|
+
signal.addEventListener("abort", abortHandler, { once: true });
|
|
20
26
|
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
fn()
|
|
28
|
+
.then(resolve)
|
|
29
|
+
.catch(reject)
|
|
30
|
+
.finally(() => {
|
|
31
|
+
signal.removeEventListener("abort", abortHandler);
|
|
32
|
+
});
|
|
23
33
|
});
|
|
24
|
-
|
|
25
|
-
return await Promise.race([fn(), abortPromise]);
|
|
26
34
|
}
|
|
27
35
|
export class BVTStepRunner {
|
|
28
36
|
#currentStepController;
|
|
29
37
|
#port;
|
|
30
|
-
constructor({ projectDir }) {
|
|
38
|
+
constructor({ projectDir, sendExecutionStatus }) {
|
|
31
39
|
this.projectDir = projectDir;
|
|
40
|
+
this.sendExecutionStatus = sendExecutionStatus;
|
|
32
41
|
}
|
|
33
42
|
setRemoteDebugPort(port) {
|
|
34
43
|
this.#port = port;
|
|
@@ -55,11 +64,12 @@ export class BVTStepRunner {
|
|
|
55
64
|
// copiedCodeToTemp = true;
|
|
56
65
|
}
|
|
57
66
|
|
|
58
|
-
async writeTempFeatureFile({ step, parametersMap, tempFolderPath }) {
|
|
67
|
+
async writeTempFeatureFile({ step, parametersMap, tempFolderPath, tags }) {
|
|
59
68
|
const tFilePath = path.join(tempFolderPath, "__temp.feature");
|
|
60
69
|
// console.log(tFilePath);
|
|
61
70
|
let tFileContent = `# temp feature file
|
|
62
71
|
Feature: Temp feature
|
|
72
|
+
${tags ? tags.join(" ") : ""}
|
|
63
73
|
Scenario Outline: Temp Scenario
|
|
64
74
|
Given ${escapeString(step.text)}
|
|
65
75
|
`;
|
|
@@ -67,7 +77,135 @@ export class BVTStepRunner {
|
|
|
67
77
|
writeFileSync(tFilePath, tFileContent);
|
|
68
78
|
return tFilePath;
|
|
69
79
|
}
|
|
70
|
-
|
|
80
|
+
|
|
81
|
+
executeStepRemote = async ({ feature_file_path, scenario, tempFolderPath, stepText, config }, options) => {
|
|
82
|
+
const { skipAfter = true, skipBefore = true } = options || {};
|
|
83
|
+
const environment = {
|
|
84
|
+
...process.env,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const { loadConfiguration, loadSupport, runCucumber } = await import("@dev-blinq/cucumber-js/api");
|
|
89
|
+
const { runConfiguration } = await loadConfiguration(
|
|
90
|
+
{
|
|
91
|
+
provided: {
|
|
92
|
+
name: [scenario],
|
|
93
|
+
paths: [feature_file_path],
|
|
94
|
+
import: [path.join(tempFolderPath, "step_definitions", "**", "*.mjs")],
|
|
95
|
+
// format: ["bvt"],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{ cwd: process.cwd(), env: environment }
|
|
99
|
+
);
|
|
100
|
+
// const files = glob.sync(path.join(tempFolderPath, "step_definitions", "**", "*.mjs"));
|
|
101
|
+
// console.log("Files found:", files);
|
|
102
|
+
const support = await loadSupport(runConfiguration, { cwd: process.cwd(), env: environment });
|
|
103
|
+
// console.log("found ", support.stepDefinitions.length, "step definitions");
|
|
104
|
+
// support.stepDefinitions.map((step) => {
|
|
105
|
+
// console.log("step", step.pattern);
|
|
106
|
+
// });
|
|
107
|
+
|
|
108
|
+
support.afterTestRunHookDefinitions = [];
|
|
109
|
+
if (skipAfter) {
|
|
110
|
+
// ignore afterAll/after hooks
|
|
111
|
+
support.afterTestCaseHookDefinitions = [];
|
|
112
|
+
}
|
|
113
|
+
if (skipBefore && !config.legacySyntax) {
|
|
114
|
+
// ignore beforeAll/before hooks
|
|
115
|
+
support.beforeTestCaseHookDefinitions = support.beforeTestCaseHookDefinitions.filter((hook) => {
|
|
116
|
+
return hook.uri.endsWith("utils.mjs");
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
support.beforeTestRunHookDefinitions = [];
|
|
120
|
+
|
|
121
|
+
let errorMesssage = null;
|
|
122
|
+
let info = null;
|
|
123
|
+
let errInfo = null;
|
|
124
|
+
const result = await runCucumber({ ...runConfiguration, support }, environment, (message) => {
|
|
125
|
+
if (message.testStepFinished) {
|
|
126
|
+
const { testStepFinished } = message;
|
|
127
|
+
const { testStepResult } = testStepFinished;
|
|
128
|
+
if (testStepResult.status === "FAILED" || testStepResult.status === "AMBIGUOUS") {
|
|
129
|
+
if (!errorMesssage) {
|
|
130
|
+
errorMesssage = testStepResult.message;
|
|
131
|
+
if (info) {
|
|
132
|
+
errInfo = info;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (testStepResult.status === "UNDEFINED") {
|
|
137
|
+
if (!errorMesssage) {
|
|
138
|
+
errorMesssage = `step ${JSON.stringify(stepText)} is ${testStepResult.status}`;
|
|
139
|
+
if (info) {
|
|
140
|
+
errInfo = info;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (message.attachment) {
|
|
146
|
+
const attachment = message.attachment;
|
|
147
|
+
if (attachment.mediaType === "application/json" && attachment.body) {
|
|
148
|
+
const body = JSON.parse(attachment.body);
|
|
149
|
+
info = body.info;
|
|
150
|
+
const result = body.result;
|
|
151
|
+
|
|
152
|
+
if (result.status === "PASSED") {
|
|
153
|
+
this.sendExecutionStatus({
|
|
154
|
+
type: "cmdExecutionSuccess",
|
|
155
|
+
cmdId: body.cmdId,
|
|
156
|
+
});
|
|
157
|
+
} else {
|
|
158
|
+
this.sendExecutionStatus({
|
|
159
|
+
type: "cmdExecutionError",
|
|
160
|
+
cmdId: body.cmdId,
|
|
161
|
+
error: {
|
|
162
|
+
message: result.message,
|
|
163
|
+
info,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
} else if (attachment.mediaType === "application/json+intercept-results" && attachment.body) {
|
|
168
|
+
const body = JSON.parse(attachment.body);
|
|
169
|
+
if (body) {
|
|
170
|
+
this.sendExecutionStatus({
|
|
171
|
+
type: "interceptResults",
|
|
172
|
+
interceptResults: body,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
if (errorMesssage) {
|
|
179
|
+
const bvtError = new Error(errorMesssage);
|
|
180
|
+
Object.assign(bvtError, { info: errInfo });
|
|
181
|
+
throw bvtError;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
result,
|
|
186
|
+
info,
|
|
187
|
+
};
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error("Error running cucumber-js", error);
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
async runStep({ step, parametersMap, envPath, tags, config }, bvtContext, options) {
|
|
195
|
+
let cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId);
|
|
196
|
+
if (bvtContext.web) {
|
|
197
|
+
bvtContext.web.getCmdId = () => {
|
|
198
|
+
if (cmdIDs.length === 0) {
|
|
199
|
+
cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId);
|
|
200
|
+
}
|
|
201
|
+
const cId = cmdIDs.shift();
|
|
202
|
+
this.sendExecutionStatus({
|
|
203
|
+
type: "cmdExecutionStart",
|
|
204
|
+
cmdId: cId,
|
|
205
|
+
});
|
|
206
|
+
return cId;
|
|
207
|
+
};
|
|
208
|
+
}
|
|
71
209
|
let codePage; // = getCodePage();
|
|
72
210
|
// const tempFolderPath = process.env.tempFeaturesFolderPath;
|
|
73
211
|
const __temp_features_FolderName = "__temp_features" + Math.random().toString(36).substring(2, 7);
|
|
@@ -96,7 +234,8 @@ export class BVTStepRunner {
|
|
|
96
234
|
if (!existsSync(stepDefinitionFolderPath)) {
|
|
97
235
|
mkdirSync(stepDefinitionFolderPath, { recursive: true });
|
|
98
236
|
}
|
|
99
|
-
const stepDefsFilePath =
|
|
237
|
+
const stepDefsFilePath = locateDefinitionPath(tempFolderPath, pageName);
|
|
238
|
+
//path.join(stepDefinitionFolderPath, pageName + "_page.mjs");
|
|
100
239
|
codePage = getCodePage(stepDefsFilePath);
|
|
101
240
|
codePage = await saveRecording({ step, cucumberStep, codePage, projectDir: this.projectDir, stepsDefinitions });
|
|
102
241
|
if (codePage) {
|
|
@@ -106,19 +245,49 @@ export class BVTStepRunner {
|
|
|
106
245
|
if (!codePage) {
|
|
107
246
|
codePage = getUtilsCodePage(this.projectDir);
|
|
108
247
|
}
|
|
248
|
+
} else {
|
|
249
|
+
let routesPath = path.join(tmpdir(), `blinq_temp_routes`);
|
|
250
|
+
if (process.env.TEMP_RUN === "true") {
|
|
251
|
+
// console.log("Save routes in temp folder for running:", routesPath);
|
|
252
|
+
if (existsSync(routesPath)) {
|
|
253
|
+
console.log("Removing existing temp_routes_folder:", routesPath);
|
|
254
|
+
rmSync(routesPath, { recursive: true });
|
|
255
|
+
}
|
|
256
|
+
mkdirSync(routesPath, { recursive: true });
|
|
257
|
+
console.log("Created temp_routes_folder:", routesPath);
|
|
258
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
259
|
+
} else {
|
|
260
|
+
console.log("Saving routes in project directory:", this.projectDir);
|
|
261
|
+
if (existsSync(routesPath)) {
|
|
262
|
+
// remove the folder
|
|
263
|
+
try {
|
|
264
|
+
rmSync(routesPath, { recursive: true });
|
|
265
|
+
console.log("Removed temp_routes_folder:", routesPath);
|
|
266
|
+
} catch (error) {
|
|
267
|
+
console.error("Error removing temp_routes folder", error);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
routesPath = path.join(this.projectDir, "data", "routes");
|
|
271
|
+
console.log("Saving routes to:", routesPath);
|
|
272
|
+
if (!existsSync(routesPath)) {
|
|
273
|
+
mkdirSync(routesPath, { recursive: true });
|
|
274
|
+
}
|
|
275
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
276
|
+
}
|
|
109
277
|
}
|
|
110
|
-
const feature_file_path = await this.writeTempFeatureFile({ step, parametersMap, tempFolderPath });
|
|
278
|
+
const feature_file_path = await this.writeTempFeatureFile({ step, parametersMap, tempFolderPath, tags });
|
|
111
279
|
// console.log({ feature_file_path, step_text: step.text });
|
|
112
280
|
|
|
113
281
|
const stepExecController = new AbortController();
|
|
114
282
|
this.#currentStepController = stepExecController;
|
|
115
|
-
await withAbort(async () => {
|
|
116
|
-
await
|
|
283
|
+
const { result, info } = await withAbort(async () => {
|
|
284
|
+
return await this.executeStepRemote(
|
|
117
285
|
{
|
|
118
286
|
feature_file_path,
|
|
119
287
|
tempFolderPath,
|
|
120
288
|
stepText: step.text,
|
|
121
289
|
scenario: "Temp Scenario",
|
|
290
|
+
config,
|
|
122
291
|
},
|
|
123
292
|
options
|
|
124
293
|
);
|
|
@@ -128,5 +297,6 @@ export class BVTStepRunner {
|
|
|
128
297
|
fs.rmSync(tempFolderPath, { recursive: true });
|
|
129
298
|
}
|
|
130
299
|
});
|
|
300
|
+
return { result, info };
|
|
131
301
|
}
|
|
132
302
|
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import url from "url";
|
|
4
4
|
import logger from "../../logger.js";
|
|
5
|
-
import { CodePage } from "../code_gen/page_reflection.js";
|
|
5
|
+
import { CodePage, getAiConfig } from "../code_gen/page_reflection.js";
|
|
6
6
|
import { generateCode, generatePageName } from "../code_gen/playwright_codeget.js";
|
|
7
7
|
import { invertCodeToCommand } from "../code_gen/code_inversion.js";
|
|
8
8
|
import { Step } from "../cucumber/feature.js";
|
|
9
|
-
import { StepsDefinitions } from "../cucumber/steps_definitions.js";
|
|
9
|
+
import { locateDefinitionPath, StepsDefinitions } from "../cucumber/steps_definitions.js";
|
|
10
10
|
import { Recording } from "../recording.js";
|
|
11
11
|
import { generateApiCode } from "../code_gen/api_codegen.js";
|
|
12
|
+
import { tmpdir } from "os";
|
|
13
|
+
import { createHash } from "crypto";
|
|
12
14
|
|
|
13
15
|
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
14
16
|
|
|
@@ -69,19 +71,74 @@ function makeStepTextUnique(step, stepsDefinitions) {
|
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
export async function saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions }) {
|
|
72
|
-
|
|
74
|
+
let routesPath = path.join(tmpdir(), "blinq_temp_routes");
|
|
75
|
+
|
|
76
|
+
if (process.env.TEMP_RUN) {
|
|
77
|
+
if (existsSync(routesPath)) {
|
|
78
|
+
rmSync(routesPath, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
mkdirSync(routesPath, { recursive: true });
|
|
81
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
82
|
+
} else {
|
|
83
|
+
if (existsSync(routesPath)) {
|
|
84
|
+
// remove the folder
|
|
85
|
+
try {
|
|
86
|
+
rmSync(routesPath, { recursive: true });
|
|
87
|
+
console.log("Removed temp_routes_folder:", routesPath);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error("Error removing temp_routes folder", error);
|
|
90
|
+
}
|
|
91
|
+
routesPath = path.join(projectDir, "data", "routes");
|
|
92
|
+
if (!existsSync(routesPath)) {
|
|
93
|
+
mkdirSync(routesPath, { recursive: true });
|
|
94
|
+
}
|
|
95
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
73
99
|
if (step.isImplementedWhileRecording && !process.env.TEMP_RUN) {
|
|
74
100
|
return;
|
|
75
101
|
}
|
|
102
|
+
|
|
76
103
|
if (step.isImplemented && step.shouldOverride) {
|
|
77
104
|
let stepDef = stepsDefinitions.findMatchingStep(step.text);
|
|
78
105
|
codePage = getCodePage(stepDef.file);
|
|
79
106
|
} else {
|
|
80
107
|
const isUtilStep = makeStepTextUnique(step, stepsDefinitions);
|
|
108
|
+
|
|
81
109
|
if (isUtilStep) {
|
|
82
110
|
return;
|
|
83
111
|
}
|
|
84
112
|
}
|
|
113
|
+
|
|
114
|
+
if (process.env.TEMP_RUN === "true") {
|
|
115
|
+
console.log("Save routes in temp folder for running:", routesPath);
|
|
116
|
+
if (existsSync(routesPath)) {
|
|
117
|
+
console.log("Removing existing temp_routes_folder:", routesPath);
|
|
118
|
+
rmSync(routesPath, { recursive: true });
|
|
119
|
+
}
|
|
120
|
+
mkdirSync(routesPath, { recursive: true });
|
|
121
|
+
console.log("Created temp_routes_folder:", routesPath);
|
|
122
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
123
|
+
} else {
|
|
124
|
+
console.log("Saving routes in project directory:", projectDir);
|
|
125
|
+
if (existsSync(routesPath)) {
|
|
126
|
+
// remove the folder
|
|
127
|
+
try {
|
|
128
|
+
rmSync(routesPath, { recursive: true });
|
|
129
|
+
console.log("Removed temp_routes_folder:", routesPath);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error("Error removing temp_routes folder", error);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
routesPath = path.join(projectDir, "data", "routes");
|
|
135
|
+
console.log("Saving routes to:", routesPath);
|
|
136
|
+
if (!existsSync(routesPath)) {
|
|
137
|
+
mkdirSync(routesPath, { recursive: true });
|
|
138
|
+
}
|
|
139
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
140
|
+
}
|
|
141
|
+
|
|
85
142
|
cucumberStep.text = step.text;
|
|
86
143
|
const recording = new Recording();
|
|
87
144
|
const steps = step.commands;
|
|
@@ -108,6 +165,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
108
165
|
isStaticToken,
|
|
109
166
|
status,
|
|
110
167
|
} = step.commands[0].value;
|
|
168
|
+
|
|
111
169
|
const result = await generateApiCode(
|
|
112
170
|
{
|
|
113
171
|
url,
|
|
@@ -132,6 +190,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
132
190
|
step.keyword,
|
|
133
191
|
stepsDefinitions
|
|
134
192
|
);
|
|
193
|
+
|
|
135
194
|
if (!step.isImplemented) {
|
|
136
195
|
stepsDefinitions.addStep({
|
|
137
196
|
name: step.text,
|
|
@@ -139,6 +198,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
139
198
|
source: "recorder",
|
|
140
199
|
});
|
|
141
200
|
}
|
|
201
|
+
|
|
142
202
|
cucumberStep.methodName = result.methodName;
|
|
143
203
|
return result.codePage;
|
|
144
204
|
} else {
|
|
@@ -166,7 +226,13 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
166
226
|
path
|
|
167
227
|
);
|
|
168
228
|
const keyword = (cucumberStep.keywordAlias ?? cucumberStep.keyword).trim();
|
|
169
|
-
const stepResult = codePage.addCucumberStep(
|
|
229
|
+
const stepResult = codePage.addCucumberStep(
|
|
230
|
+
keyword,
|
|
231
|
+
cucumberStep.getTemplate(),
|
|
232
|
+
methodName,
|
|
233
|
+
steps.length,
|
|
234
|
+
step.finalTimeout
|
|
235
|
+
);
|
|
170
236
|
|
|
171
237
|
if (!step.isImplemented) {
|
|
172
238
|
stepsDefinitions.addStep({
|
|
@@ -187,7 +253,17 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
187
253
|
|
|
188
254
|
const getLocatorsJson = (file) => {
|
|
189
255
|
if (!file) return {};
|
|
190
|
-
|
|
256
|
+
let locatorsFilePath = file.replace(".mjs", ".json");
|
|
257
|
+
const originLocatorsFilePath = locatorsFilePath;
|
|
258
|
+
const config = getAiConfig();
|
|
259
|
+
if (config && config.locatorsMetadataDir) {
|
|
260
|
+
// if config.locatorsMetadataDir is set, use it to create the file path
|
|
261
|
+
locatorsFilePath = path.join(config.locatorsMetadataDir, path.basename(locatorsFilePath));
|
|
262
|
+
if (!existsSync(locatorsFilePath)) {
|
|
263
|
+
// if the file does not exist in the config directory, use the original path
|
|
264
|
+
locatorsFilePath = originLocatorsFilePath;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
191
267
|
if (!existsSync(locatorsFilePath)) {
|
|
192
268
|
return {};
|
|
193
269
|
}
|
|
@@ -299,6 +375,7 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
299
375
|
const steps = scenario.steps;
|
|
300
376
|
|
|
301
377
|
const stepsDefinitions = new StepsDefinitions(projectDir);
|
|
378
|
+
const featureFolder = path.join(projectDir, "features");
|
|
302
379
|
stepsDefinitions.load(false);
|
|
303
380
|
// const parameters = scenario.parameters;
|
|
304
381
|
// await saveRecordings({ steps, parameters, codePage, projectDir });
|
|
@@ -310,13 +387,41 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
310
387
|
}
|
|
311
388
|
}
|
|
312
389
|
if ((step.isImplemented && !step.shouldOverride) || step.commands.length === 0) {
|
|
390
|
+
let routesPath = path.join(tmpdir(), `blinq_temp_routes`);
|
|
391
|
+
if (process.env.TEMP_RUN === "true") {
|
|
392
|
+
console.log("Save routes in temp folder for running:", routesPath);
|
|
393
|
+
if (existsSync(routesPath)) {
|
|
394
|
+
console.log("Removing existing temp_routes_folder:", routesPath);
|
|
395
|
+
rmSync(routesPath, { recursive: true });
|
|
396
|
+
}
|
|
397
|
+
mkdirSync(routesPath, { recursive: true });
|
|
398
|
+
console.log("Created temp_routes_folder:", routesPath);
|
|
399
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
400
|
+
} else {
|
|
401
|
+
console.log("Saving routes in project directory:", projectDir);
|
|
402
|
+
if (existsSync(routesPath)) {
|
|
403
|
+
// remove the folder
|
|
404
|
+
try {
|
|
405
|
+
rmSync(routesPath, { recursive: true });
|
|
406
|
+
console.log("Removed temp_routes_folder:", routesPath);
|
|
407
|
+
} catch (error) {
|
|
408
|
+
console.error("Error removing temp_routes folder", error);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
routesPath = path.join(projectDir, "data", "routes");
|
|
412
|
+
console.log("Saving routes to:", routesPath);
|
|
413
|
+
if (!existsSync(routesPath)) {
|
|
414
|
+
mkdirSync(routesPath, { recursive: true });
|
|
415
|
+
}
|
|
416
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
417
|
+
}
|
|
313
418
|
continue;
|
|
314
419
|
}
|
|
315
420
|
const cucumberStep = getCucumberStep({ step });
|
|
316
421
|
const pageName = generatePageName(step.startFrame?.url ?? "default");
|
|
317
|
-
const stepDefsFilePath =
|
|
422
|
+
const stepDefsFilePath = locateDefinitionPath(featureFolder, pageName);
|
|
423
|
+
// path.join(stepDefinitionFolderPath, pageName + "_page.mjs");
|
|
318
424
|
let codePage = getCodePage(stepDefsFilePath);
|
|
319
|
-
|
|
320
425
|
codePage = await saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions });
|
|
321
426
|
if (!codePage) {
|
|
322
427
|
continue;
|
|
@@ -328,3 +433,45 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
328
433
|
}
|
|
329
434
|
writeFileSync(utilsFilePath, utilsContent, "utf8");
|
|
330
435
|
}
|
|
436
|
+
|
|
437
|
+
export function saveRoutes({ step, folderPath }) {
|
|
438
|
+
const routeItems = step.routeItems;
|
|
439
|
+
if (!routeItems || routeItems.length === 0) {
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
const cucumberStep = getCucumberStep({ step });
|
|
443
|
+
const template = cucumberStep.getTemplate();
|
|
444
|
+
const stepNameHash = createHash("sha256").update(template).digest("hex");
|
|
445
|
+
console.log("Saving routes for step:", step.text, "with hash:", stepNameHash);
|
|
446
|
+
|
|
447
|
+
const routeItemsWithFilters = routeItems.map((routeItem) => {
|
|
448
|
+
const oldFilters = routeItem.filters;
|
|
449
|
+
const queryParamsObject = {};
|
|
450
|
+
oldFilters.queryParams.forEach((queryParam) => {
|
|
451
|
+
queryParamsObject[queryParam.key] = queryParam.value;
|
|
452
|
+
});
|
|
453
|
+
const newFilters = { path: oldFilters.path, method: oldFilters.method, queryParams: queryParamsObject };
|
|
454
|
+
return {
|
|
455
|
+
...routeItem,
|
|
456
|
+
filters: newFilters,
|
|
457
|
+
};
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
const routesFilePath = path.join(folderPath, stepNameHash + ".json");
|
|
461
|
+
console.log("Routes file path:", routesFilePath);
|
|
462
|
+
const routesData = {
|
|
463
|
+
template,
|
|
464
|
+
routes: routeItemsWithFilters,
|
|
465
|
+
};
|
|
466
|
+
console.log("Routes data to save:", routesData);
|
|
467
|
+
|
|
468
|
+
if (!existsSync(folderPath)) {
|
|
469
|
+
mkdirSync(folderPath, { recursive: true });
|
|
470
|
+
}
|
|
471
|
+
try {
|
|
472
|
+
writeFileSync(routesFilePath, JSON.stringify(routesData, null, 2), "utf8");
|
|
473
|
+
console.log("Saved routes to", routesFilePath);
|
|
474
|
+
} catch (error) {
|
|
475
|
+
console.error("Failed to save routes to", routesFilePath, "Error:", error);
|
|
476
|
+
}
|
|
477
|
+
}
|