@dev-blinq/cucumber_client 1.0.1224-dev → 1.0.1226-dev
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/client/code_cleanup/utils.js +6 -1
- package/bin/client/code_gen/index.js +3 -0
- package/bin/client/code_gen/page_reflection.js +25 -5
- package/bin/client/code_gen/playwright_codeget.js +8 -1
- package/bin/client/local_agent.js +4 -0
- package/bin/client/recorderv3/step_utils.js +12 -2
- package/bin/client/run_cucumber.js +10 -1
- package/package.json +2 -2
|
@@ -10,6 +10,7 @@ import * as t from "@babel/types";
|
|
|
10
10
|
|
|
11
11
|
import { CucumberExpression, ParameterTypeRegistry } from "@cucumber/cucumber-expressions";
|
|
12
12
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
13
|
+
import { getAiConfig } from "../code_gen/page_reflection";
|
|
13
14
|
const STEP_KEYWORDS = new Set(["Given", "When", "Then"]);
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -293,7 +294,11 @@ export function removeUnusedElementsKeys(ast, supportFilePath) {
|
|
|
293
294
|
* @param {Array<{keyword: string, pattern: string}>} stepDefinitions
|
|
294
295
|
*/
|
|
295
296
|
export async function removeUnusedStepDefinitions(filePath, stepDefinitions) {
|
|
296
|
-
|
|
297
|
+
let supportFilePath = filePath.replace(".mjs", ".json");
|
|
298
|
+
const config = getAiConfig();
|
|
299
|
+
if (config && config.locatorsMetadataDir) {
|
|
300
|
+
supportFilePath = path.join(config.locatorsMetadataDir, path.basename(supportFilePath));
|
|
301
|
+
}
|
|
297
302
|
const ast = await parse(filePath);
|
|
298
303
|
removeStepDefinitions(stepDefinitions, ast);
|
|
299
304
|
removeUnusedDeclarations(ast);
|
|
@@ -58,6 +58,9 @@ for (let i = 0; i < scenarioReport.stepsProgress.length; i++) {
|
|
|
58
58
|
page.addCucumberStep(keyword, step.cucumberLine, methodName, step.recording.steps.length);
|
|
59
59
|
|
|
60
60
|
page.removeUnusedElements();
|
|
61
|
+
if (generateCodeResult.locatorsMetadata) {
|
|
62
|
+
page.addLocatorsMetadata(generateCodeResult.locatorsMetadata);
|
|
63
|
+
}
|
|
61
64
|
await page.save();
|
|
62
65
|
set.add(page.sourceFileName);
|
|
63
66
|
}
|
|
@@ -22,6 +22,18 @@ function unescapeFromComment(text) {
|
|
|
22
22
|
.replace(/\*\\/g, "*/") // Unescape comment-closing sequence
|
|
23
23
|
.replace(/\\\\/g, "\\"); // Unescape backslashes
|
|
24
24
|
}
|
|
25
|
+
let ai_config = null;
|
|
26
|
+
export function getAiConfig() {
|
|
27
|
+
if (ai_config) {
|
|
28
|
+
return ai_config;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
ai_config = JSON.parse(readFileSync("ai_config.json", "utf8"));
|
|
32
|
+
} catch (e) {
|
|
33
|
+
ai_config = {};
|
|
34
|
+
}
|
|
35
|
+
return ai_config;
|
|
36
|
+
}
|
|
25
37
|
class CodePage {
|
|
26
38
|
constructor(sourceFileName = null) {
|
|
27
39
|
this.sourceFileName = sourceFileName;
|
|
@@ -224,13 +236,12 @@ this.imports[2].node.source.value
|
|
|
224
236
|
params = paramsObj.map((param) => param.name);
|
|
225
237
|
}
|
|
226
238
|
firstFind = false;
|
|
227
|
-
}
|
|
239
|
+
}
|
|
228
240
|
stepPaths.push(method.path);
|
|
229
|
-
|
|
230
241
|
}
|
|
231
242
|
}
|
|
232
243
|
if (foundMethod) {
|
|
233
|
-
templates.push({ pattern, methodName, params, stepType, paths: stepPaths});
|
|
244
|
+
templates.push({ pattern, methodName, params, stepType, paths: stepPaths });
|
|
234
245
|
}
|
|
235
246
|
}
|
|
236
247
|
}
|
|
@@ -481,7 +492,16 @@ this.imports[2].node.source.value
|
|
|
481
492
|
}
|
|
482
493
|
addLocatorsMetadata(locatorsMetadata) {
|
|
483
494
|
// create a file name based on the source file name replace .mjs with .json
|
|
484
|
-
|
|
495
|
+
let locatorsMetadataFileName = this.sourceFileName.replace(".mjs", ".json");
|
|
496
|
+
const config = getAiConfig();
|
|
497
|
+
if (config && config.locatorsMetadataDir) {
|
|
498
|
+
// if config.locatorsMetadataDir is set, use it to create the file path
|
|
499
|
+
locatorsMetadataFileName = path.join(config.locatorsMetadataDir, path.basename(locatorsMetadataFileName));
|
|
500
|
+
// check if the directory exists, if not create it
|
|
501
|
+
if (!existsSync(path.dirname(locatorsMetadataFileName))) {
|
|
502
|
+
mkdirSync(path.dirname(locatorsMetadataFileName), { recursive: true });
|
|
503
|
+
}
|
|
504
|
+
}
|
|
485
505
|
let metadata = {};
|
|
486
506
|
// try to read the file to metadata, protect with try catch
|
|
487
507
|
try {
|
|
@@ -782,7 +802,7 @@ function getPath(comment) {
|
|
|
782
802
|
if (index === -1) {
|
|
783
803
|
return null;
|
|
784
804
|
}
|
|
785
|
-
return comment.substring(index).split(
|
|
805
|
+
return comment.substring(index).split("\n")[0].substring(6);
|
|
786
806
|
}
|
|
787
807
|
|
|
788
808
|
class CodePart {
|
|
@@ -62,6 +62,12 @@ const _isCodeGenerationStep = (step) => {
|
|
|
62
62
|
}
|
|
63
63
|
return false;
|
|
64
64
|
};
|
|
65
|
+
// Note: this function is used to exclude a key from an object
|
|
66
|
+
// Please move it to utils and use it as a reusable function ...
|
|
67
|
+
function excludeKey(obj, keyToRemove) {
|
|
68
|
+
const { [keyToRemove]: _, ...rest } = obj;
|
|
69
|
+
return rest;
|
|
70
|
+
}
|
|
65
71
|
const splitToLocatorsGroups = (locators) => {
|
|
66
72
|
const no_text = locators.locators.filter((locator) => locator.mode === "NO_TEXT");
|
|
67
73
|
const ignore_digit = locators.locators.filter((locator) => locator.mode === "IGNORE_DIGIT");
|
|
@@ -131,7 +137,8 @@ const _generateCodeFromCommand = (step, elements, userData) => {
|
|
|
131
137
|
if (!elementIdentifier) {
|
|
132
138
|
elementIdentifier = findElementIdentifier(node, step, userData, elements);
|
|
133
139
|
}
|
|
134
|
-
|
|
140
|
+
const withoutAllStrategyLocators = excludeKey(locatorObject, "allStrategyLocators");
|
|
141
|
+
elements[elementIdentifier] = withoutAllStrategyLocators;
|
|
135
142
|
elementsChanged = true;
|
|
136
143
|
}
|
|
137
144
|
let optionElement = null;
|
|
@@ -655,6 +655,7 @@ class LocalAgent {
|
|
|
655
655
|
|
|
656
656
|
let page = agent.project.getPage(agent.pageName, true);
|
|
657
657
|
const generateCodeResult = generateCode(recording, page, userData, agent.project.rootFolder, methodName);
|
|
658
|
+
|
|
658
659
|
if (generateCodeResult.simple === true) {
|
|
659
660
|
agent.sendDone("generateStepCode", null);
|
|
660
661
|
break;
|
|
@@ -707,6 +708,9 @@ class LocalAgent {
|
|
|
707
708
|
cucumberStep: agent.cucumberStep,
|
|
708
709
|
},
|
|
709
710
|
});
|
|
711
|
+
if (generateCodeResult.locatorsMetadata) {
|
|
712
|
+
page.addLocatorsMetadata(generateCodeResult.locatorsMetadata);
|
|
713
|
+
}
|
|
710
714
|
await page.save();
|
|
711
715
|
agent.scenarioReport.updateLastStep({
|
|
712
716
|
recording: command.data.recording,
|
|
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, readFileSync, 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";
|
|
@@ -187,7 +187,17 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
187
187
|
|
|
188
188
|
const getLocatorsJson = (file) => {
|
|
189
189
|
if (!file) return {};
|
|
190
|
-
|
|
190
|
+
let locatorsFilePath = file.replace(".mjs", ".json");
|
|
191
|
+
const originLocatorsFilePath = locatorsFilePath;
|
|
192
|
+
const config = getAiConfig();
|
|
193
|
+
if (config && config.locatorsMetadataDir) {
|
|
194
|
+
// if config.locatorsMetadataDir is set, use it to create the file path
|
|
195
|
+
locatorsFilePath = path.join(config.locatorsMetadataDir, path.basename(locatorsFilePath));
|
|
196
|
+
if (!existsSync(locatorsFilePath)) {
|
|
197
|
+
// if the file does not exist in the config directory, use the original path
|
|
198
|
+
locatorsFilePath = originLocatorsFilePath;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
191
201
|
if (!existsSync(locatorsFilePath)) {
|
|
192
202
|
return {};
|
|
193
203
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
2
2
|
import logger from "../logger.js";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { scenarioResolution } from "./cucumber/feature.js";
|
|
@@ -236,6 +236,15 @@ const runCucumber = async (
|
|
|
236
236
|
|
|
237
237
|
let scenarioId = findNextIdInFolder("./reports");
|
|
238
238
|
let scenarioPath = "./reports" + "/" + scenarioId;
|
|
239
|
+
const dataFilePath = path.join(scenarioPath, "data.json");
|
|
240
|
+
mkdirSync(path.dirname(dataFilePath), { recursive: true });
|
|
241
|
+
if (process.env.NODE_ENV_BLINQ === "local") {
|
|
242
|
+
let dataPath = aiAgent.project.rootFolder + "/data/data.json";
|
|
243
|
+
if (existsSync(dataPath)) {
|
|
244
|
+
const poolData = JSON.parse(readFileSync(dataPath, "utf-8"));
|
|
245
|
+
writeFileSync(dataFilePath, JSON.stringify(poolData, null, 2), "utf-8");
|
|
246
|
+
}
|
|
247
|
+
}
|
|
239
248
|
result.scenarioPath = scenarioPath;
|
|
240
249
|
aiAgent.initTestData(envFile, path.join(scenarioPath, "data.json"));
|
|
241
250
|
let featureFileRelative = path.relative(projectDir, fullFeatureFilePath);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev-blinq/cucumber_client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1226-dev",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "bin/index.js",
|
|
6
6
|
"types": "bin/index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@cucumber/tag-expressions": "^6.1.1",
|
|
29
29
|
"@dev-blinq/cucumber-js": "1.0.172-dev",
|
|
30
30
|
"@faker-js/faker": "^8.1.0",
|
|
31
|
-
"automation_model": "1.0.
|
|
31
|
+
"automation_model": "1.0.737-dev",
|
|
32
32
|
"axios": "^1.7.4",
|
|
33
33
|
"chokidar": "^3.6.0",
|
|
34
34
|
"create-require": "^1.1.1",
|