@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
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
After,
|
|
3
|
+
setDefaultTimeout,
|
|
4
|
+
Before,
|
|
5
|
+
AfterStep,
|
|
6
|
+
BeforeStep,
|
|
7
|
+
} from "@dev-blinq/cucumber-js";
|
|
8
|
+
import { closeContext, initContext, navigate, executeBrunoRequest, verifyFileExists } from "automation_model";
|
|
9
|
+
setDefaultTimeout(60 * 1000);
|
|
10
|
+
|
|
11
|
+
const url = null;
|
|
12
|
+
|
|
13
|
+
const elements = {};
|
|
14
|
+
|
|
15
|
+
let context = null;
|
|
16
|
+
Before(async function (scenario) {
|
|
17
|
+
context = await initContext(url, false, false, this);
|
|
18
|
+
await navigate(url);
|
|
19
|
+
await context.web.beforeScenario(this, scenario);
|
|
20
|
+
});
|
|
21
|
+
After(async function (scenario) {
|
|
22
|
+
await context.web.afterScenario(this, scenario);
|
|
23
|
+
await closeContext();
|
|
24
|
+
context = null;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
BeforeStep(async function (step) {
|
|
28
|
+
if (context) {
|
|
29
|
+
await context.web.beforeStep(this, step);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
AfterStep(async function (step) {
|
|
34
|
+
if (context) {
|
|
35
|
+
await context.web.afterStep(this, step);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
@@ -1,20 +1,6 @@
|
|
|
1
|
-
import { Given, When, Then, After, setDefaultTimeout, Before} from "@dev-blinq/cucumber-js";
|
|
2
|
-
import { closeContext, initContext, navigate } from "automation_model";
|
|
3
|
-
setDefaultTimeout(60 * 1000);
|
|
4
|
-
|
|
5
|
-
const path = null;
|
|
1
|
+
import { Given, When, Then, After, setDefaultTimeout, Before } from "@dev-blinq/cucumber-js";
|
|
2
|
+
import { closeContext, initContext, navigate, TestContext as context } from "automation_model";
|
|
6
3
|
|
|
7
4
|
const elements = {
|
|
8
5
|
};
|
|
9
6
|
|
|
10
|
-
let context = null;
|
|
11
|
-
Before(async function () {
|
|
12
|
-
if (!context) {
|
|
13
|
-
context = await initContext(path, false, false, this);
|
|
14
|
-
}
|
|
15
|
-
await navigate(path);
|
|
16
|
-
});
|
|
17
|
-
After(async function () {
|
|
18
|
-
await closeContext();
|
|
19
|
-
context = null;
|
|
20
|
-
});
|
|
@@ -2,55 +2,10 @@ import {
|
|
|
2
2
|
Given,
|
|
3
3
|
When,
|
|
4
4
|
Then,
|
|
5
|
-
After,
|
|
6
|
-
setDefaultTimeout,
|
|
7
|
-
Before,
|
|
8
5
|
defineStep,
|
|
9
|
-
AfterStep,
|
|
10
|
-
BeforeStep,
|
|
11
6
|
} from "@dev-blinq/cucumber-js";
|
|
12
|
-
import { closeContext, initContext, navigate, executeBrunoRequest, verifyFileExists } from "automation_model";
|
|
7
|
+
import { closeContext, initContext, navigate, executeBrunoRequest, verifyFileExists, TestContext as context } from "automation_model";
|
|
13
8
|
import path from "path";
|
|
14
|
-
setDefaultTimeout(60 * 1000);
|
|
15
|
-
|
|
16
|
-
const url = null;
|
|
17
|
-
|
|
18
|
-
const elements = {};
|
|
19
|
-
|
|
20
|
-
let context = null;
|
|
21
|
-
Before(async function (scenario) {
|
|
22
|
-
if (!context) {
|
|
23
|
-
context = await initContext(url, false, false, this);
|
|
24
|
-
}
|
|
25
|
-
await navigate(url);
|
|
26
|
-
await context.web.beforeScenario(this, scenario);
|
|
27
|
-
});
|
|
28
|
-
After(async function (scenario) {
|
|
29
|
-
await context.web.afterScenario(this, scenario);
|
|
30
|
-
await closeContext();
|
|
31
|
-
context = null;
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
BeforeStep(async function (step) {
|
|
35
|
-
if (context) {
|
|
36
|
-
await context.web.beforeStep(this, step);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
AfterStep(async function (step) {
|
|
41
|
-
if (context) {
|
|
42
|
-
await context.web.afterStep(this, step);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Load test data for a user
|
|
48
|
-
* @param {string} user name of the user to load test data for
|
|
49
|
-
* @protect
|
|
50
|
-
*/
|
|
51
|
-
async function loadUserData(user) {
|
|
52
|
-
await context.web.loadTestDataAsync("users", user, this);
|
|
53
|
-
}
|
|
54
9
|
|
|
55
10
|
/**
|
|
56
11
|
* Verify text exsits in page
|
|
@@ -60,7 +15,6 @@ async function loadUserData(user) {
|
|
|
60
15
|
async function verifyTextExistsInPage(text) {
|
|
61
16
|
await context.web.verifyTextExistInPage(text, null, this);
|
|
62
17
|
}
|
|
63
|
-
|
|
64
18
|
Then("Verify the text {string} can be found in the page", verifyTextExistsInPage);
|
|
65
19
|
|
|
66
20
|
/**
|
|
@@ -87,6 +41,7 @@ async function fillElement(elementDescription, value) {
|
|
|
87
41
|
}
|
|
88
42
|
When("fill {string} with {string}", fillElement);
|
|
89
43
|
When("Fill {string} with {string}", fillElement);
|
|
44
|
+
|
|
90
45
|
/**
|
|
91
46
|
* Verify text does not exist in page
|
|
92
47
|
* @param {string} text the text to verify does not exist in page
|
|
@@ -107,6 +62,24 @@ async function navigateTo(url) {
|
|
|
107
62
|
}
|
|
108
63
|
When("Navigate to {string}", navigateTo);
|
|
109
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Navigate to the current page
|
|
67
|
+
* @protect
|
|
68
|
+
*/
|
|
69
|
+
async function browserNavigateBack() {
|
|
70
|
+
await context.web.goBack({}, this);
|
|
71
|
+
}
|
|
72
|
+
Then("Browser navigate back", browserNavigateBack);
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Navigate forward in browser history
|
|
76
|
+
* @protect
|
|
77
|
+
*/
|
|
78
|
+
async function browserNavigateForward() {
|
|
79
|
+
await context.web.goForward({}, this);
|
|
80
|
+
}
|
|
81
|
+
Then("Browser navigate forward", browserNavigateForward);
|
|
82
|
+
|
|
110
83
|
/**
|
|
111
84
|
* Store browser session "<path>"
|
|
112
85
|
* @param {string} filePath the file path or empty to store in the test data file
|
|
@@ -141,6 +114,7 @@ Then(
|
|
|
141
114
|
"Identify the text {string}, climb {string} levels in the page, validate text {string} can be found in the context",
|
|
142
115
|
verifyTextRelatedToText
|
|
143
116
|
);
|
|
117
|
+
|
|
144
118
|
/**
|
|
145
119
|
* execute bruno single request given the bruno project is placed in a folder called bruno under the root of the cucumber project
|
|
146
120
|
* @requestName the name of the bruno request file
|
|
@@ -149,7 +123,6 @@ Then(
|
|
|
149
123
|
async function runBrunoRequest(requestName) {
|
|
150
124
|
await executeBrunoRequest(requestName, {}, context, this);
|
|
151
125
|
}
|
|
152
|
-
|
|
153
126
|
When("Bruno - {string}", runBrunoRequest);
|
|
154
127
|
When("bruno - {string}", runBrunoRequest);
|
|
155
128
|
|
|
@@ -163,41 +136,41 @@ async function verify_the_downloaded_file_exists(fileName) {
|
|
|
163
136
|
const downloadFile = path.join(downloadFolder, fileName);
|
|
164
137
|
await verifyFileExists(downloadFile, {}, context, this);
|
|
165
138
|
}
|
|
166
|
-
|
|
167
139
|
Then("Verify the file {string} exists", { timeout: 60000 }, verify_the_downloaded_file_exists);
|
|
168
140
|
|
|
169
|
-
When("Noop", async function(){})
|
|
170
|
-
|
|
171
141
|
/**
|
|
172
|
-
*
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
*/
|
|
142
|
+
* Noop step for running only hooks
|
|
143
|
+
*/
|
|
144
|
+
When("Noop", async function () {});
|
|
176
145
|
|
|
177
|
-
|
|
178
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Verify the page url is "<url>"
|
|
148
|
+
* @param {string} url URL to be verified against current URL
|
|
149
|
+
* @protect
|
|
150
|
+
*/
|
|
151
|
+
async function verify_page_url(url) {
|
|
152
|
+
await context.web.verifyPagePath(url, {}, this);
|
|
179
153
|
}
|
|
180
154
|
Then("Verify the page url is {string}", verify_page_url);
|
|
181
155
|
|
|
182
156
|
/**
|
|
183
|
-
* Verify the page title is "<title>"
|
|
184
|
-
* @param {string} title Title to be verified against current Title
|
|
185
|
-
* @protect
|
|
186
|
-
*/
|
|
187
|
-
async function verify_page_title(title){
|
|
157
|
+
* Verify the page title is "<title>"
|
|
158
|
+
* @param {string} title Title to be verified against current Title
|
|
159
|
+
* @protect
|
|
160
|
+
*/
|
|
161
|
+
async function verify_page_title(title) {
|
|
188
162
|
await context.web.verifyPageTitle(title, {}, this);
|
|
189
163
|
}
|
|
190
|
-
Then("Verify the page title is {string}",verify_page_title)
|
|
164
|
+
Then("Verify the page title is {string}", verify_page_title);
|
|
191
165
|
|
|
192
166
|
/**
|
|
193
|
-
* Explicit wait/sleep function that pauses execution for a specified duration
|
|
194
|
-
* @param {duration} - Duration to sleep in milliseconds (default: 1000ms)
|
|
195
|
-
* @param {options} - Optional configuration object
|
|
196
|
-
* @param {world} - Optional world context
|
|
197
|
-
* @returns Promise that resolves after the specified duration
|
|
198
|
-
*/
|
|
167
|
+
* Explicit wait/sleep function that pauses execution for a specified duration
|
|
168
|
+
* @param {duration} - Duration to sleep in milliseconds (default: 1000ms)
|
|
169
|
+
* @param {options} - Optional configuration object
|
|
170
|
+
* @param {world} - Optional world context
|
|
171
|
+
* @returns Promise that resolves after the specified duration
|
|
172
|
+
*/
|
|
199
173
|
async function sleep(duration) {
|
|
200
174
|
await context.web.sleep(duration, {}, null);
|
|
201
175
|
}
|
|
202
|
-
|
|
203
|
-
Then("Sleep for {string} ms", {timeout: -1}, sleep);
|
|
176
|
+
Then("Sleep for {string} ms", { timeout: -1 }, sleep);
|
|
@@ -75,6 +75,12 @@ class ApiTest {
|
|
|
75
75
|
const utilsTemplateFilePath = path.join(__dirname, "../../assets", "templates", "utils_template.txt");
|
|
76
76
|
const utilsContent = readFileSync(utilsTemplateFilePath, "utf8");
|
|
77
77
|
writeFileSync(utilsFilePath, utilsContent, "utf8");
|
|
78
|
+
const hooksTemplateFilePath = path.join(__dirname, "../../assets", "templates", "_hooks_template.txt");
|
|
79
|
+
if (existsSync(hooksTemplateFilePath)) {
|
|
80
|
+
const hooksFilePath = path.join(stepDefinitionFolderPath, "_hooks.mjs");
|
|
81
|
+
const hooksContent = readFileSync(hooksTemplateFilePath, "utf8");
|
|
82
|
+
writeFileSync(hooksFilePath, hooksContent, "utf8");
|
|
83
|
+
}
|
|
78
84
|
} catch (error) {
|
|
79
85
|
console.log("error", error);
|
|
80
86
|
}
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
|
|
2
1
|
const validateCLIArg = (arg, name) => {
|
|
3
2
|
if (!arg) {
|
|
4
|
-
throw new Error(`${name} is required`)
|
|
3
|
+
throw new Error(`${name} is required`);
|
|
5
4
|
}
|
|
6
|
-
}
|
|
5
|
+
};
|
|
7
6
|
const showUsage = (error, usage) => {
|
|
8
|
-
console.error(error.message)
|
|
9
|
-
console.info(usage)
|
|
10
|
-
process.exit(1)
|
|
11
|
-
}
|
|
12
|
-
const loadArgs = ()=>{
|
|
13
|
-
const args = process.argv.slice(2)
|
|
14
|
-
return args
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export { validateCLIArg, loadArgs, showUsage };
|
|
7
|
+
console.error(error.message);
|
|
8
|
+
console.info(usage);
|
|
9
|
+
process.exit(1);
|
|
10
|
+
};
|
|
11
|
+
const loadArgs = () => {
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
return args;
|
|
14
|
+
};
|
|
15
|
+
export { validateCLIArg, loadArgs, showUsage };
|
|
@@ -287,7 +287,39 @@ export function removeUnusedElementsKeys(ast, supportFilePath) {
|
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
289
|
}
|
|
290
|
-
|
|
290
|
+
export function getDefaultPrettierConfig() {
|
|
291
|
+
let prettierConfig = {
|
|
292
|
+
parser: "babel",
|
|
293
|
+
trailingComma: "es5",
|
|
294
|
+
tabWidth: 2,
|
|
295
|
+
semi: true,
|
|
296
|
+
singleQuote: false,
|
|
297
|
+
bracketSpacing: true,
|
|
298
|
+
arrowParens: "always",
|
|
299
|
+
embeddedLanguageFormatting: "auto",
|
|
300
|
+
endOfLine: "lf",
|
|
301
|
+
printWidth: 120,
|
|
302
|
+
};
|
|
303
|
+
// check if .prettierrc file exists
|
|
304
|
+
const prettierConfigPath = ".prettierrc";
|
|
305
|
+
if (existsSync(prettierConfigPath)) {
|
|
306
|
+
try {
|
|
307
|
+
const configContent = readFileSync(prettierConfigPath, "utf-8");
|
|
308
|
+
prettierConfig = JSON.parse(configContent);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
console.error(`Error parsing Prettier config file: ${error}`);
|
|
311
|
+
}
|
|
312
|
+
} else {
|
|
313
|
+
// save the default config to .prettierrc
|
|
314
|
+
try {
|
|
315
|
+
writeFileSync(prettierConfigPath, JSON.stringify(prettierConfig, null, 2), "utf-8");
|
|
316
|
+
console.log(`Created default Prettier config at ${prettierConfigPath}`);
|
|
317
|
+
} catch (error) {
|
|
318
|
+
console.error(`Error writing Prettier config file: ${error}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return prettierConfig;
|
|
322
|
+
}
|
|
291
323
|
/**
|
|
292
324
|
* Remove unused step definitions from a file.
|
|
293
325
|
* @param {string} filePath
|
|
@@ -306,19 +338,10 @@ export async function removeUnusedStepDefinitions(filePath, stepDefinitions) {
|
|
|
306
338
|
// removeUnusedImports(ast);
|
|
307
339
|
let code = generateCode(ast);
|
|
308
340
|
|
|
341
|
+
// configuration object
|
|
342
|
+
const prettierConfig = getDefaultPrettierConfig();
|
|
309
343
|
// Format the code using Prettier
|
|
310
|
-
code = await prettier.format(code,
|
|
311
|
-
parser: "babel",
|
|
312
|
-
trailingComma: "es5",
|
|
313
|
-
tabWidth: 2,
|
|
314
|
-
semi: true,
|
|
315
|
-
singleQuote: false,
|
|
316
|
-
bracketSpacing: true,
|
|
317
|
-
arrowParens: "always",
|
|
318
|
-
embeddedLanguageFormatting: "auto",
|
|
319
|
-
endOfLine: "lf",
|
|
320
|
-
printWidth: 120,
|
|
321
|
-
});
|
|
344
|
+
code = await prettier.format(code, prettierConfig);
|
|
322
345
|
|
|
323
346
|
await fs.writeFile(filePath, code, "utf-8");
|
|
324
347
|
console.log(`Removed unused step definitions from ${filePath}`);
|
|
@@ -109,13 +109,13 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
109
109
|
|
|
110
110
|
case "click":
|
|
111
111
|
// Handle different click scenarios
|
|
112
|
+
step.type = Types.CLICK;
|
|
113
|
+
step.element = extractElement(call.arguments[0]);
|
|
112
114
|
if (call.arguments.length > 2 && call.arguments[2]?.type === "ObjectExpression") {
|
|
113
115
|
// Context click
|
|
114
|
-
step.type = "context_click";
|
|
115
|
-
step.element = extractElement(call.arguments[0]);
|
|
116
|
-
|
|
117
116
|
const contextProp = call.arguments[2].properties.find((prop) => prop.key.name === "context");
|
|
118
117
|
if (contextProp) {
|
|
118
|
+
step.type = "context_click";
|
|
119
119
|
const contextValue = parseDataSource(contextProp.value, stepParams);
|
|
120
120
|
if (contextValue.type === "literal") {
|
|
121
121
|
step.value = contextValue.value;
|
|
@@ -125,9 +125,10 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
125
125
|
step.value = toVariableName(contextValue.dataKey);
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
const clickCountProp = call.arguments[2].properties.find((prop) => prop.key.name === "clickCount");
|
|
129
|
+
if (clickCountProp) {
|
|
130
|
+
step.count = clickCountProp.value.value;
|
|
131
|
+
}
|
|
131
132
|
}
|
|
132
133
|
break;
|
|
133
134
|
|
|
@@ -309,6 +310,14 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
309
310
|
break;
|
|
310
311
|
}
|
|
311
312
|
|
|
313
|
+
case "goBack":
|
|
314
|
+
step.type = Types.GO_BACK;
|
|
315
|
+
break;
|
|
316
|
+
|
|
317
|
+
case "goForward":
|
|
318
|
+
step.type = Types.GO_FORWARD;
|
|
319
|
+
break;
|
|
320
|
+
|
|
312
321
|
case "reloadPage":
|
|
313
322
|
step.type = Types.RELOAD;
|
|
314
323
|
break;
|
|
@@ -365,10 +374,15 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
365
374
|
}
|
|
366
375
|
case "verifyTextRelatedToText": {
|
|
367
376
|
step.type = Types.VERIFY_TEXT_RELATED_TO_TEXT;
|
|
368
|
-
const
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
377
|
+
const textAnchorParse = parseDataSource(call.arguments[0], stepParams);
|
|
378
|
+
const textAnchor =
|
|
379
|
+
textAnchorParse.type === "literal" ? textAnchorParse.value : toVariableName(textAnchorParse.dataKey);
|
|
380
|
+
const climbParse = parseDataSource(call.arguments[1], stepParams);
|
|
381
|
+
const climb = climbParse.type === "literal" ? climbParse.value : toVariableName(climbParse.dataKey);
|
|
382
|
+
const textToVerifyParse = parseDataSource(call.arguments[2], stepParams);
|
|
383
|
+
const textToVerify =
|
|
384
|
+
textToVerifyParse.type === "literal" ? textToVerifyParse.value : toVariableName(textToVerifyParse.dataKey);
|
|
385
|
+
step.parameters = [textAnchor, climb, textToVerify];
|
|
372
386
|
break;
|
|
373
387
|
}
|
|
374
388
|
case "setInputFiles": {
|
|
@@ -417,6 +431,50 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
417
431
|
}
|
|
418
432
|
break;
|
|
419
433
|
}
|
|
434
|
+
case "verifyProperty": {
|
|
435
|
+
step.type = Types.VERIFY_PROPERTY;
|
|
436
|
+
step.element = extractElement(call.arguments[0]);
|
|
437
|
+
const property = call.arguments[1].value;
|
|
438
|
+
const value = parseDataSource(call.arguments[2], stepParams);
|
|
439
|
+
if (value.type === "literal") {
|
|
440
|
+
step.parameters = [property, value.value];
|
|
441
|
+
} else {
|
|
442
|
+
step.dataSource = value.dataSource;
|
|
443
|
+
step.dataKey = value.dataKey;
|
|
444
|
+
step.parameters = [property, toVariableName(value.dataKey)];
|
|
445
|
+
}
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
case "extractProperty": {
|
|
449
|
+
step.type = Types.EXTRACT_PROPERTY;
|
|
450
|
+
step.element = extractElement(call.arguments[0]);
|
|
451
|
+
const attribute = call.arguments[1].value;
|
|
452
|
+
const variable = parseDataSource(call.arguments[2], stepParams);
|
|
453
|
+
if (variable.type === "literal") {
|
|
454
|
+
step.parameters = [attribute, variable.value];
|
|
455
|
+
} else {
|
|
456
|
+
step.dataSource = variable.dataSource;
|
|
457
|
+
step.dataKey = variable.dataKey;
|
|
458
|
+
step.parameters = [attribute, toVariableName(variable.dataKey)];
|
|
459
|
+
}
|
|
460
|
+
if (call.arguments[4].type === "ObjectExpression") {
|
|
461
|
+
const properties = call.arguments[4].properties;
|
|
462
|
+
const regexProp = properties.findIndex((prop) => prop.key.name === "regex");
|
|
463
|
+
if (regexProp !== -1) {
|
|
464
|
+
const regex = properties[regexProp].value.value;
|
|
465
|
+
step.regex = regex;
|
|
466
|
+
}
|
|
467
|
+
const trimSpacesProp = properties.findIndex((prop) => prop.key.name === "trimSpaces");
|
|
468
|
+
if (trimSpacesProp !== -1) {
|
|
469
|
+
const trimSpaces = properties[trimSpacesProp].value.value;
|
|
470
|
+
step.trimSpaces = trimSpaces;
|
|
471
|
+
}
|
|
472
|
+
} else {
|
|
473
|
+
step.regex = "";
|
|
474
|
+
step.trimSpaces = false;
|
|
475
|
+
}
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
420
478
|
default:
|
|
421
479
|
return; // Skip if no matching method
|
|
422
480
|
}
|
|
@@ -6,6 +6,7 @@ import logger from "../../logger.js";
|
|
|
6
6
|
import { convertToIdentifier } from "./utils.js";
|
|
7
7
|
import prettier from "prettier";
|
|
8
8
|
import url from "url";
|
|
9
|
+
import { getDefaultPrettierConfig } from "../code_cleanup/utils.js";
|
|
9
10
|
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
10
11
|
const CodeStatus = {
|
|
11
12
|
ADD: "add",
|
|
@@ -32,6 +33,9 @@ export function getAiConfig() {
|
|
|
32
33
|
} catch (e) {
|
|
33
34
|
ai_config = {};
|
|
34
35
|
}
|
|
36
|
+
if (!ai_config.locatorsMetadataDir) {
|
|
37
|
+
ai_config.locatorsMetadataDir = "features/step_definitions/locators";
|
|
38
|
+
}
|
|
35
39
|
return ai_config;
|
|
36
40
|
}
|
|
37
41
|
class CodePage {
|
|
@@ -57,18 +61,7 @@ class CodePage {
|
|
|
57
61
|
if (this.sourceFileName !== null) {
|
|
58
62
|
// format the code before saving
|
|
59
63
|
try {
|
|
60
|
-
const fileContentNew = await prettier.format(this.fileContent,
|
|
61
|
-
parser: "babel",
|
|
62
|
-
trailingComma: "es5",
|
|
63
|
-
tabWidth: 2,
|
|
64
|
-
semi: true,
|
|
65
|
-
singleQuote: false,
|
|
66
|
-
bracketSpacing: true,
|
|
67
|
-
arrowParens: "always",
|
|
68
|
-
embeddedLanguageFormatting: "auto",
|
|
69
|
-
endOfLine: "lf",
|
|
70
|
-
printWidth: 120,
|
|
71
|
-
});
|
|
64
|
+
const fileContentNew = await prettier.format(this.fileContent, getDefaultPrettierConfig());
|
|
72
65
|
this._init();
|
|
73
66
|
this.generateModel(fileContentNew);
|
|
74
67
|
} catch (e) {
|
|
@@ -247,13 +240,17 @@ this.imports[2].node.source.value
|
|
|
247
240
|
}
|
|
248
241
|
return templates;
|
|
249
242
|
}
|
|
250
|
-
getExpectedTimeout(expectedNumofCmds) {
|
|
243
|
+
getExpectedTimeout(expectedNumofCmds, finalTimeout) {
|
|
244
|
+
const timeoutNum = parseFloat(finalTimeout);
|
|
245
|
+
if (finalTimeout && !isNaN(timeoutNum)) {
|
|
246
|
+
return -1;
|
|
247
|
+
}
|
|
251
248
|
return expectedNumofCmds * 60 * 1000;
|
|
252
249
|
}
|
|
253
|
-
addCucumberStep(type, cucumberLine, method, expectedNumofCmds) {
|
|
250
|
+
addCucumberStep(type, cucumberLine, method, expectedNumofCmds, finalTimeout) {
|
|
254
251
|
const result = {};
|
|
255
252
|
let code = "\n";
|
|
256
|
-
code += `${type}(${JSON.stringify(cucumberLine)}, ${expectedNumofCmds ? `{ timeout: ${this.getExpectedTimeout(expectedNumofCmds)}}, ` : ""}${method});\n`;
|
|
253
|
+
code += `${type}(${JSON.stringify(cucumberLine)}, ${expectedNumofCmds ? `{ timeout: ${this.getExpectedTimeout(expectedNumofCmds, finalTimeout)}}, ` : ""}${method});\n`;
|
|
257
254
|
let existCodePart = null;
|
|
258
255
|
for (let i = 0; i < this.cucumberCalls.length; i++) {
|
|
259
256
|
if (
|