@dev-blinq/cucumber_client 1.0.1265-dev → 1.0.1265-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 +159 -14068
- package/bin/assets/preload/recorderv3.js +3 -1
- package/bin/assets/scripts/dom_parent.js +26 -0
- package/bin/assets/scripts/recorder.js +8 -4
- package/bin/assets/scripts/unique_locators.js +847 -547
- 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 +5 -1
- package/bin/client/code_gen/code_inversion.js +61 -4
- package/bin/client/code_gen/page_reflection.js +838 -899
- package/bin/client/code_gen/playwright_codeget.js +52 -13
- package/bin/client/cucumber/feature.js +89 -27
- package/bin/client/cucumber/project_to_document.js +1 -1
- package/bin/client/cucumber/steps_definitions.js +84 -76
- package/bin/client/cucumber_selector.js +17 -1
- package/bin/client/local_agent.js +5 -4
- package/bin/client/project.js +186 -196
- package/bin/client/recorderv3/bvt_recorder.js +290 -80
- package/bin/client/recorderv3/implemented_steps.js +74 -16
- package/bin/client/recorderv3/index.js +47 -25
- package/bin/client/recorderv3/network.js +299 -0
- package/bin/client/recorderv3/services.js +4 -16
- package/bin/client/recorderv3/step_runner.js +331 -67
- package/bin/client/recorderv3/step_utils.js +153 -5
- package/bin/client/recorderv3/update_feature.js +32 -30
- package/bin/client/recording.js +3 -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/client/utils/socket_logger.js +132 -0
- package/bin/index.js +1 -0
- package/bin/logger.js +3 -2
- package/bin/min/consoleApi.min.cjs +2 -3
- package/bin/min/injectedScript.min.cjs +16 -16
- package/package.json +24 -14
|
@@ -4,6 +4,7 @@ import { StepsDefinitions } from "../cucumber/steps_definitions.js";
|
|
|
4
4
|
import path from "path";
|
|
5
5
|
import { CodePage } from "./page_reflection.js";
|
|
6
6
|
import { convertToIdentifier, escapeNonPrintables } from "./utils.js";
|
|
7
|
+
import socketLogger from "../utils/socket_logger.js";
|
|
7
8
|
const findElementIdentifier = (node, step, userData, elements) => {
|
|
8
9
|
if (node.key) {
|
|
9
10
|
// incase of rerunning implemented steps
|
|
@@ -12,6 +13,13 @@ const findElementIdentifier = (node, step, userData, elements) => {
|
|
|
12
13
|
|
|
13
14
|
let elementIdentifier = null;
|
|
14
15
|
const keys = Object.keys(elements);
|
|
16
|
+
|
|
17
|
+
for (let i = 0; i < keys.length; i++) {
|
|
18
|
+
const element_key = keys[i];
|
|
19
|
+
const element = elements[element_key];
|
|
20
|
+
element["element_key"] = element_key;
|
|
21
|
+
}
|
|
22
|
+
|
|
15
23
|
let name = node.name;
|
|
16
24
|
if (!name && step.dataKey) {
|
|
17
25
|
name = step.dataKey;
|
|
@@ -58,7 +66,8 @@ const _isCodeGenerationStep = (step) => {
|
|
|
58
66
|
step.type === Types.VERIFY_ATTRIBUTE ||
|
|
59
67
|
step.type === Types.VERIFY_PROPERTY ||
|
|
60
68
|
step.type === Types.SET_INPUT_FILES ||
|
|
61
|
-
step.type === Types.VERIFY_PAGE_SNAPSHOT
|
|
69
|
+
step.type === Types.VERIFY_PAGE_SNAPSHOT ||
|
|
70
|
+
step.type === Types.CONDITIONAL_WAIT
|
|
62
71
|
) {
|
|
63
72
|
return true;
|
|
64
73
|
}
|
|
@@ -91,7 +100,7 @@ const splitToLocatorsGroups = (locators) => {
|
|
|
91
100
|
const _generateCodeFromCommand = (step, elements, userData) => {
|
|
92
101
|
let elementsChanged = false;
|
|
93
102
|
|
|
94
|
-
let elementIdentifier =
|
|
103
|
+
let elementIdentifier = step.locators?.element_key;
|
|
95
104
|
let locatorObject = step.locators;
|
|
96
105
|
// handle element
|
|
97
106
|
let element_name = null;
|
|
@@ -129,18 +138,20 @@ const _generateCodeFromCommand = (step, elements, userData) => {
|
|
|
129
138
|
let locatorObjectClone = JSON.parse(JSON.stringify(locatorObject));
|
|
130
139
|
element_name = locatorObjectClone.element_name;
|
|
131
140
|
delete locatorObjectClone.element_name;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
141
|
+
if (!elementIdentifier) {
|
|
142
|
+
keys.forEach((key) => {
|
|
143
|
+
let elementClone = JSON.parse(JSON.stringify(elements[key]));
|
|
144
|
+
delete elementClone.element_name;
|
|
145
|
+
if (JSON.stringify(elementClone) === JSON.stringify(locatorObjectClone)) {
|
|
146
|
+
elementIdentifier = key;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
139
150
|
if (!elementIdentifier) {
|
|
140
151
|
elementIdentifier = findElementIdentifier(node, step, userData, elements);
|
|
141
152
|
}
|
|
142
153
|
const withoutAllStrategyLocators = excludeKey(locatorObject, "allStrategyLocators");
|
|
143
|
-
elements[elementIdentifier] = withoutAllStrategyLocators;
|
|
154
|
+
elements[elementIdentifier] = { ...withoutAllStrategyLocators, element_key: elementIdentifier };
|
|
144
155
|
elementsChanged = true;
|
|
145
156
|
}
|
|
146
157
|
let optionElement = null;
|
|
@@ -641,6 +652,13 @@ const _generateCodeFromCommand = (step, elements, userData) => {
|
|
|
641
652
|
codeLines.push(line);
|
|
642
653
|
break;
|
|
643
654
|
}
|
|
655
|
+
case Types.CONDITIONAL_WAIT: {
|
|
656
|
+
line = `await context.web.conditionalWait(elements["${elementIdentifier}"], `;
|
|
657
|
+
input = "_param_0";
|
|
658
|
+
line += `"${step.parameters[1]}", ${input}, _params, null, this);`;
|
|
659
|
+
codeLines.push(line);
|
|
660
|
+
break;
|
|
661
|
+
}
|
|
644
662
|
case Types.SET_INPUT_FILES: {
|
|
645
663
|
line = `await context.web.setInputFiles(elements["${elementIdentifier}"], `;
|
|
646
664
|
let files = step.parameters[0];
|
|
@@ -666,6 +684,22 @@ const _generateCodeFromCommand = (step, elements, userData) => {
|
|
|
666
684
|
return { codeLines, elements: elementsChanged ? elements : null, elementIdentifier, allStrategyLocators };
|
|
667
685
|
};
|
|
668
686
|
|
|
687
|
+
/**
|
|
688
|
+
* Generates a report command based on the given position.
|
|
689
|
+
* @param {"start"|"end"} position
|
|
690
|
+
*/
|
|
691
|
+
const generateReportCommand = (position, cmdId) => {
|
|
692
|
+
const codeLines = [];
|
|
693
|
+
if (position === "start") {
|
|
694
|
+
const line = `await context.web.addCommandToReport("${cmdId}", "PASSED", '{"status":"start","cmdId":"${cmdId}"}', {type:"cmdReport"},this);`;
|
|
695
|
+
codeLines.push(line);
|
|
696
|
+
} else if (position === "end") {
|
|
697
|
+
const line = `await context.web.addCommandToReport("${cmdId}", "PASSED", '{"status":"end","cmdId":"${cmdId}"}', {type:"cmdReport"},this);`;
|
|
698
|
+
codeLines.push(line);
|
|
699
|
+
}
|
|
700
|
+
return codeLines;
|
|
701
|
+
};
|
|
702
|
+
|
|
669
703
|
const generateCode = (recording, codePage, userData, projectDir, methodName) => {
|
|
670
704
|
const stepsDefinitions = new StepsDefinitions(projectDir);
|
|
671
705
|
stepsDefinitions.load(false);
|
|
@@ -692,6 +726,7 @@ const generateCode = (recording, codePage, userData, projectDir, methodName) =>
|
|
|
692
726
|
}
|
|
693
727
|
let elements = {};
|
|
694
728
|
if (!codePage) {
|
|
729
|
+
socketLogger.info("CodePage is null");
|
|
695
730
|
console.log("codePage is null");
|
|
696
731
|
} else {
|
|
697
732
|
elements = codePage.getVariableDeclarationAsObject("elements");
|
|
@@ -706,12 +741,16 @@ const generateCode = (recording, codePage, userData, projectDir, methodName) =>
|
|
|
706
741
|
if (recordingStep.type === Types.COMPLETE) {
|
|
707
742
|
return;
|
|
708
743
|
}
|
|
709
|
-
|
|
710
|
-
//
|
|
711
|
-
//
|
|
744
|
+
|
|
745
|
+
// if (process.env.TEMP_RUN === "true") {
|
|
746
|
+
// codeLines.push(...generateReportCommand("start", recordingStep.cmdId));
|
|
712
747
|
// }
|
|
713
748
|
const result = _generateCodeFromCommand(recordingStep, elements, userData);
|
|
749
|
+
|
|
714
750
|
codeLines.push(...result.codeLines);
|
|
751
|
+
// if (process.env.TEMP_RUN === "true") {
|
|
752
|
+
// codeLines.push(...generateReportCommand("end", recordingStep.cmdId));
|
|
753
|
+
// }
|
|
715
754
|
if (result.elements) {
|
|
716
755
|
elements = result.elements;
|
|
717
756
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { IdGenerator } from "@cucumber/messages";
|
|
2
|
+
import { AstBuilder, GherkinClassicTokenMatcher, Parser, compile } from "@cucumber/gherkin";
|
|
1
3
|
import { loadConfiguration, loadSupport, runCucumber } from "@dev-blinq/cucumber-js/api";
|
|
2
4
|
import fs from "fs";
|
|
3
|
-
|
|
5
|
+
import os from "os";
|
|
6
|
+
import path from "path";
|
|
4
7
|
import { parseStepTextParameters, toCucumberExpression, unEscapeNonPrintables } from "./utils.js";
|
|
5
|
-
import
|
|
6
|
-
import { IdGenerator } from "@cucumber/messages";
|
|
8
|
+
import stream from "stream";
|
|
7
9
|
import { testStringForRegex } from "../recorderv3/update_feature.js";
|
|
8
|
-
import
|
|
10
|
+
import { generateTestData } from "./feature_data.js";
|
|
11
|
+
import socketLogger from "../utils/socket_logger.js";
|
|
9
12
|
class DataTable {
|
|
10
13
|
constructor(dataTableDocument) {
|
|
11
14
|
if (!dataTableDocument) {
|
|
@@ -372,6 +375,11 @@ class Examples {
|
|
|
372
375
|
return null;
|
|
373
376
|
}
|
|
374
377
|
let value = this.tableBody[0].cells[parameterIndex].value;
|
|
378
|
+
if (!value) {
|
|
379
|
+
console.warn(`Parameter ${parameterName} not found in examples table body, or it is empty`);
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
|
|
375
383
|
return unEscapeNonPrintables(value); // While editing in recorder, we need to remove backslashes
|
|
376
384
|
}
|
|
377
385
|
}
|
|
@@ -449,29 +457,7 @@ class Scenario {
|
|
|
449
457
|
return this.scenarioText;
|
|
450
458
|
}
|
|
451
459
|
}
|
|
452
|
-
const scenarioResolution = async (featureFilePath) => {
|
|
453
|
-
if (!fs.existsSync(featureFilePath)) {
|
|
454
|
-
throw new Error(`Feature file ${featureFilePath} does not exist`);
|
|
455
|
-
}
|
|
456
|
-
const newId = IdGenerator.uuid();
|
|
457
|
-
const builder = new AstBuilder(newId);
|
|
458
|
-
const matcher = new GherkinClassicTokenMatcher();
|
|
459
|
-
|
|
460
|
-
const parser = new Parser(builder, matcher);
|
|
461
|
-
|
|
462
|
-
// normalize the path to start with featuers/ if it's not cut the featureFielPath to only the part after features/
|
|
463
|
-
let uri = featureFilePath.startsWith("features/")
|
|
464
|
-
? featureFilePath
|
|
465
|
-
: "features/" + featureFilePath.split("features/")[1];
|
|
466
|
-
|
|
467
|
-
const featureFileContent = fs.readFileSync(featureFilePath, "utf8");
|
|
468
|
-
const gherkinDocument = parser.parse(featureFileContent, newId);
|
|
469
460
|
|
|
470
|
-
const feature = new Feature(gherkinDocument, featureFileContent);
|
|
471
|
-
//const scenario = feature.getScenario(scenarioName);
|
|
472
|
-
//return scenario;
|
|
473
|
-
return feature;
|
|
474
|
-
};
|
|
475
461
|
const getDocumentAndPickel = (featureName, featureContent, scenarioName) => {
|
|
476
462
|
const newId = IdGenerator.uuid();
|
|
477
463
|
const builder = new AstBuilder(newId);
|
|
@@ -484,12 +470,88 @@ const getDocumentAndPickel = (featureName, featureContent, scenarioName) => {
|
|
|
484
470
|
|
|
485
471
|
const gherkinDocument = parser.parse(featureContent, newId);
|
|
486
472
|
const pickles = compile(gherkinDocument, uri, newId);
|
|
487
|
-
|
|
488
473
|
// Step 3: Find the specific scenario Pickle
|
|
489
474
|
const pickle = pickles.find((pickle) => {
|
|
490
475
|
return pickle.name === scenarioName;
|
|
491
476
|
});
|
|
492
477
|
return { gherkinDocument, pickle };
|
|
493
478
|
};
|
|
479
|
+
const scenarioResolution = async (featureFilePath) => {
|
|
480
|
+
if (!fs.existsSync(featureFilePath)) {
|
|
481
|
+
throw new Error(`Feature file ${featureFilePath} does not exist`);
|
|
482
|
+
}
|
|
483
|
+
const featureFileContent = fs.readFileSync(featureFilePath, "utf8");
|
|
484
|
+
let tmpDir = null;
|
|
485
|
+
try {
|
|
486
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "ai-qa"));
|
|
487
|
+
const tmpFeaturePath = path.join(tmpDir, "features");
|
|
488
|
+
fs.mkdirSync(tmpFeaturePath);
|
|
489
|
+
const tmpFeatureFilePath = path.join(tmpFeaturePath, path.basename(featureFilePath));
|
|
490
|
+
let result = generateTestData(featureFilePath);
|
|
491
|
+
if (result.changed) {
|
|
492
|
+
fs.writeFileSync(tmpFeatureFilePath, result.newContent);
|
|
493
|
+
console.log("Fake data was generated for this scenario");
|
|
494
|
+
console.log("Variables:");
|
|
495
|
+
for (let key in result.variables) {
|
|
496
|
+
console.log(`${key}: ${result.variables[key].fake}`);
|
|
497
|
+
}
|
|
498
|
+
console.log("Other fake data:");
|
|
499
|
+
for (let i = 0; i < result.otherFakeData.length; i++) {
|
|
500
|
+
console.log(`${result.otherFakeData[i].var}: ${result.otherFakeData[i].fake}`);
|
|
501
|
+
}
|
|
502
|
+
} else {
|
|
503
|
+
fs.copyFileSync(featureFilePath, tmpFeatureFilePath);
|
|
504
|
+
}
|
|
505
|
+
const writable = new stream.Writable({
|
|
506
|
+
write: function (chunk, encoding, next) {
|
|
507
|
+
//console.log(chunk.toString());
|
|
508
|
+
next();
|
|
509
|
+
},
|
|
510
|
+
});
|
|
511
|
+
const environment = { cwd: tmpDir, stdout: writable, stderr: writable };
|
|
512
|
+
// load configuration from a particular file, and override a specific option
|
|
513
|
+
const provided = {
|
|
514
|
+
default: "--publish-quiet",
|
|
515
|
+
require: [tmpDir],
|
|
516
|
+
failFast: false,
|
|
517
|
+
};
|
|
494
518
|
|
|
519
|
+
let gherkinDocument = null;
|
|
520
|
+
const { runConfiguration } = await loadConfiguration({ provided }, environment);
|
|
521
|
+
// load the support code upfront
|
|
522
|
+
const support = await loadSupport(runConfiguration, environment);
|
|
523
|
+
// run cucumber, using the support code we loaded already
|
|
524
|
+
await runCucumber({ ...runConfiguration, support }, environment, function (event) {
|
|
525
|
+
// if (event.source) {
|
|
526
|
+
// scenarioInfo.source = event.source.data;
|
|
527
|
+
// }
|
|
528
|
+
// if (event.pickle && event.pickle.name === scenarioName) {
|
|
529
|
+
// scenarioInfo.pickle = event.pickle;
|
|
530
|
+
// }
|
|
531
|
+
if (event.gherkinDocument) {
|
|
532
|
+
gherkinDocument = event.gherkinDocument;
|
|
533
|
+
}
|
|
534
|
+
//console.log(event);
|
|
535
|
+
//console.log(JSON.stringify(event, null, 2));
|
|
536
|
+
// console.log("");
|
|
537
|
+
});
|
|
538
|
+
const feature = new Feature(gherkinDocument, featureFileContent);
|
|
539
|
+
//const scenario = feature.getScenario(scenarioName);
|
|
540
|
+
//return scenario;
|
|
541
|
+
return feature;
|
|
542
|
+
} finally {
|
|
543
|
+
try {
|
|
544
|
+
if (tmpDir) {
|
|
545
|
+
fs.rmSync(tmpDir, { recursive: true });
|
|
546
|
+
}
|
|
547
|
+
} catch (e) {
|
|
548
|
+
socketLogger.error(
|
|
549
|
+
`An error has occurred while removing the temp folder at ${tmpDir}. Please remove it manually. Error: ${e}`
|
|
550
|
+
);
|
|
551
|
+
console.error(
|
|
552
|
+
`An error has occurred while removing the temp folder at ${tmpDir}. Please remove it manually. Error: ${e}`
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
};
|
|
495
557
|
export { Feature, Scenario, Step, DataTable, Examples, scenarioResolution, getDocumentAndPickel };
|
|
@@ -15,7 +15,7 @@ export const projectDocument = (folder, featureName = null, scenarioName = null,
|
|
|
15
15
|
// read all the feature files in the project folder under features folder
|
|
16
16
|
let featureFiles = [];
|
|
17
17
|
const featuresDir = path.join(folder, "features");
|
|
18
|
-
featureFiles = fs.readdirSync(featuresDir).filter((file) => {
|
|
18
|
+
featureFiles = fs.readdirSync(featuresDir, { recursive: true }).filter((file) => {
|
|
19
19
|
return file.endsWith(".feature");
|
|
20
20
|
});
|
|
21
21
|
const documents = [];
|
|
@@ -523,86 +523,94 @@ class StepsDefinitions {
|
|
|
523
523
|
// }
|
|
524
524
|
// );
|
|
525
525
|
};
|
|
526
|
+
//! Deprecated, not removing until stepRunner.executeStepRemote is stable
|
|
527
|
+
// executeStepRemote = async ({ feature_file_path, scenario, tempFolderPath, stepText, onCommandResult }, options) => {
|
|
528
|
+
// // const { skipAfter = true, skipBefore = true } = options || {};
|
|
529
|
+
// const environment = {
|
|
530
|
+
// ...process.env,
|
|
531
|
+
// };
|
|
526
532
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
533
|
+
// try {
|
|
534
|
+
// const { loadConfiguration, loadSupport, runCucumber } = await import("@dev-blinq/cucumber-js/api");
|
|
535
|
+
// const { runConfiguration } = await loadConfiguration(
|
|
536
|
+
// {
|
|
537
|
+
// provided: {
|
|
538
|
+
// name: [scenario],
|
|
539
|
+
// paths: [feature_file_path],
|
|
540
|
+
// import: [path.join(tempFolderPath, "step_definitions", "**", "*.mjs")],
|
|
541
|
+
// // format: ["bvt"],
|
|
542
|
+
// },
|
|
543
|
+
// },
|
|
544
|
+
// { cwd: process.cwd(), env: environment }
|
|
545
|
+
// );
|
|
546
|
+
// // const files = glob.sync(path.join(tempFolderPath, "step_definitions", "**", "*.mjs"));
|
|
547
|
+
// // console.log("Files found:", files);
|
|
548
|
+
// const support = await loadSupport(runConfiguration, { cwd: process.cwd(), env: environment });
|
|
549
|
+
// // console.log("found ", support.stepDefinitions.length, "step definitions");
|
|
550
|
+
// // support.stepDefinitions.map((step) => {
|
|
551
|
+
// // console.log("step", step.pattern);
|
|
552
|
+
// // });
|
|
536
553
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
);
|
|
550
|
-
// const files = glob.sync(path.join(tempFolderPath, "step_definitions", "**", "*.mjs"));
|
|
551
|
-
// console.log("Files found:", files);
|
|
552
|
-
const support = await loadSupport(runConfiguration, { cwd: process.cwd(), env: environment });
|
|
553
|
-
// console.log("found ", support.stepDefinitions.length, "step definitions");
|
|
554
|
-
// support.stepDefinitions.map((step) => {
|
|
555
|
-
// console.log("step", step.pattern);
|
|
556
|
-
// });
|
|
554
|
+
// if (skipAfter) {
|
|
555
|
+
// // ignore afterAll/after hooks
|
|
556
|
+
// support.afterTestCaseHookDefinitions = [];
|
|
557
|
+
// support.afterTestRunHookDefinitions = [];
|
|
558
|
+
// }
|
|
559
|
+
// // if (skipBefore) {
|
|
560
|
+
// // // ignore beforeAll/before hooks
|
|
561
|
+
// // support.beforeTestCaseHookDefinitions = support.beforeTestCaseHookDefinitions.filter((hook) => {
|
|
562
|
+
// // return hook.uri.endsWith("utils.mjs")
|
|
563
|
+
// // });
|
|
564
|
+
// // support.beforeTestRunHookDefinitions = [];
|
|
565
|
+
// // }
|
|
557
566
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
567
|
+
// let errorMesssage = null;
|
|
568
|
+
// let info = null;
|
|
569
|
+
// let errInfo = null;
|
|
570
|
+
// const result = await runCucumber({ ...runConfiguration, support }, environment, (message) => {
|
|
571
|
+
// if (message.testStepFinished) {
|
|
572
|
+
// const { testStepFinished } = message;
|
|
573
|
+
// const { testStepResult } = testStepFinished;
|
|
574
|
+
// if (testStepResult.status === "FAILED" || testStepResult.status === "AMBIGUOUS") {
|
|
575
|
+
// if (!errorMesssage) {
|
|
576
|
+
// errorMesssage = testStepResult.message;
|
|
577
|
+
// if (info) {
|
|
578
|
+
// errInfo = info;
|
|
579
|
+
// }
|
|
580
|
+
// }
|
|
581
|
+
// }
|
|
582
|
+
// if (testStepResult.status === "UNDEFINED") {
|
|
583
|
+
// if (!errorMesssage) {
|
|
584
|
+
// errorMesssage = `step ${JSON.stringify(stepText)} is ${testStepResult.status}`;
|
|
585
|
+
// if (info) {
|
|
586
|
+
// errInfo = info;
|
|
587
|
+
// }
|
|
588
|
+
// }
|
|
589
|
+
// }
|
|
590
|
+
// }
|
|
591
|
+
// if (message.attachment) {
|
|
592
|
+
// const attachment = message.attachment;
|
|
593
|
+
// if (attachment.mediaType === "application/json" && attachment.body) {
|
|
594
|
+
// const body = JSON.parse(attachment.body);
|
|
595
|
+
// info = body.info;
|
|
596
|
+
// }
|
|
597
|
+
// }
|
|
598
|
+
// });
|
|
599
|
+
// if (errorMesssage) {
|
|
600
|
+
// const bvtError = new Error(errorMesssage);
|
|
601
|
+
// Object.assign(bvtError, { info: errInfo });
|
|
602
|
+
// throw bvtError;
|
|
603
|
+
// }
|
|
563
604
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
errorMesssage = testStepResult.message;
|
|
574
|
-
if (info) {
|
|
575
|
-
errInfo = info;
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
if (testStepResult.status === "UNDEFINED") {
|
|
580
|
-
if (!errorMesssage) {
|
|
581
|
-
errorMesssage = `step ${JSON.stringify(stepText)} is ${testStepResult.status}`;
|
|
582
|
-
if (info) {
|
|
583
|
-
errInfo = info;
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
if (message.attachment) {
|
|
589
|
-
const attachment = message.attachment;
|
|
590
|
-
if (attachment.mediaType === "application/json" && attachment.body) {
|
|
591
|
-
const body = JSON.parse(attachment.body);
|
|
592
|
-
info = body.info;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
});
|
|
596
|
-
if (errorMesssage) {
|
|
597
|
-
const bvtError = new Error(errorMesssage);
|
|
598
|
-
Object.assign(bvtError, { info: errInfo });
|
|
599
|
-
throw bvtError;
|
|
600
|
-
}
|
|
601
|
-
} catch (error) {
|
|
602
|
-
console.error("Error running cucumber-js", error);
|
|
603
|
-
throw error;
|
|
604
|
-
}
|
|
605
|
-
};
|
|
605
|
+
// return {
|
|
606
|
+
// result,
|
|
607
|
+
// info,
|
|
608
|
+
// };
|
|
609
|
+
// } catch (error) {
|
|
610
|
+
// console.error("Error running cucumber-js", error);
|
|
611
|
+
// throw error;
|
|
612
|
+
// }
|
|
613
|
+
// };
|
|
606
614
|
}
|
|
607
615
|
function findFilesWithExtension(folderPath, extension, rootFolder = null) {
|
|
608
616
|
let result = [];
|
|
@@ -6,6 +6,7 @@ import crypto from "crypto";
|
|
|
6
6
|
import { findFilesWithExtension } from "./cucumber/steps_definitions.js";
|
|
7
7
|
import fs from "fs";
|
|
8
8
|
//import { spawn } from "child_process";
|
|
9
|
+
const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
|
9
10
|
|
|
10
11
|
if (process.argv.length < 3) {
|
|
11
12
|
console.log("Usage: node cucumber_selector.js <projectsDir> --all");
|
|
@@ -100,8 +101,8 @@ if (process.argv.includes("--scenario-name")) {
|
|
|
100
101
|
}
|
|
101
102
|
const projectName = selectedScenario.featureFile.split(path.sep)[0];
|
|
102
103
|
let deleteMjsFiles = readlineSync.keyInYN("Delete mjs file?");
|
|
104
|
+
let stepsPath = path.join(selectedScenario.projectsDir, projectName, "features", "step_definitions");
|
|
103
105
|
if (deleteMjsFiles) {
|
|
104
|
-
let stepsPath = path.join(selectedScenario.projectsDir, projectName, "features", "step_definitions");
|
|
105
106
|
if (fs.existsSync(stepsPath)) {
|
|
106
107
|
// delete all the *.mjs files
|
|
107
108
|
let files = fs.readdirSync(stepsPath);
|
|
@@ -112,6 +113,21 @@ if (deleteMjsFiles) {
|
|
|
112
113
|
}
|
|
113
114
|
}
|
|
114
115
|
}
|
|
116
|
+
// copy utils file to the steps directory
|
|
117
|
+
const utilsPath = path.join(__dirname, "../assets/templates/utils_template.txt");
|
|
118
|
+
const utilsContent = fs.readFileSync(utilsPath, "utf8");
|
|
119
|
+
const utilsFileName = stepsPath + "/utils.mjs";
|
|
120
|
+
// if stepsPath directory doesn't exist create it
|
|
121
|
+
if (!fs.existsSync(stepsPath)) {
|
|
122
|
+
fs.mkdirSync(stepsPath, { recursive: true });
|
|
123
|
+
}
|
|
124
|
+
fs.writeFileSync(utilsFileName, utilsContent, "utf8");
|
|
125
|
+
// copy hooks file to the steps directory
|
|
126
|
+
const hooksTemplateFilePath = path.join(__dirname, "../assets/templates/_hooks_template.txt");
|
|
127
|
+
const hooksContent = fs.readFileSync(hooksTemplateFilePath, "utf8");
|
|
128
|
+
const hooksFilePath = path.join(stepsPath, "_hooks.mjs");
|
|
129
|
+
fs.writeFileSync(hooksFilePath, hooksContent, "utf8");
|
|
130
|
+
|
|
115
131
|
process.env.PROJECT_PATH = path.join(selectedScenario.projectsDir, projectName);
|
|
116
132
|
//chanks[currentChank][index];
|
|
117
133
|
console.log("Running scenario:");
|
|
@@ -267,7 +267,7 @@ class LocalAgent {
|
|
|
267
267
|
null,
|
|
268
268
|
true,
|
|
269
269
|
null,
|
|
270
|
-
|
|
270
|
+
-1,
|
|
271
271
|
null,
|
|
272
272
|
initScript
|
|
273
273
|
);
|
|
@@ -696,6 +696,7 @@ class LocalAgent {
|
|
|
696
696
|
stepDiff: stepResult,
|
|
697
697
|
});
|
|
698
698
|
page.removeUnusedElements();
|
|
699
|
+
page.mergeSimilarElements();
|
|
699
700
|
agent.scenarioReport.updateLastStep({
|
|
700
701
|
code: {
|
|
701
702
|
cleanFileNames: page.cleanFileNames,
|
|
@@ -971,7 +972,7 @@ class LocalAgent {
|
|
|
971
972
|
async createNewStepLocal(
|
|
972
973
|
featureName,
|
|
973
974
|
cucumberStep,
|
|
974
|
-
|
|
975
|
+
comments,
|
|
975
976
|
userData,
|
|
976
977
|
firstStep,
|
|
977
978
|
previousTasks,
|
|
@@ -1087,7 +1088,7 @@ class LocalAgent {
|
|
|
1087
1088
|
previousTasks,
|
|
1088
1089
|
scenarioDocument,
|
|
1089
1090
|
scenarioStepIndex,
|
|
1090
|
-
comments
|
|
1091
|
+
comments,
|
|
1091
1092
|
featureFileText,
|
|
1092
1093
|
recover,
|
|
1093
1094
|
dumpConfig: this.dumpConfig,
|
|
@@ -1099,7 +1100,7 @@ class LocalAgent {
|
|
|
1099
1100
|
if (this.context && this.context.web) {
|
|
1100
1101
|
await this.context.web.afterStep(
|
|
1101
1102
|
{
|
|
1102
|
-
attach: (data, mimeType) => {},
|
|
1103
|
+
attach: (data, mimeType) => { },
|
|
1103
1104
|
},
|
|
1104
1105
|
this.cucumberStep
|
|
1105
1106
|
);
|