@dev-blinq/cucumber_client 1.0.1216-dev → 1.0.1216-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/recorderv3.js +74 -4
- 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/_hooks_template.txt +37 -0
- package/bin/assets/templates/page_template.txt +2 -16
- package/bin/assets/templates/utils_template.txt +48 -63
- package/bin/client/apiTest/apiTest.js +6 -0
- 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 +92 -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 +170 -33
- package/bin/client/cucumber/feature.js +85 -27
- package/bin/client/cucumber/steps_definitions.js +85 -77
- package/bin/client/local_agent.js +7 -3
- package/bin/client/project.js +7 -1
- package/bin/client/recorderv3/bvt_recorder.js +278 -79
- package/bin/client/recorderv3/implemented_steps.js +75 -14
- package/bin/client/recorderv3/index.js +49 -7
- package/bin/client/recorderv3/network.js +299 -0
- package/bin/client/recorderv3/step_runner.js +181 -12
- package/bin/client/recorderv3/step_utils.js +157 -6
- package/bin/client/recorderv3/update_feature.js +58 -30
- package/bin/client/recording.js +7 -0
- package/bin/client/run_cucumber.js +15 -2
- package/bin/client/scenario_report.js +18 -6
- 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,27 +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";
|
|
14
15
|
import { locateDefinitionPath } from "../cucumber/steps_definitions.js";
|
|
16
|
+
import { tmpdir } from "os";
|
|
15
17
|
|
|
16
18
|
// let copiedCodeToTemp = false;
|
|
17
19
|
async function withAbort(fn, signal) {
|
|
18
20
|
if (!signal) {
|
|
19
21
|
return await fn();
|
|
20
22
|
}
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
const abortHandler = () => reject(new Error("Aborted"));
|
|
25
|
+
signal.addEventListener("abort", abortHandler, { once: true });
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
fn()
|
|
28
|
+
.then(resolve)
|
|
29
|
+
.catch(reject)
|
|
30
|
+
.finally(() => {
|
|
31
|
+
signal.removeEventListener("abort", abortHandler);
|
|
32
|
+
});
|
|
24
33
|
});
|
|
25
|
-
|
|
26
|
-
return await Promise.race([fn(), abortPromise]);
|
|
27
34
|
}
|
|
28
35
|
export class BVTStepRunner {
|
|
29
36
|
#currentStepController;
|
|
30
37
|
#port;
|
|
31
|
-
constructor({ projectDir }) {
|
|
38
|
+
constructor({ projectDir, sendExecutionStatus }) {
|
|
32
39
|
this.projectDir = projectDir;
|
|
40
|
+
this.sendExecutionStatus = sendExecutionStatus;
|
|
33
41
|
}
|
|
34
42
|
setRemoteDebugPort(port) {
|
|
35
43
|
this.#port = port;
|
|
@@ -56,11 +64,12 @@ export class BVTStepRunner {
|
|
|
56
64
|
// copiedCodeToTemp = true;
|
|
57
65
|
}
|
|
58
66
|
|
|
59
|
-
async writeTempFeatureFile({ step, parametersMap, tempFolderPath }) {
|
|
67
|
+
async writeTempFeatureFile({ step, parametersMap, tempFolderPath, tags }) {
|
|
60
68
|
const tFilePath = path.join(tempFolderPath, "__temp.feature");
|
|
61
69
|
// console.log(tFilePath);
|
|
62
70
|
let tFileContent = `# temp feature file
|
|
63
71
|
Feature: Temp feature
|
|
72
|
+
${tags ? tags.join(" ") : ""}
|
|
64
73
|
Scenario Outline: Temp Scenario
|
|
65
74
|
Given ${escapeString(step.text)}
|
|
66
75
|
`;
|
|
@@ -68,7 +77,136 @@ export class BVTStepRunner {
|
|
|
68
77
|
writeFileSync(tFilePath, tFileContent);
|
|
69
78
|
return tFilePath;
|
|
70
79
|
}
|
|
71
|
-
|
|
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
|
+
selectedStrategy: info?.selectedStrategy,
|
|
157
|
+
});
|
|
158
|
+
} else {
|
|
159
|
+
this.sendExecutionStatus({
|
|
160
|
+
type: "cmdExecutionError",
|
|
161
|
+
cmdId: body.cmdId,
|
|
162
|
+
error: {
|
|
163
|
+
message: result.message,
|
|
164
|
+
info,
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
} else if (attachment.mediaType === "application/json+intercept-results" && attachment.body) {
|
|
169
|
+
const body = JSON.parse(attachment.body);
|
|
170
|
+
if (body) {
|
|
171
|
+
this.sendExecutionStatus({
|
|
172
|
+
type: "interceptResults",
|
|
173
|
+
interceptResults: body,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
if (errorMesssage) {
|
|
180
|
+
const bvtError = new Error(errorMesssage);
|
|
181
|
+
Object.assign(bvtError, { info: errInfo });
|
|
182
|
+
throw bvtError;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
result,
|
|
187
|
+
info,
|
|
188
|
+
};
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error("Error running cucumber-js", error);
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
async runStep({ step, parametersMap, envPath, tags, config }, bvtContext, options) {
|
|
196
|
+
let cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId);
|
|
197
|
+
if (bvtContext.web) {
|
|
198
|
+
bvtContext.web.getCmdId = () => {
|
|
199
|
+
if (cmdIDs.length === 0) {
|
|
200
|
+
cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId);
|
|
201
|
+
}
|
|
202
|
+
const cId = cmdIDs.shift();
|
|
203
|
+
this.sendExecutionStatus({
|
|
204
|
+
type: "cmdExecutionStart",
|
|
205
|
+
cmdId: cId,
|
|
206
|
+
});
|
|
207
|
+
return cId;
|
|
208
|
+
};
|
|
209
|
+
}
|
|
72
210
|
let codePage; // = getCodePage();
|
|
73
211
|
// const tempFolderPath = process.env.tempFeaturesFolderPath;
|
|
74
212
|
const __temp_features_FolderName = "__temp_features" + Math.random().toString(36).substring(2, 7);
|
|
@@ -108,19 +246,49 @@ export class BVTStepRunner {
|
|
|
108
246
|
if (!codePage) {
|
|
109
247
|
codePage = getUtilsCodePage(this.projectDir);
|
|
110
248
|
}
|
|
249
|
+
} else {
|
|
250
|
+
let routesPath = path.join(tmpdir(), `blinq_temp_routes`);
|
|
251
|
+
if (process.env.TEMP_RUN === "true") {
|
|
252
|
+
// console.log("Save routes in temp folder for running:", routesPath);
|
|
253
|
+
if (existsSync(routesPath)) {
|
|
254
|
+
console.log("Removing existing temp_routes_folder:", routesPath);
|
|
255
|
+
rmSync(routesPath, { recursive: true });
|
|
256
|
+
}
|
|
257
|
+
mkdirSync(routesPath, { recursive: true });
|
|
258
|
+
console.log("Created temp_routes_folder:", routesPath);
|
|
259
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
260
|
+
} else {
|
|
261
|
+
console.log("Saving routes in project directory:", this.projectDir);
|
|
262
|
+
if (existsSync(routesPath)) {
|
|
263
|
+
// remove the folder
|
|
264
|
+
try {
|
|
265
|
+
rmSync(routesPath, { recursive: true });
|
|
266
|
+
console.log("Removed temp_routes_folder:", routesPath);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
console.error("Error removing temp_routes folder", error);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
routesPath = path.join(this.projectDir, "data", "routes");
|
|
272
|
+
console.log("Saving routes to:", routesPath);
|
|
273
|
+
if (!existsSync(routesPath)) {
|
|
274
|
+
mkdirSync(routesPath, { recursive: true });
|
|
275
|
+
}
|
|
276
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
277
|
+
}
|
|
111
278
|
}
|
|
112
|
-
const feature_file_path = await this.writeTempFeatureFile({ step, parametersMap, tempFolderPath });
|
|
279
|
+
const feature_file_path = await this.writeTempFeatureFile({ step, parametersMap, tempFolderPath, tags });
|
|
113
280
|
// console.log({ feature_file_path, step_text: step.text });
|
|
114
281
|
|
|
115
282
|
const stepExecController = new AbortController();
|
|
116
283
|
this.#currentStepController = stepExecController;
|
|
117
|
-
await withAbort(async () => {
|
|
118
|
-
await
|
|
284
|
+
const { result, info } = await withAbort(async () => {
|
|
285
|
+
return await this.executeStepRemote(
|
|
119
286
|
{
|
|
120
287
|
feature_file_path,
|
|
121
288
|
tempFolderPath,
|
|
122
289
|
stepText: step.text,
|
|
123
290
|
scenario: "Temp Scenario",
|
|
291
|
+
config,
|
|
124
292
|
},
|
|
125
293
|
options
|
|
126
294
|
);
|
|
@@ -130,5 +298,6 @@ export class BVTStepRunner {
|
|
|
130
298
|
fs.rmSync(tempFolderPath, { recursive: true });
|
|
131
299
|
}
|
|
132
300
|
});
|
|
301
|
+
return { result, info };
|
|
133
302
|
}
|
|
134
303
|
}
|
|
@@ -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
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
|
}
|
|
@@ -296,6 +372,12 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
296
372
|
const utilsTemplateFilePath = path.join(__dirname, "../../assets", "templates", "utils_template.txt");
|
|
297
373
|
const utilsContent = readFileSync(utilsTemplateFilePath, "utf8");
|
|
298
374
|
writeFileSync(utilsFilePath, utilsContent, "utf8");
|
|
375
|
+
const hooksTemplateFilePath = path.join(__dirname, "../../assets", "templates", "_hooks_template.txt");
|
|
376
|
+
if (existsSync(hooksTemplateFilePath)) {
|
|
377
|
+
const hooksFilePath = path.join(stepDefinitionFolderPath, "_hooks.mjs");
|
|
378
|
+
const hooksContent = readFileSync(hooksTemplateFilePath, "utf8");
|
|
379
|
+
writeFileSync(hooksFilePath, hooksContent, "utf8");
|
|
380
|
+
}
|
|
299
381
|
const steps = scenario.steps;
|
|
300
382
|
|
|
301
383
|
const stepsDefinitions = new StepsDefinitions(projectDir);
|
|
@@ -311,6 +393,34 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
311
393
|
}
|
|
312
394
|
}
|
|
313
395
|
if ((step.isImplemented && !step.shouldOverride) || step.commands.length === 0) {
|
|
396
|
+
let routesPath = path.join(tmpdir(), `blinq_temp_routes`);
|
|
397
|
+
if (process.env.TEMP_RUN === "true") {
|
|
398
|
+
console.log("Save routes in temp folder for running:", routesPath);
|
|
399
|
+
if (existsSync(routesPath)) {
|
|
400
|
+
console.log("Removing existing temp_routes_folder:", routesPath);
|
|
401
|
+
rmSync(routesPath, { recursive: true });
|
|
402
|
+
}
|
|
403
|
+
mkdirSync(routesPath, { recursive: true });
|
|
404
|
+
console.log("Created temp_routes_folder:", routesPath);
|
|
405
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
406
|
+
} else {
|
|
407
|
+
console.log("Saving routes in project directory:", projectDir);
|
|
408
|
+
if (existsSync(routesPath)) {
|
|
409
|
+
// remove the folder
|
|
410
|
+
try {
|
|
411
|
+
rmSync(routesPath, { recursive: true });
|
|
412
|
+
console.log("Removed temp_routes_folder:", routesPath);
|
|
413
|
+
} catch (error) {
|
|
414
|
+
console.error("Error removing temp_routes folder", error);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
routesPath = path.join(projectDir, "data", "routes");
|
|
418
|
+
console.log("Saving routes to:", routesPath);
|
|
419
|
+
if (!existsSync(routesPath)) {
|
|
420
|
+
mkdirSync(routesPath, { recursive: true });
|
|
421
|
+
}
|
|
422
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
423
|
+
}
|
|
314
424
|
continue;
|
|
315
425
|
}
|
|
316
426
|
const cucumberStep = getCucumberStep({ step });
|
|
@@ -318,7 +428,6 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
318
428
|
const stepDefsFilePath = locateDefinitionPath(featureFolder, pageName);
|
|
319
429
|
// path.join(stepDefinitionFolderPath, pageName + "_page.mjs");
|
|
320
430
|
let codePage = getCodePage(stepDefsFilePath);
|
|
321
|
-
|
|
322
431
|
codePage = await saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions });
|
|
323
432
|
if (!codePage) {
|
|
324
433
|
continue;
|
|
@@ -330,3 +439,45 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
330
439
|
}
|
|
331
440
|
writeFileSync(utilsFilePath, utilsContent, "utf8");
|
|
332
441
|
}
|
|
442
|
+
|
|
443
|
+
export function saveRoutes({ step, folderPath }) {
|
|
444
|
+
const routeItems = step.routeItems;
|
|
445
|
+
if (!routeItems || routeItems.length === 0) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const cucumberStep = getCucumberStep({ step });
|
|
449
|
+
const template = cucumberStep.getTemplate();
|
|
450
|
+
const stepNameHash = createHash("sha256").update(template).digest("hex");
|
|
451
|
+
console.log("Saving routes for step:", step.text, "with hash:", stepNameHash);
|
|
452
|
+
|
|
453
|
+
const routeItemsWithFilters = routeItems.map((routeItem) => {
|
|
454
|
+
const oldFilters = routeItem.filters;
|
|
455
|
+
const queryParamsObject = {};
|
|
456
|
+
oldFilters.queryParams.forEach((queryParam) => {
|
|
457
|
+
queryParamsObject[queryParam.key] = queryParam.value;
|
|
458
|
+
});
|
|
459
|
+
const newFilters = { path: oldFilters.path, method: oldFilters.method, queryParams: queryParamsObject };
|
|
460
|
+
return {
|
|
461
|
+
...routeItem,
|
|
462
|
+
filters: newFilters,
|
|
463
|
+
};
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
const routesFilePath = path.join(folderPath, stepNameHash + ".json");
|
|
467
|
+
console.log("Routes file path:", routesFilePath);
|
|
468
|
+
const routesData = {
|
|
469
|
+
template,
|
|
470
|
+
routes: routeItemsWithFilters,
|
|
471
|
+
};
|
|
472
|
+
console.log("Routes data to save:", routesData);
|
|
473
|
+
|
|
474
|
+
if (!existsSync(folderPath)) {
|
|
475
|
+
mkdirSync(folderPath, { recursive: true });
|
|
476
|
+
}
|
|
477
|
+
try {
|
|
478
|
+
writeFileSync(routesFilePath, JSON.stringify(routesData, null, 2), "utf8");
|
|
479
|
+
console.log("Saved routes to", routesFilePath);
|
|
480
|
+
} catch (error) {
|
|
481
|
+
console.error("Failed to save routes to", routesFilePath, "Error:", error);
|
|
482
|
+
}
|
|
483
|
+
}
|