@dev-blinq/cucumber_client 1.0.1337-dev → 1.0.1337-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 +110 -110
- package/bin/assets/preload/css_gen.js +10 -10
- package/bin/assets/preload/recorderv3.js +3 -1
- package/bin/assets/preload/toolbar.js +27 -29
- package/bin/assets/preload/unique_locators.js +1 -1
- package/bin/assets/preload/yaml.js +288 -275
- package/bin/assets/scripts/aria_snapshot.js +223 -220
- package/bin/assets/scripts/dom_attr.js +329 -329
- package/bin/assets/scripts/dom_parent.js +169 -174
- package/bin/assets/scripts/event_utils.js +94 -94
- package/bin/assets/scripts/pw.js +2050 -1949
- package/bin/assets/scripts/recorder.js +5 -17
- package/bin/assets/scripts/snapshot_capturer.js +153 -146
- package/bin/assets/scripts/unique_locators.js +940 -815
- package/bin/assets/scripts/yaml.js +796 -783
- package/bin/assets/templates/_hooks_template.txt +41 -0
- package/bin/assets/templates/utils_template.txt +2 -45
- 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/api_codegen.js +2 -2
- package/bin/client/code_gen/code_inversion.js +112 -4
- package/bin/client/code_gen/page_reflection.js +839 -906
- package/bin/client/code_gen/playwright_codeget.js +26 -18
- package/bin/client/cucumber/feature.js +89 -27
- package/bin/client/cucumber/feature_data.js +2 -2
- package/bin/client/cucumber/project_to_document.js +9 -3
- package/bin/client/cucumber/steps_definitions.js +6 -3
- package/bin/client/cucumber_selector.js +17 -1
- package/bin/client/local_agent.js +6 -5
- package/bin/client/parse_feature_file.js +23 -26
- package/bin/client/playground/projects/env.json +2 -2
- package/bin/client/project.js +186 -196
- package/bin/client/recorderv3/bvt_recorder.js +140 -86
- package/bin/client/recorderv3/implemented_steps.js +24 -14
- package/bin/client/recorderv3/index.js +59 -54
- package/bin/client/recorderv3/network.js +22 -5
- package/bin/client/recorderv3/scriptTest.js +1 -1
- package/bin/client/recorderv3/services.js +4 -16
- package/bin/client/recorderv3/step_runner.js +318 -209
- package/bin/client/recorderv3/step_utils.js +476 -17
- package/bin/client/recorderv3/update_feature.js +32 -30
- package/bin/client/recording.js +1 -0
- package/bin/client/run_cucumber.js +1 -1
- package/bin/client/scenario_report.js +0 -5
- package/bin/client/test_scenario.js +0 -1
- package/bin/client/upload-service.js +3 -2
- 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 +21 -12
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import dotenv from "dotenv";
|
|
2
|
+
// Load .env into process.env
|
|
3
|
+
dotenv.config();
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
After,
|
|
7
|
+
setDefaultTimeout,
|
|
8
|
+
Before,
|
|
9
|
+
AfterStep,
|
|
10
|
+
BeforeStep,
|
|
11
|
+
} from "@dev-blinq/cucumber-js";
|
|
12
|
+
import { closeContext, initContext, navigate, executeBrunoRequest, verifyFileExists } from "automation_model";
|
|
13
|
+
setDefaultTimeout(60 * 1000);
|
|
14
|
+
|
|
15
|
+
const url = null;
|
|
16
|
+
|
|
17
|
+
const elements = {};
|
|
18
|
+
|
|
19
|
+
let context = null;
|
|
20
|
+
Before(async function (scenario) {
|
|
21
|
+
context = await initContext(url, false, false, this);
|
|
22
|
+
await navigate(url);
|
|
23
|
+
await context.web.beforeScenario(this, scenario);
|
|
24
|
+
});
|
|
25
|
+
After(async function (scenario) {
|
|
26
|
+
await context.web.afterScenario(this, scenario);
|
|
27
|
+
await closeContext();
|
|
28
|
+
context = null;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
BeforeStep(async function (step) {
|
|
32
|
+
if (context) {
|
|
33
|
+
await context.web.beforeStep(this, step);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
AfterStep(async function (step) {
|
|
38
|
+
if (context) {
|
|
39
|
+
await context.web.afterStep(this, step);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
@@ -2,53 +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
|
-
context = await initContext(url, false, false, this);
|
|
23
|
-
await navigate(url);
|
|
24
|
-
await context.web.beforeScenario(this, scenario);
|
|
25
|
-
});
|
|
26
|
-
After(async function (scenario) {
|
|
27
|
-
await context.web.afterScenario(this, scenario);
|
|
28
|
-
await closeContext();
|
|
29
|
-
context = null;
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
BeforeStep(async function (step) {
|
|
33
|
-
if (context) {
|
|
34
|
-
await context.web.beforeStep(this, step);
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
AfterStep(async function (step) {
|
|
39
|
-
if (context) {
|
|
40
|
-
await context.web.afterStep(this, step);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Load test data for a user
|
|
46
|
-
* @param {string} user name of the user to load test data for
|
|
47
|
-
* @protect
|
|
48
|
-
*/
|
|
49
|
-
async function loadUserData(user) {
|
|
50
|
-
await context.web.loadTestDataAsync("users", user, this);
|
|
51
|
-
}
|
|
52
9
|
|
|
53
10
|
/**
|
|
54
11
|
* Verify text exsits in page
|
|
@@ -214,6 +171,6 @@ Then("Verify the page title is {string}", verify_page_title);
|
|
|
214
171
|
* @returns Promise that resolves after the specified duration
|
|
215
172
|
*/
|
|
216
173
|
async function sleep(duration) {
|
|
217
|
-
await context.web.sleep(duration, {},
|
|
174
|
+
await context.web.sleep(duration, {}, this);
|
|
218
175
|
}
|
|
219
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 };
|
|
@@ -7,10 +7,11 @@ const { default: traverse } = pkg;
|
|
|
7
7
|
import pkg1 from "@babel/generator";
|
|
8
8
|
const { default: generate } = pkg1;
|
|
9
9
|
import * as t from "@babel/types";
|
|
10
|
-
|
|
11
10
|
import { CucumberExpression, ParameterTypeRegistry } from "@cucumber/cucumber-expressions";
|
|
12
11
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
13
12
|
import { getAiConfig } from "../code_gen/page_reflection.js";
|
|
13
|
+
import socketLogger from "../utils/socket_logger.js";
|
|
14
|
+
|
|
14
15
|
const STEP_KEYWORDS = new Set(["Given", "When", "Then"]);
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -307,14 +308,17 @@ export function getDefaultPrettierConfig() {
|
|
|
307
308
|
const configContent = readFileSync(prettierConfigPath, "utf-8");
|
|
308
309
|
prettierConfig = JSON.parse(configContent);
|
|
309
310
|
} catch (error) {
|
|
311
|
+
socketLogger.error("Error parsing Prettier config file", error);
|
|
310
312
|
console.error(`Error parsing Prettier config file: ${error}`);
|
|
311
313
|
}
|
|
312
314
|
} else {
|
|
313
315
|
// save the default config to .prettierrc
|
|
314
316
|
try {
|
|
315
317
|
writeFileSync(prettierConfigPath, JSON.stringify(prettierConfig, null, 2), "utf-8");
|
|
318
|
+
socketLogger.info(`Created default Prettier config at ${prettierConfigPath}`);
|
|
316
319
|
console.log(`Created default Prettier config at ${prettierConfigPath}`);
|
|
317
320
|
} catch (error) {
|
|
321
|
+
socketLogger.error(`Error writing Prettier config file: ${error}`);
|
|
318
322
|
console.error(`Error writing Prettier config file: ${error}`);
|
|
319
323
|
}
|
|
320
324
|
}
|
|
@@ -50,7 +50,7 @@ const generateApiCode = async (
|
|
|
50
50
|
// create new codePage
|
|
51
51
|
mjsFullPath = path.join(
|
|
52
52
|
projectDir,
|
|
53
|
-
stepsDefinitions.isTemp ? process.env.tempFeaturesFolderPath ?? "__temp_features" : "features",
|
|
53
|
+
stepsDefinitions.isTemp ? (process.env.tempFeaturesFolderPath ?? "__temp_features") : "features",
|
|
54
54
|
"step_definitions",
|
|
55
55
|
`api_tests_page.mjs`
|
|
56
56
|
);
|
|
@@ -60,7 +60,7 @@ const generateApiCode = async (
|
|
|
60
60
|
if (!codePage) {
|
|
61
61
|
mjsFullPath = path.join(
|
|
62
62
|
projectDir,
|
|
63
|
-
stepsDefinitions.isTemp ? process.env.tempFeaturesFolderPath ?? "__temp_features" : "features",
|
|
63
|
+
stepsDefinitions.isTemp ? (process.env.tempFeaturesFolderPath ?? "__temp_features") : "features",
|
|
64
64
|
"step_definitions",
|
|
65
65
|
`api_tests_page.mjs`
|
|
66
66
|
);
|
|
@@ -374,10 +374,15 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
374
374
|
}
|
|
375
375
|
case "verifyTextRelatedToText": {
|
|
376
376
|
step.type = Types.VERIFY_TEXT_RELATED_TO_TEXT;
|
|
377
|
-
const
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
|
|
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];
|
|
381
386
|
break;
|
|
382
387
|
}
|
|
383
388
|
case "setInputFiles": {
|
|
@@ -426,6 +431,109 @@ const invertStableCommand = (call, elements, stepParams) => {
|
|
|
426
431
|
}
|
|
427
432
|
break;
|
|
428
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
|
+
}
|
|
478
|
+
|
|
479
|
+
case "conditionalWait": {
|
|
480
|
+
step.type = Types.CONDITIONAL_WAIT;
|
|
481
|
+
step.element = extractElement(call.arguments[0]);
|
|
482
|
+
const condition = call.arguments[1].value;
|
|
483
|
+
|
|
484
|
+
const _timeout = parseDataSource(call.arguments[2], stepParams);
|
|
485
|
+
let timeout = 30;
|
|
486
|
+
if (_timeout.type === "literal") {
|
|
487
|
+
if (isNaN(_timeout.value)) {
|
|
488
|
+
throw new Error(`Timeout value must be a number, got ${_timeout.value}`);
|
|
489
|
+
}
|
|
490
|
+
timeout = Number(_timeout.value) * 1000;
|
|
491
|
+
} else {
|
|
492
|
+
step.dataSource = _timeout.dataSource;
|
|
493
|
+
step.dataKey = _timeout.dataKey;
|
|
494
|
+
timeout = toVariableName(_timeout.dataKey);
|
|
495
|
+
}
|
|
496
|
+
// step.timeout = timeout;
|
|
497
|
+
// step.value = "true";
|
|
498
|
+
step.parameters = [timeout, condition, step.value];
|
|
499
|
+
// step.condition = condition;
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
case "sleep": {
|
|
504
|
+
step.type = Types.SLEEP;
|
|
505
|
+
const duration = parseDataSource(call.arguments[0], stepParams);
|
|
506
|
+
if (duration.type === "literal") {
|
|
507
|
+
if (isNaN(duration.value)) {
|
|
508
|
+
throw new Error(`Sleep duration must be a number, got ${duration.value}`);
|
|
509
|
+
}
|
|
510
|
+
step.parameters = [Number(duration.value)];
|
|
511
|
+
} else {
|
|
512
|
+
step.dataSource = duration.dataSource;
|
|
513
|
+
step.dataKey = duration.dataKey;
|
|
514
|
+
step.parameters = [toVariableName(duration.dataKey)];
|
|
515
|
+
}
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
case "verify_file_exists": {
|
|
519
|
+
step.type = Types.VERIFY_FILE_EXISTS;
|
|
520
|
+
const filePath = parseDataSource(call.arguments[0], stepParams);
|
|
521
|
+
if (filePath.type === "literal") {
|
|
522
|
+
step.parameters = [filePath.value];
|
|
523
|
+
} else {
|
|
524
|
+
step.dataSource = filePath.dataSource;
|
|
525
|
+
step.dataKey = filePath.dataKey;
|
|
526
|
+
step.parameters = [toVariableName(filePath.dataKey)];
|
|
527
|
+
}
|
|
528
|
+
break;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// case "verifyPagePath":
|
|
532
|
+
// {
|
|
533
|
+
// step.type = Types.VERIFY_PAGE_PATH;
|
|
534
|
+
// step.parameters = [call.arguments[0].value];
|
|
535
|
+
// break;
|
|
536
|
+
// }
|
|
429
537
|
default:
|
|
430
538
|
return; // Skip if no matching method
|
|
431
539
|
}
|