@dev-blinq/cucumber_client 1.0.1472-dev → 1.0.1472-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 +73 -73
- package/bin/assets/scripts/recorder.js +87 -49
- package/bin/assets/scripts/snapshot_capturer.js +10 -17
- package/bin/assets/scripts/unique_locators.js +168 -40
- package/bin/assets/templates/_hooks_template.txt +6 -2
- package/bin/assets/templates/utils_template.txt +16 -16
- package/bin/client/code_cleanup/utils.js +16 -7
- package/bin/client/code_gen/code_inversion.js +125 -1
- package/bin/client/code_gen/duplication_analysis.js +2 -1
- package/bin/client/code_gen/function_signature.js +8 -0
- package/bin/client/code_gen/index.js +4 -0
- package/bin/client/code_gen/page_reflection.js +90 -9
- package/bin/client/code_gen/playwright_codeget.js +173 -77
- package/bin/client/codemod/find_harcoded_locators.js +173 -0
- package/bin/client/codemod/fix_hardcoded_locators.js +247 -0
- package/bin/client/codemod/index.js +8 -0
- package/bin/client/codemod/locators_array/find_misstructured_elements.js +148 -0
- package/bin/client/codemod/locators_array/fix_misstructured_elements.js +144 -0
- package/bin/client/codemod/locators_array/index.js +114 -0
- package/bin/client/codemod/types.js +1 -0
- package/bin/client/cucumber/feature.js +4 -17
- package/bin/client/cucumber/steps_definitions.js +17 -12
- package/bin/client/recorderv3/bvt_init.js +310 -0
- package/bin/client/recorderv3/bvt_recorder.js +1560 -1183
- package/bin/client/recorderv3/constants.js +45 -0
- package/bin/client/recorderv3/implemented_steps.js +2 -0
- package/bin/client/recorderv3/index.js +3 -293
- package/bin/client/recorderv3/mixpanel.js +41 -0
- package/bin/client/recorderv3/services.js +839 -142
- package/bin/client/recorderv3/step_runner.js +36 -7
- package/bin/client/recorderv3/step_utils.js +300 -98
- package/bin/client/recorderv3/update_feature.js +87 -39
- package/bin/client/recorderv3/utils.js +74 -0
- package/bin/client/recorderv3/wbr_entry.js +61 -0
- package/bin/client/recording.js +1 -0
- package/bin/client/types/locators.js +2 -0
- package/bin/client/upload-service.js +2 -0
- package/bin/client/utils/app_dir.js +21 -0
- package/bin/client/utils/socket_logger.js +100 -125
- package/bin/index.js +5 -0
- package/package.json +21 -6
- package/bin/client/recorderv3/app_dir.js +0 -23
- package/bin/client/recorderv3/network.js +0 -299
- package/bin/client/recorderv3/scriptTest.js +0 -5
- package/bin/client/recorderv3/ws_server.js +0 -72
|
@@ -12,7 +12,7 @@ import path from "path";
|
|
|
12
12
|
* @param {string} text the text to verify exists in page
|
|
13
13
|
* @protect
|
|
14
14
|
*/
|
|
15
|
-
async function verifyTextExistsInPage(text) {
|
|
15
|
+
export async function verifyTextExistsInPage(text) {
|
|
16
16
|
await context.web.verifyTextExistInPage(text, null, this);
|
|
17
17
|
}
|
|
18
18
|
Then("Verify the text {string} can be found in the page", verifyTextExistsInPage);
|
|
@@ -22,7 +22,7 @@ Then("Verify the text {string} can be found in the page", verifyTextExistsInPage
|
|
|
22
22
|
* @param {string} elementDescription element description
|
|
23
23
|
* @protect
|
|
24
24
|
*/
|
|
25
|
-
async function clickOnElement(elementDescription) {
|
|
25
|
+
export async function clickOnElement(elementDescription) {
|
|
26
26
|
await context.web.simpleClick(elementDescription, null, null, this);
|
|
27
27
|
}
|
|
28
28
|
When("click on {string}", clickOnElement);
|
|
@@ -36,7 +36,7 @@ When("Click {string}", clickOnElement);
|
|
|
36
36
|
* @param {string} value value to fill the element with
|
|
37
37
|
* @protect
|
|
38
38
|
*/
|
|
39
|
-
async function fillElement(elementDescription, value) {
|
|
39
|
+
export async function fillElement(elementDescription, value) {
|
|
40
40
|
await context.web.simpleClickType(elementDescription, value, null, null, this);
|
|
41
41
|
}
|
|
42
42
|
When("fill {string} with {string}", fillElement);
|
|
@@ -47,7 +47,7 @@ When("Fill {string} with {string}", fillElement);
|
|
|
47
47
|
* @param {string} text the text to verify does not exist in page
|
|
48
48
|
* @protect
|
|
49
49
|
*/
|
|
50
|
-
async function verifyTextNotExistsInPage(text) {
|
|
50
|
+
export async function verifyTextNotExistsInPage(text) {
|
|
51
51
|
await context.web.waitForTextToDisappear(text, null, this);
|
|
52
52
|
}
|
|
53
53
|
Then("Verify the text {string} cannot be found in the page", verifyTextNotExistsInPage);
|
|
@@ -57,7 +57,7 @@ Then("Verify the text {string} cannot be found in the page", verifyTextNotExists
|
|
|
57
57
|
* @param {string} url URL to navigate
|
|
58
58
|
* @protect
|
|
59
59
|
*/
|
|
60
|
-
async function navigateTo(url) {
|
|
60
|
+
export async function navigateTo(url) {
|
|
61
61
|
await context.web.goto(url, this);
|
|
62
62
|
}
|
|
63
63
|
When("Navigate to {string}", navigateTo);
|
|
@@ -66,7 +66,7 @@ When("Navigate to {string}", navigateTo);
|
|
|
66
66
|
* Navigate to the current page
|
|
67
67
|
* @protect
|
|
68
68
|
*/
|
|
69
|
-
async function browserNavigateBack() {
|
|
69
|
+
export async function browserNavigateBack() {
|
|
70
70
|
await context.web.goBack({}, this);
|
|
71
71
|
}
|
|
72
72
|
Then("Browser navigate back", browserNavigateBack);
|
|
@@ -75,7 +75,7 @@ Then("Browser navigate back", browserNavigateBack);
|
|
|
75
75
|
* Navigate forward in browser history
|
|
76
76
|
* @protect
|
|
77
77
|
*/
|
|
78
|
-
async function browserNavigateForward() {
|
|
78
|
+
export async function browserNavigateForward() {
|
|
79
79
|
await context.web.goForward({}, this);
|
|
80
80
|
}
|
|
81
81
|
Then("Browser navigate forward", browserNavigateForward);
|
|
@@ -85,7 +85,7 @@ Then("Browser navigate forward", browserNavigateForward);
|
|
|
85
85
|
* @param {string} filePath the file path or empty to store in the test data file
|
|
86
86
|
* @protect
|
|
87
87
|
*/
|
|
88
|
-
async function storeBrowserSession(filePath) {
|
|
88
|
+
export async function storeBrowserSession(filePath) {
|
|
89
89
|
await context.web.saveStoreState(filePath, this);
|
|
90
90
|
}
|
|
91
91
|
When("Store browser session {string}", storeBrowserSession);
|
|
@@ -95,7 +95,7 @@ When("Store browser session {string}", storeBrowserSession);
|
|
|
95
95
|
* @param {string} filePath the file path or empty
|
|
96
96
|
* @protect
|
|
97
97
|
*/
|
|
98
|
-
async function resetBrowserSession(filePath) {
|
|
98
|
+
export async function resetBrowserSession(filePath) {
|
|
99
99
|
await context.web.restoreSaveState(filePath, this);
|
|
100
100
|
}
|
|
101
101
|
When("Reset browser session {string}", resetBrowserSession);
|
|
@@ -107,7 +107,7 @@ When("Reset browser session {string}", resetBrowserSession);
|
|
|
107
107
|
* @param {string} textToVerify the target text to verify
|
|
108
108
|
* @protect
|
|
109
109
|
*/
|
|
110
|
-
async function verifyTextRelatedToText(textAnchor, climb, textToVerify) {
|
|
110
|
+
export async function verifyTextRelatedToText(textAnchor, climb, textToVerify) {
|
|
111
111
|
await context.web.verifyTextRelatedToText(textAnchor, climb, textToVerify, null, this);
|
|
112
112
|
}
|
|
113
113
|
Then(
|
|
@@ -120,7 +120,7 @@ Then(
|
|
|
120
120
|
* @requestName the name of the bruno request file
|
|
121
121
|
* @protect
|
|
122
122
|
*/
|
|
123
|
-
async function runBrunoRequest(requestName) {
|
|
123
|
+
export async function runBrunoRequest(requestName) {
|
|
124
124
|
await executeBrunoRequest(requestName, {}, context, this);
|
|
125
125
|
}
|
|
126
126
|
When("Bruno - {string}", runBrunoRequest);
|
|
@@ -131,7 +131,7 @@ When("bruno - {string}", runBrunoRequest);
|
|
|
131
131
|
* @param {string} fileName the downloaded file to verify
|
|
132
132
|
* @protect
|
|
133
133
|
*/
|
|
134
|
-
async function verify_the_downloaded_file_exists(fileName) {
|
|
134
|
+
export async function verify_the_downloaded_file_exists(fileName) {
|
|
135
135
|
const downloadFolder = path.join(context.reportFolder, "downloads");
|
|
136
136
|
const downloadFile = path.join(downloadFolder, fileName);
|
|
137
137
|
await verifyFileExists(downloadFile, {}, context, this);
|
|
@@ -148,7 +148,7 @@ When("Noop", async function () {});
|
|
|
148
148
|
* @param {string} url URL to be verified against current URL
|
|
149
149
|
* @protect
|
|
150
150
|
*/
|
|
151
|
-
async function verify_page_url(url) {
|
|
151
|
+
export async function verify_page_url(url) {
|
|
152
152
|
await context.web.verifyPagePath(url, {}, this);
|
|
153
153
|
}
|
|
154
154
|
Then("Verify the page url is {string}", verify_page_url);
|
|
@@ -158,7 +158,7 @@ Then("Verify the page url is {string}", verify_page_url);
|
|
|
158
158
|
* @param {string} title Title to be verified against current Title
|
|
159
159
|
* @protect
|
|
160
160
|
*/
|
|
161
|
-
async function verify_page_title(title) {
|
|
161
|
+
export async function verify_page_title(title) {
|
|
162
162
|
await context.web.verifyPageTitle(title, {}, this);
|
|
163
163
|
}
|
|
164
164
|
Then("Verify the page title is {string}", verify_page_title);
|
|
@@ -170,7 +170,7 @@ Then("Verify the page title is {string}", verify_page_title);
|
|
|
170
170
|
* @param {world} - Optional world context
|
|
171
171
|
* @returns Promise that resolves after the specified duration
|
|
172
172
|
*/
|
|
173
|
-
async function sleep(duration) {
|
|
174
|
-
await context.web.sleep(duration, {},
|
|
173
|
+
export async function sleep(duration) {
|
|
174
|
+
await context.web.sleep(duration, {}, this);
|
|
175
175
|
}
|
|
176
176
|
Then("Sleep for {string} ms", { timeout: -1 }, sleep);
|
|
@@ -10,7 +10,7 @@ import * as t from "@babel/types";
|
|
|
10
10
|
import { CucumberExpression, ParameterTypeRegistry } from "@cucumber/cucumber-expressions";
|
|
11
11
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
12
12
|
import { getAiConfig } from "../code_gen/page_reflection.js";
|
|
13
|
-
import socketLogger from "../utils/socket_logger.js";
|
|
13
|
+
import socketLogger, { getErrorMessage } from "../utils/socket_logger.js";
|
|
14
14
|
|
|
15
15
|
const STEP_KEYWORDS = new Set(["Given", "When", "Then"]);
|
|
16
16
|
|
|
@@ -308,18 +308,27 @@ export function getDefaultPrettierConfig() {
|
|
|
308
308
|
const configContent = readFileSync(prettierConfigPath, "utf-8");
|
|
309
309
|
prettierConfig = JSON.parse(configContent);
|
|
310
310
|
} catch (error) {
|
|
311
|
-
socketLogger.error(
|
|
312
|
-
|
|
311
|
+
socketLogger.error(
|
|
312
|
+
`Error parsing Prettier config file: ${getErrorMessage(error)}`,
|
|
313
|
+
undefined,
|
|
314
|
+
"getDefaultPrettierConfig"
|
|
315
|
+
);
|
|
313
316
|
}
|
|
314
317
|
} else {
|
|
315
318
|
// save the default config to .prettierrc
|
|
316
319
|
try {
|
|
317
320
|
writeFileSync(prettierConfigPath, JSON.stringify(prettierConfig, null, 2), "utf-8");
|
|
318
|
-
socketLogger.info(
|
|
319
|
-
|
|
321
|
+
socketLogger.info(
|
|
322
|
+
`Created default Prettier config at ${prettierConfigPath}`,
|
|
323
|
+
undefined,
|
|
324
|
+
"getDefaultPrettierConfig"
|
|
325
|
+
);
|
|
320
326
|
} catch (error) {
|
|
321
|
-
socketLogger.error(
|
|
322
|
-
|
|
327
|
+
socketLogger.error(
|
|
328
|
+
`Error writing Prettier config file: ${getErrorMessage(error)}`,
|
|
329
|
+
undefined,
|
|
330
|
+
"getDefaultPrettierConfig"
|
|
331
|
+
);
|
|
323
332
|
}
|
|
324
333
|
}
|
|
325
334
|
return prettierConfig;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { Types } from "../recording.js";
|
|
2
2
|
import Walker from "node-source-walk";
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {import("../types/locators").Locator} Locator
|
|
5
|
+
* @typedef {import("../types/locators").LocatorBundle} LocatorBundle
|
|
6
|
+
*/
|
|
3
7
|
|
|
4
8
|
const extractElementIdentifier = (node) => {
|
|
5
9
|
// Check for elements["someIdentifier"] pattern
|
|
@@ -86,6 +90,34 @@ const parseDataSource = (paramNode, stepParams) => {
|
|
|
86
90
|
// }
|
|
87
91
|
throw new Error("Unknown parameter type");
|
|
88
92
|
};
|
|
93
|
+
|
|
94
|
+
const parseOptions = (optionsNode) => {
|
|
95
|
+
const properties = optionsNode.properties;
|
|
96
|
+
const options = {};
|
|
97
|
+
for (const prop of properties) {
|
|
98
|
+
let key = "";
|
|
99
|
+
if (prop.key.type === "Identifier") {
|
|
100
|
+
key = prop.key.name;
|
|
101
|
+
} else if (prop.key.type === "StringLiteral") {
|
|
102
|
+
key = prop.key.value;
|
|
103
|
+
}
|
|
104
|
+
if (key === "context") continue;
|
|
105
|
+
options[key] = prop.value.value;
|
|
106
|
+
}
|
|
107
|
+
return options;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const parseOptionsFromCallNode = (call, index) => {
|
|
111
|
+
if (call.arguments[index] && call.arguments[index].type === "ObjectExpression") {
|
|
112
|
+
return parseOptions(call.arguments[index]);
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* @param {any} call
|
|
118
|
+
* @param {Record<string, { locators?: Locator[] | LocatorBundle }>} elements
|
|
119
|
+
* @param {any[]} stepParams
|
|
120
|
+
*/
|
|
89
121
|
const invertStableCommand = (call, elements, stepParams) => {
|
|
90
122
|
const methodName = call.callee.property.name;
|
|
91
123
|
const step = { type: null, parameters: [], element: null, locators: null };
|
|
@@ -104,6 +136,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
104
136
|
step.dataSource = inputParam.dataSource;
|
|
105
137
|
step.dataKey = inputParam.dataKey;
|
|
106
138
|
}
|
|
139
|
+
step.options = parseOptionsFromCallNode(call, 3);
|
|
107
140
|
break;
|
|
108
141
|
}
|
|
109
142
|
|
|
@@ -130,6 +163,8 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
130
163
|
step.count = clickCountProp.value.value;
|
|
131
164
|
}
|
|
132
165
|
}
|
|
166
|
+
|
|
167
|
+
step.options = parseOptionsFromCallNode(call, 2);
|
|
133
168
|
break;
|
|
134
169
|
|
|
135
170
|
case "setDateTime": {
|
|
@@ -147,6 +182,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
147
182
|
step.dataKey = dateParam.dataKey;
|
|
148
183
|
step.parameters = [toVariableName(dateParam.dataKey), format, enterParam];
|
|
149
184
|
}
|
|
185
|
+
step.options = parseOptionsFromCallNode(call, 5);
|
|
150
186
|
break;
|
|
151
187
|
}
|
|
152
188
|
|
|
@@ -163,6 +199,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
163
199
|
step.dataKey = selectParam.dataKey;
|
|
164
200
|
step.parameters = [toVariableName(selectParam.dataKey)];
|
|
165
201
|
}
|
|
202
|
+
step.options = parseOptionsFromCallNode(call, 3);
|
|
166
203
|
break;
|
|
167
204
|
}
|
|
168
205
|
|
|
@@ -176,6 +213,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
176
213
|
step.dataKey = text.dataKey;
|
|
177
214
|
step.parameters = [toVariableName(text.dataKey)];
|
|
178
215
|
}
|
|
216
|
+
step.options = parseOptionsFromCallNode(call, 2);
|
|
179
217
|
break;
|
|
180
218
|
}
|
|
181
219
|
case "waitForTextToDisappear": {
|
|
@@ -188,6 +226,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
188
226
|
step.dataKey = text.dataKey;
|
|
189
227
|
step.parameters = [toVariableName(text.dataKey)];
|
|
190
228
|
}
|
|
229
|
+
step.options = parseOptionsFromCallNode(call, 2);
|
|
191
230
|
break;
|
|
192
231
|
}
|
|
193
232
|
|
|
@@ -203,6 +242,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
203
242
|
step.dataKey = text.dataKey;
|
|
204
243
|
step.parameters = [toVariableName(text.dataKey), climb ?? null];
|
|
205
244
|
}
|
|
245
|
+
step.options = parseOptionsFromCallNode(call, 4);
|
|
206
246
|
break;
|
|
207
247
|
}
|
|
208
248
|
case "extractAttribute": {
|
|
@@ -233,6 +273,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
233
273
|
step.regex = "";
|
|
234
274
|
step.trimSpaces = false;
|
|
235
275
|
}
|
|
276
|
+
step.options = parseOptionsFromCallNode(call, 4);
|
|
236
277
|
break;
|
|
237
278
|
}
|
|
238
279
|
case "verifyAttribute": {
|
|
@@ -249,6 +290,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
249
290
|
step.dataKey = value.dataKey;
|
|
250
291
|
step.parameters = [attribute, toVariableName(value.dataKey)];
|
|
251
292
|
}
|
|
293
|
+
step.options = parseOptionsFromCallNode(call, 4);
|
|
252
294
|
break;
|
|
253
295
|
}
|
|
254
296
|
|
|
@@ -277,6 +319,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
277
319
|
step.parameters = [toVariableName(fillParam.dataKey), enterValue];
|
|
278
320
|
}
|
|
279
321
|
}
|
|
322
|
+
step.options = parseOptionsFromCallNode(call, 4);
|
|
280
323
|
break;
|
|
281
324
|
|
|
282
325
|
case "loadTestDataAsync": {
|
|
@@ -307,23 +350,28 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
307
350
|
step.dataKey = url.dataKey;
|
|
308
351
|
step.parameters = [toVariableName(url.dataKey)];
|
|
309
352
|
}
|
|
353
|
+
step.options = parseOptionsFromCallNode(call, 2);
|
|
310
354
|
break;
|
|
311
355
|
}
|
|
312
356
|
|
|
313
357
|
case "goBack":
|
|
314
358
|
step.type = Types.GO_BACK;
|
|
359
|
+
step.options = parseOptionsFromCallNode(call, 0);
|
|
315
360
|
break;
|
|
316
361
|
|
|
317
362
|
case "goForward":
|
|
318
363
|
step.type = Types.GO_FORWARD;
|
|
364
|
+
step.options = parseOptionsFromCallNode(call, 0);
|
|
319
365
|
break;
|
|
320
366
|
|
|
321
367
|
case "reloadPage":
|
|
322
368
|
step.type = Types.RELOAD;
|
|
369
|
+
step.options = parseOptionsFromCallNode(call, 0);
|
|
323
370
|
break;
|
|
324
371
|
|
|
325
372
|
case "closePage":
|
|
326
373
|
step.type = Types.CLOSE_PAGE;
|
|
374
|
+
step.options = parseOptionsFromCallNode(call, 0);
|
|
327
375
|
break;
|
|
328
376
|
|
|
329
377
|
case "simpleClick":
|
|
@@ -341,12 +389,15 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
341
389
|
case "hover":
|
|
342
390
|
step.type = Types.HOVER;
|
|
343
391
|
step.element = extractElement(call.arguments[0]);
|
|
392
|
+
step.options = parseOptionsFromCallNode(call, 2);
|
|
344
393
|
break;
|
|
345
394
|
|
|
346
395
|
case "setCheck":
|
|
347
396
|
step.type = Types.CHECK;
|
|
348
397
|
step.element = extractElement(call.arguments[0]);
|
|
349
398
|
step.check = call.arguments[1].value;
|
|
399
|
+
///
|
|
400
|
+
step.options = parseOptionsFromCallNode(call, 3);
|
|
350
401
|
break;
|
|
351
402
|
|
|
352
403
|
case "setViewportSize": {
|
|
@@ -354,12 +405,14 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
354
405
|
const width = call.arguments[0].value;
|
|
355
406
|
const height = call.arguments[1].value;
|
|
356
407
|
step.parameters = [width, height];
|
|
408
|
+
step.options = parseOptionsFromCallNode(call, 2);
|
|
357
409
|
break;
|
|
358
410
|
}
|
|
359
411
|
|
|
360
412
|
case "visualVerification": {
|
|
361
413
|
step.type = Types.VISUAL_VERIFICATION;
|
|
362
414
|
step.parameters = [call.arguments[0].value];
|
|
415
|
+
step.options = parseOptionsFromCallNode(call, 1);
|
|
363
416
|
break;
|
|
364
417
|
}
|
|
365
418
|
case "waitForUserInput": {
|
|
@@ -370,6 +423,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
370
423
|
case "extractEmailData": {
|
|
371
424
|
step.type = Types.MAIL_GET_CODE_OR_URL;
|
|
372
425
|
step.parameters = [call.arguments[0].value];
|
|
426
|
+
step.options = parseOptionsFromCallNode(call, 1);
|
|
373
427
|
break;
|
|
374
428
|
}
|
|
375
429
|
case "verifyTextRelatedToText": {
|
|
@@ -383,6 +437,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
383
437
|
const textToVerify =
|
|
384
438
|
textToVerifyParse.type === "literal" ? textToVerifyParse.value : toVariableName(textToVerifyParse.dataKey);
|
|
385
439
|
step.parameters = [textAnchor, climb, textToVerify];
|
|
440
|
+
step.options = parseOptionsFromCallNode(call, 3);
|
|
386
441
|
break;
|
|
387
442
|
}
|
|
388
443
|
case "setInputFiles": {
|
|
@@ -396,6 +451,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
396
451
|
step.dataKey = fileParam.dataKey;
|
|
397
452
|
step.parameters = [toVariableName(fileParam.dataKey)];
|
|
398
453
|
}
|
|
454
|
+
step.options = parseOptionsFromCallNode(call, 3);
|
|
399
455
|
break;
|
|
400
456
|
}
|
|
401
457
|
case "snapshotValidation": {
|
|
@@ -405,6 +461,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
405
461
|
step.parameters = [inputParam.value];
|
|
406
462
|
}
|
|
407
463
|
step.selectors = call.arguments[0].value;
|
|
464
|
+
step.options = parseOptionsFromCallNode(call, 3);
|
|
408
465
|
break;
|
|
409
466
|
}
|
|
410
467
|
case "verifyPageTitle": {
|
|
@@ -417,6 +474,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
417
474
|
step.dataKey = text.dataKey;
|
|
418
475
|
step.parameters = [toVariableName(text.dataKey)];
|
|
419
476
|
}
|
|
477
|
+
step.options = parseOptionsFromCallNode(call, 1);
|
|
420
478
|
break;
|
|
421
479
|
}
|
|
422
480
|
case "verifyPagePath": {
|
|
@@ -429,6 +487,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
429
487
|
step.dataKey = path.dataKey;
|
|
430
488
|
step.parameters = [toVariableName(path.dataKey)];
|
|
431
489
|
}
|
|
490
|
+
step.options = parseOptionsFromCallNode(call, 1);
|
|
432
491
|
break;
|
|
433
492
|
}
|
|
434
493
|
case "verifyProperty": {
|
|
@@ -443,6 +502,7 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
443
502
|
step.dataKey = value.dataKey;
|
|
444
503
|
step.parameters = [property, toVariableName(value.dataKey)];
|
|
445
504
|
}
|
|
505
|
+
step.options = parseOptionsFromCallNode(call, 4);
|
|
446
506
|
break;
|
|
447
507
|
}
|
|
448
508
|
case "extractProperty": {
|
|
@@ -473,15 +533,79 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
473
533
|
step.regex = "";
|
|
474
534
|
step.trimSpaces = false;
|
|
475
535
|
}
|
|
536
|
+
step.options = parseOptionsFromCallNode(call, 4);
|
|
537
|
+
break;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
case "conditionalWait": {
|
|
541
|
+
step.type = Types.CONDITIONAL_WAIT;
|
|
542
|
+
step.element = extractElement(call.arguments[0]);
|
|
543
|
+
const condition = call.arguments[1].value;
|
|
544
|
+
|
|
545
|
+
const _timeout = parseDataSource(call.arguments[2], stepParams);
|
|
546
|
+
let timeout = 30;
|
|
547
|
+
if (_timeout.type === "literal") {
|
|
548
|
+
if (isNaN(_timeout.value)) {
|
|
549
|
+
throw new Error(`Timeout value must be a number, got ${_timeout.value}`);
|
|
550
|
+
}
|
|
551
|
+
timeout = Number(_timeout.value) * 1000;
|
|
552
|
+
} else {
|
|
553
|
+
step.dataSource = _timeout.dataSource;
|
|
554
|
+
step.dataKey = _timeout.dataKey;
|
|
555
|
+
timeout = toVariableName(_timeout.dataKey);
|
|
556
|
+
}
|
|
557
|
+
// step.timeout = timeout;
|
|
558
|
+
// step.value = "true";
|
|
559
|
+
step.parameters = [timeout, condition, step.value];
|
|
560
|
+
// step.condition = condition;
|
|
561
|
+
step.options = parseOptionsFromCallNode(call, 4);
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
case "sleep": {
|
|
566
|
+
step.type = Types.SLEEP;
|
|
567
|
+
const duration = parseDataSource(call.arguments[0], stepParams);
|
|
568
|
+
if (duration.type === "literal") {
|
|
569
|
+
if (isNaN(duration.value)) {
|
|
570
|
+
throw new Error(`Sleep duration must be a number, got ${duration.value}`);
|
|
571
|
+
}
|
|
572
|
+
step.parameters = [Number(duration.value)];
|
|
573
|
+
} else {
|
|
574
|
+
step.dataSource = duration.dataSource;
|
|
575
|
+
step.dataKey = duration.dataKey;
|
|
576
|
+
step.parameters = [toVariableName(duration.dataKey)];
|
|
577
|
+
}
|
|
578
|
+
step.options = parseOptionsFromCallNode(call, 1);
|
|
476
579
|
break;
|
|
477
580
|
}
|
|
581
|
+
case "verify_file_exists": {
|
|
582
|
+
step.type = Types.VERIFY_FILE_EXISTS;
|
|
583
|
+
const filePath = parseDataSource(call.arguments[0], stepParams);
|
|
584
|
+
if (filePath.type === "literal") {
|
|
585
|
+
step.parameters = [filePath.value];
|
|
586
|
+
} else {
|
|
587
|
+
step.dataSource = filePath.dataSource;
|
|
588
|
+
step.dataKey = filePath.dataKey;
|
|
589
|
+
step.parameters = [toVariableName(filePath.dataKey)];
|
|
590
|
+
}
|
|
591
|
+
step.options = parseOptionsFromCallNode(call, 1);
|
|
592
|
+
break;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// case "verifyPagePath":
|
|
596
|
+
// {
|
|
597
|
+
// step.type = Types.VERIFY_PAGE_PATH;
|
|
598
|
+
// step.parameters = [call.arguments[0].value];
|
|
599
|
+
// break;
|
|
600
|
+
// }
|
|
478
601
|
default:
|
|
479
602
|
return; // Skip if no matching method
|
|
480
603
|
}
|
|
481
604
|
|
|
482
605
|
// Set locators if element exists
|
|
483
606
|
if (step.element && elements[step.element.key]) {
|
|
484
|
-
|
|
607
|
+
const locBundle = elements[step.element.key];
|
|
608
|
+
step.locators = locBundle;
|
|
485
609
|
}
|
|
486
610
|
|
|
487
611
|
if (step.type === Types.CLICK) {
|
|
@@ -4,6 +4,7 @@ import path from "path";
|
|
|
4
4
|
import { CodePage } from "./page_reflection.js";
|
|
5
5
|
import { compareElements, generateSignature } from "./function_signature.js";
|
|
6
6
|
import { updateStepDefinitions } from "../recorderv3/step_utils.js";
|
|
7
|
+
import socketLoggerInstance from "../utils/socket_logger.js";
|
|
7
8
|
/**
|
|
8
9
|
* DuplicationAnalizer class
|
|
9
10
|
* How to use:
|
|
@@ -101,7 +102,7 @@ async function compareWithScenario(projectDir, scenario) {
|
|
|
101
102
|
analyzerExisting.load();
|
|
102
103
|
// generate a temporary folder
|
|
103
104
|
const folder = fs.mkdtempSync(path.join(os.tmpdir(), "blinq-"));
|
|
104
|
-
await updateStepDefinitions({ scenario, featureName: "temp", projectDir: folder });
|
|
105
|
+
await updateStepDefinitions({ scenario, featureName: "temp", projectDir: folder, logger: socketLoggerInstance });
|
|
105
106
|
const analyzerScenario = new DuplicationAnalizer(folder);
|
|
106
107
|
analyzerScenario.load();
|
|
107
108
|
const compareResults = [];
|
|
@@ -11,6 +11,12 @@ async function verify_the_opportunity_name_was_created(_name) {
|
|
|
11
11
|
}
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import strip from "strip-comments";
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {import("../types/locators").Locator} Locator
|
|
17
|
+
* @typedef {import("../types/locators").LocatorBundle} LocatorBundle
|
|
18
|
+
*/
|
|
19
|
+
|
|
14
20
|
function generateSignature(page, functionName) {
|
|
15
21
|
let functionCode = null;
|
|
16
22
|
let method = null;
|
|
@@ -28,6 +34,8 @@ function generateSignature(page, functionName) {
|
|
|
28
34
|
method.node.body.parent.params.forEach((param) => {
|
|
29
35
|
parameters.push(param.name);
|
|
30
36
|
});
|
|
37
|
+
const strippedFunctionCode = strip(functionCode);
|
|
38
|
+
functionCode = strippedFunctionCode !== "" ? strippedFunctionCode : functionCode;
|
|
31
39
|
let lines = functionCode.split("\n");
|
|
32
40
|
// trim all lines
|
|
33
41
|
lines = lines.map((line) => line.trim());
|