@dev-blinq/cucumber_client 1.0.1237-dev → 1.0.1237-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 +5 -3
- package/bin/assets/preload/unique_locators.js +1 -1
- 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 +852 -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 +44 -71
- package/bin/client/apiTest/apiTest.js +6 -0
- package/bin/client/cli_helpers.js +11 -13
- package/bin/client/code_cleanup/utils.js +36 -13
- package/bin/client/code_gen/code_inversion.js +68 -10
- package/bin/client/code_gen/page_reflection.js +12 -15
- package/bin/client/code_gen/playwright_codeget.js +127 -34
- package/bin/client/cucumber/feature.js +85 -27
- package/bin/client/cucumber/steps_definitions.js +84 -76
- package/bin/client/cucumber_selector.js +13 -1
- package/bin/client/local_agent.js +3 -3
- package/bin/client/project.js +7 -1
- package/bin/client/recorderv3/bvt_recorder.js +267 -87
- package/bin/client/recorderv3/implemented_steps.js +74 -12
- package/bin/client/recorderv3/index.js +58 -8
- package/bin/client/recorderv3/network.js +299 -0
- package/bin/client/recorderv3/step_runner.js +319 -67
- package/bin/client/recorderv3/step_utils.js +152 -5
- package/bin/client/recorderv3/update_feature.js +58 -30
- package/bin/client/recording.js +5 -0
- package/bin/client/run_cucumber.js +5 -1
- package/bin/client/scenario_report.js +0 -5
- package/bin/client/test_scenario.js +0 -1
- package/bin/index.js +1 -0
- package/package.json +17 -9
|
@@ -1,4 +1,4 @@
|
|
|
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";
|
|
@@ -9,6 +9,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 {
|
|
@@ -156,17 +216,29 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
156
216
|
if (step.commands && step.commands.length > 0 && step.commands[0]) {
|
|
157
217
|
path = step.commands[0].lastKnownUrlPath;
|
|
158
218
|
}
|
|
219
|
+
let protect = false;
|
|
220
|
+
if (step.commands && step.commands.length > 0 && step.commands[0].type) {
|
|
221
|
+
if (step.commands[0].type === "verify_element_property" || step.commands[0].type === "conditional_wait") {
|
|
222
|
+
protect = true;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
159
225
|
const infraResult = codePage.addInfraCommand(
|
|
160
226
|
methodName,
|
|
161
227
|
description,
|
|
162
228
|
cucumberStep.getVariablesList(),
|
|
163
229
|
generateCodeResult.codeLines,
|
|
164
|
-
|
|
230
|
+
protect,
|
|
165
231
|
"recorder",
|
|
166
232
|
path
|
|
167
233
|
);
|
|
168
234
|
const keyword = (cucumberStep.keywordAlias ?? cucumberStep.keyword).trim();
|
|
169
|
-
const stepResult = codePage.addCucumberStep(
|
|
235
|
+
const stepResult = codePage.addCucumberStep(
|
|
236
|
+
keyword,
|
|
237
|
+
cucumberStep.getTemplate(),
|
|
238
|
+
methodName,
|
|
239
|
+
steps.length,
|
|
240
|
+
step.finalTimeout
|
|
241
|
+
);
|
|
170
242
|
|
|
171
243
|
if (!step.isImplemented) {
|
|
172
244
|
stepsDefinitions.addStep({
|
|
@@ -306,6 +378,12 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
306
378
|
const utilsTemplateFilePath = path.join(__dirname, "../../assets", "templates", "utils_template.txt");
|
|
307
379
|
const utilsContent = readFileSync(utilsTemplateFilePath, "utf8");
|
|
308
380
|
writeFileSync(utilsFilePath, utilsContent, "utf8");
|
|
381
|
+
const hooksTemplateFilePath = path.join(__dirname, "../../assets", "templates", "_hooks_template.txt");
|
|
382
|
+
if (existsSync(hooksTemplateFilePath)) {
|
|
383
|
+
const hooksFilePath = path.join(stepDefinitionFolderPath, "_hooks.mjs");
|
|
384
|
+
const hooksContent = readFileSync(hooksTemplateFilePath, "utf8");
|
|
385
|
+
writeFileSync(hooksFilePath, hooksContent, "utf8");
|
|
386
|
+
}
|
|
309
387
|
const steps = scenario.steps;
|
|
310
388
|
|
|
311
389
|
const stepsDefinitions = new StepsDefinitions(projectDir);
|
|
@@ -321,6 +399,34 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
321
399
|
}
|
|
322
400
|
}
|
|
323
401
|
if ((step.isImplemented && !step.shouldOverride) || step.commands.length === 0) {
|
|
402
|
+
let routesPath = path.join(tmpdir(), `blinq_temp_routes`);
|
|
403
|
+
if (process.env.TEMP_RUN === "true") {
|
|
404
|
+
console.log("Save routes in temp folder for running:", routesPath);
|
|
405
|
+
if (existsSync(routesPath)) {
|
|
406
|
+
console.log("Removing existing temp_routes_folder:", routesPath);
|
|
407
|
+
rmSync(routesPath, { recursive: true });
|
|
408
|
+
}
|
|
409
|
+
mkdirSync(routesPath, { recursive: true });
|
|
410
|
+
console.log("Created temp_routes_folder:", routesPath);
|
|
411
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
412
|
+
} else {
|
|
413
|
+
console.log("Saving routes in project directory:", projectDir);
|
|
414
|
+
if (existsSync(routesPath)) {
|
|
415
|
+
// remove the folder
|
|
416
|
+
try {
|
|
417
|
+
rmSync(routesPath, { recursive: true });
|
|
418
|
+
console.log("Removed temp_routes_folder:", routesPath);
|
|
419
|
+
} catch (error) {
|
|
420
|
+
console.error("Error removing temp_routes folder", error);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
routesPath = path.join(projectDir, "data", "routes");
|
|
424
|
+
console.log("Saving routes to:", routesPath);
|
|
425
|
+
if (!existsSync(routesPath)) {
|
|
426
|
+
mkdirSync(routesPath, { recursive: true });
|
|
427
|
+
}
|
|
428
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
429
|
+
}
|
|
324
430
|
continue;
|
|
325
431
|
}
|
|
326
432
|
const cucumberStep = getCucumberStep({ step });
|
|
@@ -328,7 +434,6 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
328
434
|
const stepDefsFilePath = locateDefinitionPath(featureFolder, pageName);
|
|
329
435
|
// path.join(stepDefinitionFolderPath, pageName + "_page.mjs");
|
|
330
436
|
let codePage = getCodePage(stepDefsFilePath);
|
|
331
|
-
|
|
332
437
|
codePage = await saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions });
|
|
333
438
|
if (!codePage) {
|
|
334
439
|
continue;
|
|
@@ -340,3 +445,45 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
340
445
|
}
|
|
341
446
|
writeFileSync(utilsFilePath, utilsContent, "utf8");
|
|
342
447
|
}
|
|
448
|
+
|
|
449
|
+
export function saveRoutes({ step, folderPath }) {
|
|
450
|
+
const routeItems = step.routeItems;
|
|
451
|
+
if (!routeItems || routeItems.length === 0) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
const cucumberStep = getCucumberStep({ step });
|
|
455
|
+
const template = cucumberStep.getTemplate();
|
|
456
|
+
const stepNameHash = createHash("sha256").update(template).digest("hex");
|
|
457
|
+
console.log("Saving routes for step:", step.text, "with hash:", stepNameHash);
|
|
458
|
+
|
|
459
|
+
const routeItemsWithFilters = routeItems.map((routeItem) => {
|
|
460
|
+
const oldFilters = routeItem.filters;
|
|
461
|
+
const queryParamsObject = {};
|
|
462
|
+
oldFilters.queryParams.forEach((queryParam) => {
|
|
463
|
+
queryParamsObject[queryParam.key] = queryParam.value;
|
|
464
|
+
});
|
|
465
|
+
const newFilters = { path: oldFilters.path, method: oldFilters.method, queryParams: queryParamsObject };
|
|
466
|
+
return {
|
|
467
|
+
...routeItem,
|
|
468
|
+
filters: newFilters,
|
|
469
|
+
};
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
const routesFilePath = path.join(folderPath, stepNameHash + ".json");
|
|
473
|
+
console.log("Routes file path:", routesFilePath);
|
|
474
|
+
const routesData = {
|
|
475
|
+
template,
|
|
476
|
+
routes: routeItemsWithFilters,
|
|
477
|
+
};
|
|
478
|
+
console.log("Routes data to save:", routesData);
|
|
479
|
+
|
|
480
|
+
if (!existsSync(folderPath)) {
|
|
481
|
+
mkdirSync(folderPath, { recursive: true });
|
|
482
|
+
}
|
|
483
|
+
try {
|
|
484
|
+
writeFileSync(routesFilePath, JSON.stringify(routesData, null, 2), "utf8");
|
|
485
|
+
console.log("Saved routes to", routesFilePath);
|
|
486
|
+
} catch (error) {
|
|
487
|
+
console.error("Failed to save routes to", routesFilePath, "Error:", error);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
|
|
3
|
+
import { getDefaultPrettierConfig } from "../code_cleanup/utils.js";
|
|
4
|
+
import prettier from "prettier";
|
|
4
5
|
export function containsScenario({ featureFileContent, scenarioName }) {
|
|
5
6
|
const lines = featureFileContent.split("\n");
|
|
6
7
|
for (const line of lines) {
|
|
@@ -63,7 +64,7 @@ const escapeNonPrintables = (text) => {
|
|
|
63
64
|
export function getCommandContent(command) {
|
|
64
65
|
switch (command.type) {
|
|
65
66
|
case "click_element": {
|
|
66
|
-
return
|
|
67
|
+
return `${command.count === 2 ? "Double click" : "Click"} on ${escapeNonPrintables(command.element.name)}`;
|
|
67
68
|
}
|
|
68
69
|
case "fill_element": {
|
|
69
70
|
return `fill ${escapeNonPrintables(command.element.name)} with ${escapeNonPrintables(command.parameters[0])}${command.parameters[1] ? ` and press enter key` : ""}`;
|
|
@@ -81,7 +82,7 @@ export function getCommandContent(command) {
|
|
|
81
82
|
return `verify the element ${escapeNonPrintables(command.element.name)} contains text ${escapeNonPrintables(command.parameters[0])}`;
|
|
82
83
|
}
|
|
83
84
|
case "context_click": {
|
|
84
|
-
return
|
|
85
|
+
return `${command.count === 2 ? "Double click" : "Click"} on ${escapeNonPrintables(command.label)} in the context of ${escapeNonPrintables(command.value)}`;
|
|
85
86
|
}
|
|
86
87
|
case "hover_element": {
|
|
87
88
|
return `hover over ${escapeNonPrintables(command.element.name)}`;
|
|
@@ -98,6 +99,9 @@ export function getCommandContent(command) {
|
|
|
98
99
|
case "verify_page_snapshot": {
|
|
99
100
|
return `verify page snapshot stored in ${command.parameters[0]}`;
|
|
100
101
|
}
|
|
102
|
+
case "parameterized_click": {
|
|
103
|
+
return `${command.count === 2 ? "Parameterized double click" : "Parameterized click"} on ${escapeNonPrintables(command.element.name)}`;
|
|
104
|
+
}
|
|
101
105
|
default: {
|
|
102
106
|
return "";
|
|
103
107
|
}
|
|
@@ -209,14 +213,12 @@ const GherkinToObject = (gherkin) => {
|
|
|
209
213
|
steps: [],
|
|
210
214
|
};
|
|
211
215
|
while (idx < lines.length && lines[idx].startsWith("@")) {
|
|
212
|
-
skipEmptyLines();
|
|
213
216
|
const tags = [...lines[idx].matchAll(/@([^@]+)/g)].map((match) => match[1].trim());
|
|
214
217
|
scenario.tags.push(...(tags ?? []));
|
|
215
218
|
idx++;
|
|
219
|
+
skipEmptyLines();
|
|
216
220
|
}
|
|
217
221
|
|
|
218
|
-
skipEmptyLines();
|
|
219
|
-
|
|
220
222
|
if (idx < lines.length && (lines[idx].startsWith("Scenario:") || lines[idx].startsWith("Scenario Outline:"))) {
|
|
221
223
|
scenario.name = lines[idx].substring(lines[idx].indexOf(":") + 1).trim();
|
|
222
224
|
idx++;
|
|
@@ -239,32 +241,32 @@ const GherkinToObject = (gherkin) => {
|
|
|
239
241
|
!lines[idx].startsWith("@")
|
|
240
242
|
) {
|
|
241
243
|
const line = lines[idx++];
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
type: "comment",
|
|
247
|
-
text: comment,
|
|
248
|
-
};
|
|
249
|
-
scenario.steps.push(command);
|
|
250
|
-
}
|
|
251
|
-
} else if (line.startsWith("Examples:")) {
|
|
252
|
-
obj.hasParams = true;
|
|
253
|
-
const command = {
|
|
244
|
+
let command;
|
|
245
|
+
if (line.startsWith("Examples:")) {
|
|
246
|
+
scenario.hasParams = true;
|
|
247
|
+
command = {
|
|
254
248
|
type: "examples",
|
|
255
249
|
lines: [],
|
|
256
250
|
};
|
|
257
|
-
|
|
258
251
|
while (idx < lines.length && lines[idx].startsWith("|")) {
|
|
259
252
|
const line = lines[idx++];
|
|
260
253
|
command.lines.push(line);
|
|
261
254
|
}
|
|
262
255
|
} else {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
256
|
+
if (line.startsWith("#")) {
|
|
257
|
+
command = {
|
|
258
|
+
type: "comment",
|
|
259
|
+
text: line,
|
|
260
|
+
};
|
|
261
|
+
} else {
|
|
262
|
+
command = {
|
|
263
|
+
type: "step",
|
|
264
|
+
text: line,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
267
|
}
|
|
268
|
+
scenario.steps.push(command);
|
|
269
|
+
skipEmptyLines();
|
|
268
270
|
}
|
|
269
271
|
|
|
270
272
|
return scenario;
|
|
@@ -273,7 +275,6 @@ const GherkinToObject = (gherkin) => {
|
|
|
273
275
|
while (idx < lines.length) {
|
|
274
276
|
const scenario = getScenario();
|
|
275
277
|
if (scenario === -1) break;
|
|
276
|
-
|
|
277
278
|
if (scenario.error) {
|
|
278
279
|
return {
|
|
279
280
|
error: scenario.error,
|
|
@@ -299,8 +300,7 @@ function updateExistingScenario({ featureFileContent, scenarioName, scenarioCont
|
|
|
299
300
|
skipScenarioIndex = i;
|
|
300
301
|
continue;
|
|
301
302
|
}
|
|
302
|
-
let scenarioContent = `${
|
|
303
|
-
|
|
303
|
+
let scenarioContent = `${scenario.hasParams ? "Scenario Outline" : "Scenario"}: ${scenario.name}`;
|
|
304
304
|
let tagsLine;
|
|
305
305
|
if (scenario.tags?.length > 0) {
|
|
306
306
|
tagsLine = `${scenario.tags.map((t) => `@${t}`).join(" ")}`;
|
|
@@ -323,7 +323,6 @@ function updateExistingScenario({ featureFileContent, scenarioName, scenarioCont
|
|
|
323
323
|
if (skipScenarioIndex !== -1) {
|
|
324
324
|
finalContent = results.join("\n") + "\n" + scenarioContent;
|
|
325
325
|
}
|
|
326
|
-
|
|
327
326
|
return finalContent;
|
|
328
327
|
}
|
|
329
328
|
export async function updateFeatureFile({ featureName, scenario, override, projectDir }) {
|
|
@@ -333,6 +332,8 @@ export async function updateFeatureFile({ featureName, scenario, override, proje
|
|
|
333
332
|
{ scenario },
|
|
334
333
|
isFeatureFileExists ? GherkinToObject(readFileSync(featureFilePath, "utf8")) : undefined
|
|
335
334
|
);
|
|
335
|
+
const prettierConfig = getDefaultPrettierConfig();
|
|
336
|
+
// Format the code using Prettier
|
|
336
337
|
|
|
337
338
|
if (isFeatureFileExists) {
|
|
338
339
|
const featureFileContent = readFileSync(featureFilePath, "utf8");
|
|
@@ -341,7 +342,7 @@ export async function updateFeatureFile({ featureName, scenario, override, proje
|
|
|
341
342
|
if (!override) {
|
|
342
343
|
throw new Error(`Scenario "${scenario.name}" already exists in feature "${featureName}"`);
|
|
343
344
|
} else {
|
|
344
|
-
|
|
345
|
+
let updatedFeatureFileContent = updateExistingScenario({
|
|
345
346
|
featureFileContent,
|
|
346
347
|
scenarioName: scenario.name,
|
|
347
348
|
scenarioContent,
|
|
@@ -349,14 +350,41 @@ export async function updateFeatureFile({ featureName, scenario, override, proje
|
|
|
349
350
|
if (updatedFeatureFileContent === "error") {
|
|
350
351
|
throw new Error(`Error while parsing feature file: Invalid gherkin`);
|
|
351
352
|
}
|
|
353
|
+
try {
|
|
354
|
+
updatedFeatureFileContent = await prettier.format(updatedFeatureFileContent, {
|
|
355
|
+
...prettierConfig,
|
|
356
|
+
parser: "gherkin",
|
|
357
|
+
plugins: ["prettier-plugin-gherkin"],
|
|
358
|
+
});
|
|
359
|
+
} catch (error) {
|
|
360
|
+
console.error("Error formatting feature file content with Prettier:", error);
|
|
361
|
+
}
|
|
352
362
|
writeFileSync(featureFilePath, updatedFeatureFileContent);
|
|
353
363
|
return;
|
|
354
364
|
}
|
|
355
365
|
}
|
|
356
|
-
|
|
366
|
+
let updatedFeatureFileContent = featureFileContent + "\n" + scenarioContent;
|
|
367
|
+
try {
|
|
368
|
+
updatedFeatureFileContent = await prettier.format(updatedFeatureFileContent, {
|
|
369
|
+
...prettierConfig,
|
|
370
|
+
parser: "gherkin",
|
|
371
|
+
plugins: ["prettier-plugin-gherkin"],
|
|
372
|
+
});
|
|
373
|
+
} catch (error) {
|
|
374
|
+
console.error("Error formatting feature file content with Prettier:", error);
|
|
375
|
+
}
|
|
357
376
|
writeFileSync(featureFilePath, updatedFeatureFileContent);
|
|
358
377
|
} else {
|
|
359
|
-
|
|
378
|
+
let featureFileContent = `Feature: ${featureName}\n${scenarioContent}`;
|
|
379
|
+
try {
|
|
380
|
+
featureFileContent = await prettier.format(featureFileContent, {
|
|
381
|
+
...prettierConfig,
|
|
382
|
+
parser: "gherkin",
|
|
383
|
+
plugins: ["prettier-plugin-gherkin"],
|
|
384
|
+
});
|
|
385
|
+
} catch (error) {
|
|
386
|
+
console.error("Error formatting feature file content with Prettier:", error);
|
|
387
|
+
}
|
|
360
388
|
writeFileSync(featureFilePath, featureFileContent);
|
|
361
389
|
}
|
|
362
390
|
}
|
package/bin/client/recording.js
CHANGED
|
@@ -8,7 +8,11 @@ const Types = {
|
|
|
8
8
|
API: "api",
|
|
9
9
|
CLICK: "click_element",
|
|
10
10
|
CLICK_SIMPLE: "click_simple",
|
|
11
|
+
PARAMETERIZED_CLICK: "parameterized_click",
|
|
12
|
+
CONTEXT_CLICK: "context_click",
|
|
11
13
|
NAVIGATE: "navigate",
|
|
14
|
+
GO_BACK: "browser_go_back",
|
|
15
|
+
GO_FORWARD: "browser_go_forward",
|
|
12
16
|
FILL: "fill_element",
|
|
13
17
|
FILL_SIMPLE: "fill_simple",
|
|
14
18
|
EXECUTE: "execute_page_method",
|
|
@@ -48,6 +52,7 @@ const Types = {
|
|
|
48
52
|
VERIFY_FILE_EXISTS: "verify_file_exists",
|
|
49
53
|
SET_INPUT_FILES: "set_input_files",
|
|
50
54
|
VERIFY_PAGE_SNAPSHOT: "verify_page_snapshot",
|
|
55
|
+
CONDITIONAL_WAIT: "conditional_wait",
|
|
51
56
|
};
|
|
52
57
|
class Recording {
|
|
53
58
|
steps = [];
|
|
@@ -131,6 +131,10 @@ const runCucumber = async (
|
|
|
131
131
|
} else if (!process.env.NODE_ENV_BLINQ) {
|
|
132
132
|
serviceUrl = "https://logic.blinq.io";
|
|
133
133
|
logger.info("Running in prod mode");
|
|
134
|
+
} else if (process.env.WHITELABEL === "true") {
|
|
135
|
+
// if it's a whitelabel it will use "api" instead of "logic"
|
|
136
|
+
serviceUrl = process.env.NODE_ENV_BLINQ;
|
|
137
|
+
logger.info("Running in custom mode: " + serviceUrl);
|
|
134
138
|
} else {
|
|
135
139
|
serviceUrl = process.env.NODE_ENV_BLINQ.replace("api", "logic");
|
|
136
140
|
logger.info("Running in custom mode: " + serviceUrl);
|
|
@@ -355,7 +359,7 @@ const runCucumber = async (
|
|
|
355
359
|
await aiAgent.createNewStepLocal(
|
|
356
360
|
featureName,
|
|
357
361
|
cucumberStep,
|
|
358
|
-
feature,
|
|
362
|
+
feature.comments,
|
|
359
363
|
userData,
|
|
360
364
|
first,
|
|
361
365
|
previousTasks,
|
|
@@ -33,17 +33,12 @@ const findNextIdInFolder = (folder) => {
|
|
|
33
33
|
// get temp file path from --temp-file arg
|
|
34
34
|
const getTempFilePath = () => {
|
|
35
35
|
let tempFilePath = null;
|
|
36
|
-
|
|
37
36
|
for (const arg of process.argv) {
|
|
38
37
|
const [key, path] = arg.split("=");
|
|
39
38
|
if (key === "--temp-file" && !!path) {
|
|
40
39
|
tempFilePath = path;
|
|
41
40
|
}
|
|
42
41
|
}
|
|
43
|
-
|
|
44
|
-
if (tempFilePath === null) {
|
|
45
|
-
tempFilePath = process.env.TEMP_FILE_PATH;
|
|
46
|
-
}
|
|
47
42
|
return tempFilePath;
|
|
48
43
|
};
|
|
49
44
|
|
package/bin/index.js
CHANGED
|
@@ -13,4 +13,5 @@ export * from "./client/cucumber/feature_data.js";
|
|
|
13
13
|
export * from "./client/cucumber/steps_definitions.js";
|
|
14
14
|
export * from "./client/profiler.js";
|
|
15
15
|
export * from "./client/code_cleanup/utils.js";
|
|
16
|
+
|
|
16
17
|
export * from "./client/code_cleanup/find_step_definition_references.js";
|
package/package.json
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev-blinq/cucumber_client",
|
|
3
|
-
"version": "1.0.1237-
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "1.0.1237-stage",
|
|
4
|
+
"description": " ",
|
|
5
5
|
"main": "bin/index.js",
|
|
6
6
|
"types": "bin/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"pack": "mkdir build && mkdir build/bin && cp -R ./src/* ./build/bin && cp ./package.json ./build",
|
|
9
|
+
"pack": "npm run bundle && mkdir build && mkdir build/bin && cp -R ./src/* ./build/bin && cp ./package.json ./build",
|
|
10
10
|
"test": "node ./test/test.js",
|
|
11
11
|
"tests_prod": "rm -rf results.json && cross-env NODE_ENV_BLINQ=prod TOKEN=xxx npx mocha --parallel --jobs=10 ./tests",
|
|
12
12
|
"tests": "node ./multi_test_runner.js",
|
|
13
13
|
"lint": "eslint ./src/**/*.js",
|
|
14
14
|
"clean": "rm -rf ./build",
|
|
15
15
|
"build": "npm run clean && npm run pack",
|
|
16
|
+
"build:watch": "npx nodemon --watch src/client --exec 'npm run build'",
|
|
16
17
|
"update_logic": "rm -rf ../logic/node_modules/@dev-blinq && mkdir ../logic/node_modules/@dev-blinq && mkdir ../logic/node_modules/@dev-blinq/cucumber_client && mkdir ../logic/node_modules/@dev-blinq/cucumber_client/bin && mkdir ../logic/node_modules/@dev-blinq/cucumber_client/node_modules && cp -R ./build/* ../logic/node_modules/@dev-blinq/cucumber_client/bin && cp -R ./node_modules/* ../logic/node_modules/@dev-blinq/cucumber_client/node_modules && cp ./package.json ../logic/node_modules/@dev-blinq/cucumber_client/",
|
|
17
18
|
"version-bump": "npm version prepatch --preid=dev",
|
|
18
|
-
"scripts_regression": "cross-env HEADLESS=true npx mocha --bail --parallel --jobs=12 ./scripts_regression/ --timeout 120000",
|
|
19
|
-
"runtime_reg": "cross-env HEADLESS=true npx mocha --bail --parallel --jobs=12 ./runtime_regression/ --timeout 4800000"
|
|
19
|
+
"scripts_regression": "npm run bundle && cross-env HEADLESS=true npx mocha --bail --parallel --jobs=12 ./scripts_regression/ --timeout 120000",
|
|
20
|
+
"runtime_reg": "npm run bundle && cross-env HEADLESS=true npx mocha --bail --parallel --jobs=12 ./runtime_regression/ --timeout 4800000",
|
|
21
|
+
"runtime_reg_dev": "npm run bundle && cross-env NODE_ENV_BLINQ=dev TOKEN=bbf2cb6bc1ba4ab625b077b2334b1c2c PROJECT_KEY=680dc09551bc3968d60f8c6d HEADLESS=true mocha --bail --parallel --jobs=12 ./runtime_regression/ --timeout 4800000",
|
|
22
|
+
"runtime_reg_stage": "npm run bundle && cross-env NODE_ENV_BLINQ=stage TOKEN=4b2eda1a52c30a8a1b56c46a5e6e6b46 PROJECT_ID=6821962e5293339975f57600 PROJECT_KEY=680dc09551bc3968d60f8c6d HEADLESS=true mocha --bail --parallel --jobs=12 ./runtime_regression/ --timeout 4800000",
|
|
23
|
+
"bundle": "npx tsup",
|
|
24
|
+
"bundle:watch": "npx tsup --watch",
|
|
25
|
+
"regenerate_baselines": "rm -rf ./scripts_regression/locators_baseline/* ./scripts_regression/commands_baseline/* && npm run scripts_regression && npm run scripts_regression"
|
|
20
26
|
},
|
|
21
27
|
"author": "",
|
|
22
28
|
"license": "ISC",
|
|
@@ -26,9 +32,9 @@
|
|
|
26
32
|
"@babel/traverse": "^7.27.1",
|
|
27
33
|
"@babel/types": "^7.27.1",
|
|
28
34
|
"@cucumber/tag-expressions": "^6.1.1",
|
|
29
|
-
"@dev-blinq/cucumber-js": "1.0.
|
|
35
|
+
"@dev-blinq/cucumber-js": "1.0.96-stage",
|
|
30
36
|
"@faker-js/faker": "^8.1.0",
|
|
31
|
-
"automation_model": "1.0.
|
|
37
|
+
"automation_model": "1.0.723-stage",
|
|
32
38
|
"axios": "^1.7.4",
|
|
33
39
|
"chokidar": "^3.6.0",
|
|
34
40
|
"create-require": "^1.1.1",
|
|
@@ -40,9 +46,9 @@
|
|
|
40
46
|
"node-source-walk": "^6.0.2",
|
|
41
47
|
"object-path": "^0.11.8",
|
|
42
48
|
"open": "^10.1.0",
|
|
43
|
-
"patch-package": "^8.0.0",
|
|
44
49
|
"playwright-core": "1.52.0",
|
|
45
50
|
"prettier": "^3.2.5",
|
|
51
|
+
"prettier-plugin-gherkin": "^3.1.2",
|
|
46
52
|
"pureimage": "0.4.9",
|
|
47
53
|
"socket.io": "^4.7.5",
|
|
48
54
|
"socket.io-client": "^4.7.5",
|
|
@@ -59,6 +65,8 @@
|
|
|
59
65
|
"eslint": "^8.50.0",
|
|
60
66
|
"http-server": "^14.1.1",
|
|
61
67
|
"mocha": "^10.2.0",
|
|
62
|
-
"readline-sync": "^1.4.10"
|
|
68
|
+
"readline-sync": "^1.4.10",
|
|
69
|
+
"tsup": "^8.5.0",
|
|
70
|
+
"typescript": "^5.8.3"
|
|
63
71
|
}
|
|
64
72
|
}
|