artes 1.7.25 → 1.7.26

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.
Files changed (49) hide show
  1. package/README.md +781 -781
  2. package/assets/styles.css +4 -4
  3. package/cucumber.config.js +253 -253
  4. package/docs/ciExecutors.md +198 -198
  5. package/docs/emulationDevicesList.md +152 -152
  6. package/docs/functionDefinitions.md +2401 -2401
  7. package/docs/stepDefinitions.md +435 -435
  8. package/executer.js +266 -266
  9. package/index.js +51 -51
  10. package/package.json +56 -56
  11. package/src/helper/contextManager/browserManager.js +74 -74
  12. package/src/helper/contextManager/requestManager.js +23 -23
  13. package/src/helper/controller/elementController.js +35 -0
  14. package/src/helper/controller/findDuplicateTestNames.js +69 -69
  15. package/src/helper/controller/getEnvInfo.js +97 -97
  16. package/src/helper/controller/getExecutor.js +109 -109
  17. package/src/helper/controller/pomCollector.js +83 -83
  18. package/src/helper/controller/reportCustomizer.js +511 -511
  19. package/src/helper/controller/screenComparer.js +96 -96
  20. package/src/helper/controller/status-formatter.js +137 -137
  21. package/src/helper/controller/testCoverageCalculator.js +111 -111
  22. package/src/helper/executers/cleaner.js +23 -23
  23. package/src/helper/executers/exporter.js +19 -19
  24. package/src/helper/executers/helper.js +193 -193
  25. package/src/helper/executers/projectCreator.js +226 -226
  26. package/src/helper/executers/reportGenerator.js +91 -91
  27. package/src/helper/executers/testRunner.js +28 -28
  28. package/src/helper/executers/versionChecker.js +31 -31
  29. package/src/helper/imports/commons.js +69 -69
  30. package/src/helper/stepFunctions/APIActions.js +582 -582
  31. package/src/helper/stepFunctions/assertions.js +986 -986
  32. package/src/helper/stepFunctions/browserActions.js +87 -87
  33. package/src/helper/stepFunctions/elementInteractions.js +60 -60
  34. package/src/helper/stepFunctions/exporter.js +19 -19
  35. package/src/helper/stepFunctions/frameActions.js +72 -72
  36. package/src/helper/stepFunctions/keyboardActions.js +66 -66
  37. package/src/helper/stepFunctions/mouseActions.js +84 -84
  38. package/src/helper/stepFunctions/pageActions.js +43 -43
  39. package/src/hooks/context.js +18 -18
  40. package/src/hooks/hooks.js +287 -287
  41. package/src/stepDefinitions/API.steps.js +404 -404
  42. package/src/stepDefinitions/assertions.steps.js +1389 -1389
  43. package/src/stepDefinitions/browser.steps.js +74 -74
  44. package/src/stepDefinitions/frameActions.steps.js +132 -0
  45. package/src/stepDefinitions/keyboardActions.steps.js +264 -264
  46. package/src/stepDefinitions/mouseActions.steps.js +374 -374
  47. package/src/stepDefinitions/page.steps.js +71 -71
  48. package/src/stepDefinitions/random.steps.js +199 -199
  49. package/src/stepDefinitions/report.steps.js +5 -5
package/package.json CHANGED
@@ -1,56 +1,56 @@
1
- {
2
- "name": "artes",
3
- "version": "1.7.25",
4
- "description": "The simplest way to automate UI and API tests using Cucumber-style steps.",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "cucumber-js --config=cucumber.config.js",
8
- "createProject": "node ./src/helper/executers/projectCreator.js",
9
- "publishOnly": "prettier -w . && npm version patch && npm publish"
10
- },
11
- "bin": {
12
- "artes": "./executer.js"
13
- },
14
- "publishConfig": {
15
- "registry": "https://registry.npmjs.org/"
16
- },
17
- "author": "VhdAghyv",
18
- "license": "ISC",
19
- "dependencies": {
20
- "@cucumber/cucumber": "^11.3.0",
21
- "@cucumber/messages": "26.0.1",
22
- "@faker-js/faker": "9.8.0",
23
- "@types/node": "22.9.0",
24
- "ajv": "8.17.1",
25
- "allure-commandline": "2.36.0",
26
- "allure-cucumberjs": "3.4.5",
27
- "allure-js-commons": "3.4.5",
28
- "archiver": "^7.0.1",
29
- "dayjs": "1.11.13",
30
- "deasync": "^0.1.31",
31
- "playwright": "^1.58.2",
32
- "@axe-core/playwright": "^4.11.1",
33
- "ffmpeg-static": "^5.3.0",
34
- "ffprobe-static": "^3.1.0",
35
- "pixelmatch": "^5.3.0",
36
- "pngjs": "^7.0.0",
37
- "sharp": "^0.34.5"
38
- },
39
- "repository": {
40
- "type": "git",
41
- "url": "git+https://github.com/4gayev1/Artes"
42
- },
43
- "bugs": {
44
- "url": "https://github.com/4gayev1/Artes/issues"
45
- },
46
- "homepage": "https://github.com/4gayev1/Artes/blob/main/README.md",
47
- "keywords": [
48
- "kdt",
49
- "automation",
50
- "playwright",
51
- "cucumber",
52
- "test automation",
53
- "end-to-end",
54
- "API testing"
55
- ]
56
- }
1
+ {
2
+ "name": "artes",
3
+ "version": "1.7.26",
4
+ "description": "The simplest way to automate UI and API tests using Cucumber-style steps.",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "cucumber-js --config=cucumber.config.js",
8
+ "createProject": "node ./src/helper/executers/projectCreator.js",
9
+ "publishOnly": "prettier -w . && npm version patch && npm publish"
10
+ },
11
+ "bin": {
12
+ "artes": "./executer.js"
13
+ },
14
+ "publishConfig": {
15
+ "registry": "https://registry.npmjs.org/"
16
+ },
17
+ "author": "VhdAghyv",
18
+ "license": "ISC",
19
+ "dependencies": {
20
+ "@cucumber/cucumber": "^11.3.0",
21
+ "@cucumber/messages": "26.0.1",
22
+ "@faker-js/faker": "9.8.0",
23
+ "@types/node": "22.9.0",
24
+ "ajv": "8.17.1",
25
+ "allure-commandline": "2.36.0",
26
+ "allure-cucumberjs": "3.4.5",
27
+ "allure-js-commons": "3.4.5",
28
+ "archiver": "^7.0.1",
29
+ "dayjs": "1.11.13",
30
+ "deasync": "^0.1.31",
31
+ "playwright": "^1.58.2",
32
+ "@axe-core/playwright": "^4.11.1",
33
+ "ffmpeg-static": "^5.3.0",
34
+ "ffprobe-static": "^3.1.0",
35
+ "pixelmatch": "^5.3.0",
36
+ "pngjs": "^7.0.0",
37
+ "sharp": "^0.34.5"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/4gayev1/Artes"
42
+ },
43
+ "bugs": {
44
+ "url": "https://github.com/4gayev1/Artes/issues"
45
+ },
46
+ "homepage": "https://github.com/4gayev1/Artes/blob/main/README.md",
47
+ "keywords": [
48
+ "kdt",
49
+ "automation",
50
+ "playwright",
51
+ "cucumber",
52
+ "test automation",
53
+ "end-to-end",
54
+ "API testing"
55
+ ]
56
+ }
@@ -1,74 +1,74 @@
1
- const { chromium, firefox, webkit, devices } = require("playwright");
2
- const cucumberConfig = require("../../../cucumber.config.js");
3
-
4
- const invokeBrowser = async () => {
5
- let browser;
6
-
7
- let baseURL = "";
8
-
9
- if (typeof cucumberConfig.baseURL === "object") {
10
- const env = (cucumberConfig.env || "").trim();
11
- baseURL = cucumberConfig.baseURL[env];
12
- } else {
13
- baseURL = cucumberConfig.baseURL;
14
- }
15
-
16
- const options = {
17
- headless: cucumberConfig.browser.headless,
18
- slowMo: cucumberConfig.browser.slowMo,
19
- args: [cucumberConfig.browser.maximizeScreen ? "--start-maximized" : ""],
20
- };
21
-
22
- const browserType = cucumberConfig.browser.device
23
- ? "webkit"
24
- : cucumberConfig.browser.browserType.toLowerCase() || "chrome";
25
-
26
- const browserContextOptions = {
27
- baseURL: baseURL,
28
- ...(cucumberConfig.browser.device
29
- ? {}
30
- : {
31
- viewport: cucumberConfig.browser.maximizeScreen
32
- ? null
33
- : cucumberConfig.browser.viewport,
34
- }),
35
- recordVideo: {
36
- dir: "./test-results/visualReport/",
37
- size: cucumberConfig.browser.viewport,
38
- },
39
- ignoreHTTPSErrors: true,
40
- offline: cucumberConfig.browser.offline,
41
- };
42
-
43
- switch (browserType) {
44
- case "chrome":
45
- browser = await chromium.launch(options);
46
- break;
47
- case "firefox":
48
- browser = await firefox.launch(options);
49
- break;
50
- case "webkit":
51
- browser = await webkit.launch(options);
52
- break;
53
- default:
54
- throw new Error(
55
- "Please set the proper browser!\n Options: chrome, firefox, webkit",
56
- );
57
- }
58
-
59
- const context = await browser.newContext({
60
- ...(cucumberConfig.browser.device
61
- ? devices[cucumberConfig.browser.device]
62
- : {}),
63
- ...browserContextOptions,
64
- });
65
-
66
- return {
67
- browser: browser,
68
- context: context,
69
- };
70
- };
71
-
72
- module.exports = {
73
- invokeBrowser,
74
- };
1
+ const { chromium, firefox, webkit, devices } = require("playwright");
2
+ const cucumberConfig = require("../../../cucumber.config.js");
3
+
4
+ const invokeBrowser = async () => {
5
+ let browser;
6
+
7
+ let baseURL = "";
8
+
9
+ if (typeof cucumberConfig.baseURL === "object") {
10
+ const env = (cucumberConfig.env || "").trim();
11
+ baseURL = cucumberConfig.baseURL[env];
12
+ } else {
13
+ baseURL = cucumberConfig.baseURL;
14
+ }
15
+
16
+ const options = {
17
+ headless: cucumberConfig.browser.headless,
18
+ slowMo: cucumberConfig.browser.slowMo,
19
+ args: [cucumberConfig.browser.maximizeScreen ? "--start-maximized" : ""],
20
+ };
21
+
22
+ const browserType = cucumberConfig.browser.device
23
+ ? "webkit"
24
+ : cucumberConfig.browser.browserType.toLowerCase() || "chrome";
25
+
26
+ const browserContextOptions = {
27
+ baseURL: baseURL,
28
+ ...(cucumberConfig.browser.device
29
+ ? {}
30
+ : {
31
+ viewport: cucumberConfig.browser.maximizeScreen
32
+ ? null
33
+ : cucumberConfig.browser.viewport,
34
+ }),
35
+ recordVideo: {
36
+ dir: "./test-results/visualReport/",
37
+ size: cucumberConfig.browser.viewport,
38
+ },
39
+ ignoreHTTPSErrors: true,
40
+ offline: cucumberConfig.browser.offline,
41
+ };
42
+
43
+ switch (browserType) {
44
+ case "chrome":
45
+ browser = await chromium.launch(options);
46
+ break;
47
+ case "firefox":
48
+ browser = await firefox.launch(options);
49
+ break;
50
+ case "webkit":
51
+ browser = await webkit.launch(options);
52
+ break;
53
+ default:
54
+ throw new Error(
55
+ "Please set the proper browser!\n Options: chrome, firefox, webkit",
56
+ );
57
+ }
58
+
59
+ const context = await browser.newContext({
60
+ ...(cucumberConfig.browser.device
61
+ ? devices[cucumberConfig.browser.device]
62
+ : {}),
63
+ ...browserContextOptions,
64
+ });
65
+
66
+ return {
67
+ browser: browser,
68
+ context: context,
69
+ };
70
+ };
71
+
72
+ module.exports = {
73
+ invokeBrowser,
74
+ };
@@ -1,23 +1,23 @@
1
- const { request } = require("playwright");
2
- const cucumberConfig = require("../../../cucumber.config.js");
3
-
4
- let baseURL = "";
5
-
6
- if (typeof cucumberConfig.baseURL === "object") {
7
- const env = (cucumberConfig.env || "").trim();
8
- baseURL = cucumberConfig.baseURL[env];
9
- } else {
10
- baseURL = cucumberConfig.baseURL;
11
- }
12
-
13
- const requestContextOptions = {
14
- baseURL: baseURL,
15
- ignoreHTTPSErrors: true,
16
- };
17
-
18
- async function invokeRequest() {
19
- const context = await request.newContext(requestContextOptions);
20
- return context;
21
- }
22
-
23
- module.exports = { invokeRequest };
1
+ const { request } = require("playwright");
2
+ const cucumberConfig = require("../../../cucumber.config.js");
3
+
4
+ let baseURL = "";
5
+
6
+ if (typeof cucumberConfig.baseURL === "object") {
7
+ const env = (cucumberConfig.env || "").trim();
8
+ baseURL = cucumberConfig.baseURL[env];
9
+ } else {
10
+ baseURL = cucumberConfig.baseURL;
11
+ }
12
+
13
+ const requestContextOptions = {
14
+ baseURL: baseURL,
15
+ ignoreHTTPSErrors: true,
16
+ };
17
+
18
+ async function invokeRequest() {
19
+ const context = await request.newContext(requestContextOptions);
20
+ return context;
21
+ }
22
+
23
+ module.exports = { invokeRequest };
@@ -13,6 +13,28 @@ function addElements(newElements) {
13
13
  // return locatorCount ==0 ? false : true;
14
14
  // }
15
15
 
16
+ function isPlaywrightCallSyntax(str) {
17
+ return typeof str === "string" && /^[a-zA-Z]+\(.*\)\s*;?\s*$/s.test(str.trim());
18
+ }
19
+
20
+ function parsePlaywrightCall(str) {
21
+ const match = str.trim().match(/^([a-zA-Z]+)\((.*)\)\s*;?\s*$/s);
22
+ if (!match) return null;
23
+
24
+ const [, method, argsStr] = match;
25
+
26
+ // Safely evaluate the argument list as a JS array literal
27
+ // e.g. "'button', { name: 'Decline' }" -> ['button', { name: 'Decline' }]
28
+ let args;
29
+ try {
30
+ args = Function(`"use strict"; return [${argsStr}];`)();
31
+ } catch (err) {
32
+ throw new Error(`Failed to parse locator arguments in "${str}": ${err.message}`);
33
+ }
34
+
35
+ return { method, args };
36
+ }
37
+
16
38
  function selectorSeparator(element) {
17
39
  if (typeof element !== "string") return element;
18
40
 
@@ -52,6 +74,19 @@ function getElement(element) {
52
74
  throw new Error("Page context is not initialized.");
53
75
  }
54
76
 
77
+ const rawValue = resolveVariable(
78
+ elements?.[element]?.selector || elements?.[element] || element
79
+ );
80
+
81
+ // NEW: handle raw Playwright method-call syntax, e.g. getByRole('button', { name: 'Decline' })
82
+ if (isPlaywrightCallSyntax(rawValue)) {
83
+ const parsed = parsePlaywrightCall(rawValue);
84
+ if (!parsed || typeof context.page[parsed.method] !== "function") {
85
+ throw new Error(`Unsupported or invalid Playwright locator call: "${rawValue}"`);
86
+ }
87
+ return context.page[parsed.method](...parsed.args);
88
+ }
89
+
55
90
  const selector = getSelector(element);
56
91
  const waitTime = elements[element]?.waitTime * 1000 || 0;
57
92
 
@@ -1,69 +1,69 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
-
4
- function findDuplicateTestNames() {
5
- const testStatusFile = path.join(
6
- process.cwd(),
7
- "node_modules",
8
- "artes",
9
- "test-status",
10
- "test-status.txt",
11
- );
12
-
13
- if (!fs.existsSync(testStatusFile)) {
14
- console.error("test-status.txt not found");
15
- return;
16
- }
17
-
18
- const content = fs.readFileSync(testStatusFile, "utf8");
19
- const lines = content.split("\n").filter((line) => line.trim());
20
-
21
- const testNameToEntries = {};
22
-
23
- lines.forEach((line) => {
24
- const parts = line.split(" | ");
25
- if (parts.length < 5) return;
26
-
27
- const testName = parts[2].trim();
28
- const filePath = parts[4].trim();
29
- const uuid = parts[3].trim();
30
-
31
- if (!testNameToEntries[testName]) {
32
- testNameToEntries[testName] = [];
33
- }
34
-
35
- const alreadyExists = testNameToEntries[testName].some(
36
- (e) => e.uuid === uuid,
37
- );
38
- if (!alreadyExists) {
39
- testNameToEntries[testName].push({ filePath, uuid });
40
- }
41
- });
42
-
43
- const duplicates = {};
44
-
45
- Object.entries(testNameToEntries).forEach(([testName, entries]) => {
46
- if (entries.length > 1) {
47
- duplicates[testName] = entries.map((e) => e.filePath);
48
- }
49
- });
50
-
51
- if (Object.keys(duplicates).length > 0) {
52
- console.warn(
53
- "\n\x1b[33m[WARNING] Duplicate scenario names found: This will affect your reporting",
54
- );
55
- Object.entries(duplicates).forEach(([testName, files]) => {
56
- console.log(`\x1b[33m"${testName}" exists in:`);
57
- files.forEach((file) => {
58
- console.log(` - ${file}`);
59
- });
60
- console.log("");
61
- });
62
- console.log("\x1b[0m");
63
- console.log("");
64
- }
65
-
66
- return duplicates;
67
- }
68
-
69
- module.exports = { findDuplicateTestNames };
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ function findDuplicateTestNames() {
5
+ const testStatusFile = path.join(
6
+ process.cwd(),
7
+ "node_modules",
8
+ "artes",
9
+ "test-status",
10
+ "test-status.txt",
11
+ );
12
+
13
+ if (!fs.existsSync(testStatusFile)) {
14
+ console.error("test-status.txt not found");
15
+ return;
16
+ }
17
+
18
+ const content = fs.readFileSync(testStatusFile, "utf8");
19
+ const lines = content.split("\n").filter((line) => line.trim());
20
+
21
+ const testNameToEntries = {};
22
+
23
+ lines.forEach((line) => {
24
+ const parts = line.split(" | ");
25
+ if (parts.length < 5) return;
26
+
27
+ const testName = parts[2].trim();
28
+ const filePath = parts[4].trim();
29
+ const uuid = parts[3].trim();
30
+
31
+ if (!testNameToEntries[testName]) {
32
+ testNameToEntries[testName] = [];
33
+ }
34
+
35
+ const alreadyExists = testNameToEntries[testName].some(
36
+ (e) => e.uuid === uuid,
37
+ );
38
+ if (!alreadyExists) {
39
+ testNameToEntries[testName].push({ filePath, uuid });
40
+ }
41
+ });
42
+
43
+ const duplicates = {};
44
+
45
+ Object.entries(testNameToEntries).forEach(([testName, entries]) => {
46
+ if (entries.length > 1) {
47
+ duplicates[testName] = entries.map((e) => e.filePath);
48
+ }
49
+ });
50
+
51
+ if (Object.keys(duplicates).length > 0) {
52
+ console.warn(
53
+ "\n\x1b[33m[WARNING] Duplicate scenario names found: This will affect your reporting",
54
+ );
55
+ Object.entries(duplicates).forEach(([testName, files]) => {
56
+ console.log(`\x1b[33m"${testName}" exists in:`);
57
+ files.forEach((file) => {
58
+ console.log(` - ${file}`);
59
+ });
60
+ console.log("");
61
+ });
62
+ console.log("\x1b[0m");
63
+ console.log("");
64
+ }
65
+
66
+ return duplicates;
67
+ }
68
+
69
+ module.exports = { findDuplicateTestNames };