artes 1.5.10 → 1.6.0

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/README.md CHANGED
@@ -115,9 +115,14 @@ npx artes [options]
115
115
  | `-rwt, --reportWithTrace` | Add trace to the report | `artes -rwt` or `artes --reportWithTrace` |
116
116
  | `--singleFileReport` | Generate single file allure report | `artes -r --singleFileReport` |
117
117
  | `--zip` | Zip the report folder after generation | `artes -r --zip` |
118
+ | `--uploadReport` | Upload the generated report to Artes Reporting System | `artes --uploadReport --reporterURL "https://example.com"` |
119
+ | `--reporterURL` | URL of the Artes Reporting System to upload the report | `artes --uploadReport --reporterURL "https://example.com"` |
120
+ | `--projectName` | Name of the project in the Artes Reporting System (default: `"Artes Report"`) | `artes --uploadReport --reporterURL "https://example.com" --projectName "My Project"` |
121
+ | `--projectType` | Type of the project for reporting purposes (default: `"Artes"`) | `artes --uploadReport --reporterURL "https://example.com" --projectType "API"` |
122
+ | `--reportPath` | Path to the report zip file to upload (default: `./report.zip`) | `artes --uploadReport --reporterURL "https://example.com" --reportPath "./my_report.zip"` |
118
123
  | 🖼️ `--logo` | Set a custom logo in the report sidebar. Accepts an absolute path, a relative path, or a direct image URL | `artes --logo /abs/path/logo.png`<br>`artes --logo logo.png`<br>`artes --logo 'https://example.com/logo.png'` |
119
124
  | 🏢 `--brandName` | Set the brand name displayed next to the logo in the report sidebar | `artes --brandName 'My Company'` |
120
- | 📄 `--reportName` | Set the report name displayed on the summary widget | `artes --reportName 'Alma UI'`
125
+ | 📄 `--reportName` | Report name displayed on the summary widget and in the Artes Reporting System | `artes --reportName 'Alma UI'`
121
126
  | 📁 `--features` | Specify one or more feature files' relative paths to run (comma-separated) | `artes --features "tests/features/Alma,tests/features/Banan.feature"` |
122
127
  | 📜 `--stepDef` | Specify one or more step definition files' relative paths to use (comma-separated) | `artes --stepDef "tests/steps/login.js,tests/steps/home.js"` |
123
128
  | 🔖 `--tags` | Run tests with specified Cucumber tags | `artes --tags "@smoke or @wip"` |
@@ -615,13 +620,26 @@ Artes supports environment-specific configurations through environment variables
615
620
 
616
621
  | Option | Default Value | Description |
617
622
  | ------------- | ------------------------------ | ------------------------------------------------------ |
618
- | `device` | `""` | [Device List](./docs/emulationDevicesList.md) |
623
+ | `device` | `""` | [Device List](./docs/emulationDevicesList.md) |
619
624
 
620
625
 
621
- ## 📊 Report Generation
626
+ ## 📊 Reporting
622
627
 
623
628
  Artes can generate Allure reports. After running tests with the `-r` flag, the reports will be stored in the `report` folder in HTML format. You can view them in your browser after the tests complete.
624
629
 
630
+ ### Integration with Artes Reporting System
631
+
632
+ Artes has a built-in integration with the Artes Reporting System. By configuring the options below, you can automatically upload your test reports and keep your pipeline stages clean and organized.
633
+
634
+ | **Option** | **Default Value** | **Description** |
635
+ | ---------------- | ----------------------------- | ---------------------------------------------------------------------- |
636
+ | `uploadReport` | `false` | Automatically upload the report to Artes Reporting System after tests. |
637
+ | `reporterURL` | `""` | URL of the Artes Reporting System instance to upload the report to. |
638
+ | `projectName` | `"Artes Report"` | Name of the project in the Artes Reporting System. |
639
+ | `projectType` | `"Artes"` | Type/category of the project (e.g., UI, API). |
640
+ | `reportName` | `"Artes Report"` | Display name of the report in the Artes Reporting System. |
641
+ | `reportPath` | `"./report.zip"` | Path to the report zip file to be uploaded. |
642
+
625
643
  ---
626
644
 
627
645
  ## 🐳 Docker Image for CI/CD
@@ -638,7 +656,7 @@ To achieve the best video recording quality, use the following command:
638
656
  xvfb-run -a --server-args="-screen 0 3840x1180x24" --auto-servernum npx artes --width 1600 --height 900
639
657
  ```
640
658
 
641
- ### 🔬 CI/CD Executor on Report
659
+ ### CI/CD Executor on Report
642
660
 
643
661
  Artes automatically detects your CI/CD environment and displays executor information — pipeline name, build number, and a direct link to the build — on the generated report.
644
662
 
@@ -4,6 +4,7 @@
4
4
 
5
5
  - [Mouse Actions](#mouse-actions)
6
6
  - [Keyboard Actions](#keyboard-actions)
7
+ - [Browser Actions](#browser-actions)
7
8
  - [Page Actions](#page-actions)
8
9
  - [Frame Actions](#frame-actions)
9
10
  - [API Actions](#api-actions)
@@ -107,6 +108,30 @@
107
108
  - User releases `{string}`
108
109
  - User presses `{string}`
109
110
 
111
+ # Browser Actions
112
+
113
+ ## Cookie Actions
114
+
115
+ - User sets `{string}` cookies
116
+
117
+ ## Accessibility Actions
118
+
119
+ ### Full Page Checks
120
+ - User checks accessibility of current page
121
+ - User checks accessibility of `{string}` page
122
+
123
+ ### Element Checks
124
+ - User checks accessibility of `{string}` element
125
+ - User checks accessibility of `{string}` element on the `{string}` page
126
+
127
+ ### WCAG-Specific Checks
128
+ > For valid WCAG tags, refer to the [axe-core Tags Documentation](https://www.deque.com/axe/core-documentation/api-documentation/#axecore-tags)
129
+
130
+ - User checks accessibility of current page due to `{string}` WCAG
131
+ - User checks accessibility of `{string}` page due to `{string}` WCAG
132
+ - User checks accessibility of `{string}` element due to `{string}` WCAG
133
+ - User checks accessibility of `{string}` element on the `{string}` page due to `{string}` WCAG
134
+
110
135
  ---
111
136
 
112
137
  # Page Actions
package/executer.js CHANGED
@@ -18,6 +18,8 @@ const {
18
18
  findDuplicateTestNames,
19
19
  } = require("./src/helper/controller/findDuplicateTestNames");
20
20
  const { getEnvInfo } = require("artes/src/helper/controller/getEnvInfo");
21
+ const { uploadReport } = require("./src/helper/controller/reportUploader");
22
+
21
23
 
22
24
  const artesConfigPath = path.resolve(process.cwd(), "artes.config.js");
23
25
 
@@ -49,6 +51,11 @@ const flags = {
49
51
  customBrandName: args.includes("--brandName"),
50
52
  customReportName: args.includes("--reportName"),
51
53
  zip: args.includes("--zip"),
54
+ uploadReport: args.includes("--uploadReport"),
55
+ reporterURL: args.includes("--reporterURL"),
56
+ projectName: args.includes("--projectName"),
57
+ projectType: args.includes("--projectType"),
58
+ reportPath: args.includes("--reportPath"),
52
59
  features: args.includes("--features"),
53
60
  stepDef: args.includes("--stepDef"),
54
61
  tags: args.includes("--tags"),
@@ -73,6 +80,10 @@ const flags = {
73
80
 
74
81
  const env = getArgValue("--env");
75
82
  const vars = getArgValue("--saveVar");
83
+ const reporterURL = getArgValue("--reporterURL");
84
+ const projectType = getArgValue("--projectType");
85
+ const projectName = getArgValue("--projectName");
86
+ const reportPath = getArgValue("--reportPath");
76
87
  const logo = getArgValue("--logo");
77
88
  const brandName = getArgValue("--brandName");
78
89
  const reportName = getArgValue("--reportName");
@@ -173,7 +184,7 @@ flags.timeout ? (process.env.TIMEOUT = timeout) : "";
173
184
 
174
185
  flags.slowMo ? (process.env.SLOWMO = slowMo) : "";
175
186
 
176
- function main() {
187
+ async function main() {
177
188
  if (flags.help) return showHelp();
178
189
  if (flags.version) return showVersion();
179
190
  if (flags.create) return createProject(flags.createYes, flags.noDeps);
@@ -240,6 +251,16 @@ function main() {
240
251
  });
241
252
  }
242
253
 
254
+ if (flags.uploadReport || artesConfig.uploadReport) {
255
+ await uploadReport({
256
+ reporterURL: reporterURL || artesConfig.reporterURL,
257
+ projectName: projectName || artesConfig.projectName || "Artes Report",
258
+ projectType: projectType || artesConfig.projectType || "Artes",
259
+ reportName: reportName || artesConfig.reportName || "Artes Report",
260
+ reportPath: reportPath || artesConfig.reportPath || path.join(process.cwd(), "report.zip")
261
+ });
262
+ }
263
+
243
264
  cleanUp();
244
265
  process.exit(process.env.EXIT_CODE);
245
266
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "artes",
3
- "version": "1.5.10",
3
+ "version": "1.6.0",
4
4
  "description": "The simplest way to automate UI and API tests using Cucumber-style steps.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -29,6 +29,7 @@
29
29
  "dayjs": "1.11.13",
30
30
  "deasync": "^0.1.31",
31
31
  "playwright": "^1.58.2",
32
+ "@axe-core/playwright": "^4.11.1",
32
33
  "ffmpeg-static": "^5.3.0",
33
34
  "ffprobe-static": "^3.1.0",
34
35
  "pixelmatch": "^5.3.0",
@@ -0,0 +1,33 @@
1
+ const fs = require("fs");
2
+
3
+ async function uploadReport({
4
+ reporterURL,
5
+ projectName,
6
+ projectType,
7
+ reportName,
8
+ reportPath
9
+ }) {
10
+
11
+ const formData = new FormData();
12
+
13
+ const fileBuffer = fs.readFileSync(reportPath);
14
+ const fileBlob = new Blob([fileBuffer], { type: "application/x-zip-compressed" });
15
+ formData.append("file", fileBlob, "report.zip");
16
+ formData.append("name", reportName);
17
+ formData.append("project", projectName);
18
+ formData.append("type", projectType);
19
+
20
+ const response = await fetch(`${reporterURL}/api/report`, {
21
+ method: "POST",
22
+ body: formData,
23
+ });
24
+
25
+ const data = await response.json();
26
+ console.log("Report URL:", data.report.report_url);
27
+
28
+ return data;
29
+ }
30
+
31
+ module.exports = {
32
+ uploadReport
33
+ };
@@ -0,0 +1,52 @@
1
+ const EXACT_TAGS = new Set([
2
+ 'wcag2a', 'wcag2aa', 'wcag2aaa',
3
+ 'wcag21a', 'wcag21aa',
4
+ 'wcag22aa',
5
+ 'best-practice',
6
+ 'wcag2a-obsolete',
7
+ 'ACT',
8
+ 'section508',
9
+ 'TTv5',
10
+ 'EN-301-549',
11
+ 'RGAAv4',
12
+ 'experimental'
13
+ ]);
14
+
15
+ const PATTERN_TAGS = [
16
+ /^wcag\d{3,}$/,
17
+ /^section508\.\d+\.\d+$/,
18
+ /^TT\d+\.\d+$/,
19
+ /^EN-9\.\d+(\.\d+)*$/,
20
+ /^RGAA-\d+\.\d+\.\d+$/,
21
+ /^cat\..+$/
22
+ ];
23
+
24
+ const isValidTag = (tag) => {
25
+ if (EXACT_TAGS.has(tag)) return true;
26
+ return PATTERN_TAGS.some(pattern => pattern.test(tag));
27
+ };
28
+
29
+ const validateWCAGTags = (tags) => {
30
+ const normalized = tags.split(",").map(tag => tag.trim());
31
+
32
+ if (normalized.length === 0) {
33
+ throw new Error('At least one WCAG tag must be provided.');
34
+ }
35
+
36
+ const invalid = normalized.filter(tag => !isValidTag(tag));
37
+
38
+ if (invalid.length > 0) {
39
+ throw new Error(
40
+ `Invalid WCAG tag(s): "${invalid.join('", "')}"\n` +
41
+ `Valid tags: wcag2a, wcag2aa, wcag2aaa, wcag21a, wcag21aa, wcag22aa, ` +
42
+ `best-practice, wcag2a-obsolete, wcag111 (SC pattern), ACT, section508, ` +
43
+ `section508.x.x, TTv5, TT*.*, EN-301-549, EN-9.*, RGAAv4, RGAA-*.*.*, ` +
44
+ `experimental, cat.* `+
45
+ `For more information: https://www.deque.com/axe/core-documentation/api-documentation/#axecore-tags`
46
+ );
47
+ }
48
+
49
+ return normalized;
50
+ };
51
+
52
+ module.exports = { validateWCAGTags };
@@ -40,16 +40,31 @@ function showHelp() {
40
40
  📄 --singleFileReport Generate single file Allure report
41
41
  Usage: artes -r --singleFileReport
42
42
 
43
- 🗜️ --zip Zip the report folder after generation
43
+ 🗜️ --zip Zip the report folder after generation
44
44
  Usage: artes -r --zip
45
45
 
46
+ --uploadReport Upload the generated report to a Artes Reporting System
47
+ Usage: artes --uploadReport --reporterURL "https://example.com/upload"
48
+
49
+ --reporterURL URL of the Artes Reporting System to upload the report
50
+ Usage: artes --uploadReport --reporterURL "https://example.com/upload"
51
+
52
+ --projectName Name of the project in the Artes Reporting System (default: "Artes Report")
53
+ Usage: artes --uploadReport --reporterURL "https://example.com/upload" --projectName "My Project"
54
+
55
+ --projectType Type of the project (e.g., UI, API) for reporting purposes (default: "Artes")
56
+ Usage: artes --uploadReport --reporterURL "https://example.com/upload" --projectType "API"
57
+
58
+ --reportPath Path to the report zip or html file to be uploaded (default: ./report.zip)
59
+ Usage: artes --uploadReport --reporterURL "https://example.com/upload" --reportPath "./my_report.zip"
60
+
46
61
  🖼️ --logo Set a custom logo in the report sidebar
47
62
  Usage: artes --logo logo.png
48
63
 
49
64
  🏢 --brandName Set the brand name displayed next to the logo in the report sidebar
50
65
  Usage: artes --brandName 'My Company'
51
66
 
52
- 📄 --reportName Set the report name displayed on the summary widget
67
+ 📄 --reportName Report name displayed on the summary widget and in the Artes Reporting System
53
68
  Usage: artes --reportName 'Alma UI'
54
69
 
55
70
  📁 --features Specify one or more feature files' relative paths to run (comma-separated)
@@ -43,7 +43,7 @@ function createProject(createYes, noDeps) {
43
43
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
44
44
 
45
45
  const config = `module.exports = {
46
- headless: false, // Set to true for headless browser mode
46
+ headless: false, // Set to true for headless browser mode
47
47
 
48
48
  // Configuration options:
49
49
  // env: "", // string - Environment name for tests
@@ -56,11 +56,16 @@ function createProject(createYes, noDeps) {
56
56
  // timeout : 0, // number - Test timeout in seconds
57
57
  // slowMo: 0, // number - Slow down test execution (Default: 0 seconds)
58
58
  // parallel: 0, // number - Number of parallel workers
59
- // report: true // boolean - Generate report
60
- // zip: false // boolean - Generate zip of report
61
- // logo: "" // string - Custom logo for the report sidebar. Accepts an absolute path, a relative path, or a direct image URL
62
- // brandName: "" // string - Brand name displayed next to the logo in the report sidebar
63
- // reportName: "" // string - Report name displayed on the summary widget
59
+ // report: true, // boolean - Generate report
60
+ // zip: false, // boolean - Generate zip of report
61
+ // uploadReport: false, // boolean - Upload report to Artes Reporting System
62
+ // reporterURL: "", // string - URL of the Artes Reporting System
63
+ // projectName: "Artes Report", // string - Name of the project in the Artes Reporting System
64
+ // projectType: "Artes", // string - Type/category of the project (e.g., UI, API)
65
+ // reportPath: "./report.zip", // string - Path to the report zip file to be uploaded
66
+ // logo: "", // string - Custom logo for the report sidebar. Accepts an absolute path, a relative path, or a direct image URL
67
+ // brandName: "", // string - Brand name displayed next to the logo in the report sidebar
68
+ // reportName: "Artes Report", // string - Report name displayed on the summary widget and in the Artes Reporting System
64
69
  // reportSuccess: false, // boolean - Add screenshots and video records to report also for success test cases
65
70
  // trace: false, // boolean - Enable tracing
66
71
  // reportWithTrace: false, // boolean - Include trace in report
@@ -1,4 +1,16 @@
1
- const { context, selector, resolveVariable } = require("../imports/commons");
1
+ const { page: p } = require("artes/src/helper/stepFunctions/pageActions");
2
+ const {
3
+ context,
4
+ resolveVariable,
5
+ expect,
6
+ selector,
7
+ } = require("../imports/commons");
8
+ const { AxeBuilder } = require("@axe-core/playwright");
9
+ const {
10
+ validateWCAGTags,
11
+ } = require("artes/src/helper/controller/validateWCAGTags ");
12
+ require("allure-cucumberjs");
13
+ const allure = require("allure-js-commons");
2
14
 
3
15
  const browser = {
4
16
  setCookies: async (cookies) => {
@@ -15,6 +27,59 @@ const browser = {
15
27
 
16
28
  await context.browserContext.addCookies(cookieData);
17
29
  },
30
+ checkAccessibilityOfPage: async (page, url, element) => {
31
+ if (url) {
32
+ await p.navigateTo(url);
33
+ }
34
+
35
+ if (element) {
36
+ element = await selector(element);
37
+ await page.locator(element).waitFor();
38
+ }
39
+
40
+ const accessibilityScanResults = await new AxeBuilder({ page })
41
+ .include(element)
42
+ .analyze();
43
+ await allure.attachment(
44
+ "Accessibility Results",
45
+ JSON.stringify(accessibilityScanResults, null, 2),
46
+ "application/json",
47
+ );
48
+
49
+ try {
50
+ expect(accessibilityScanResults.violations).toEqual([]);
51
+ } catch (e) {
52
+ e.name = "AssertionError";
53
+ throw e;
54
+ }
55
+ },
56
+ checkAccessibilityOfPageDueToWCAG: async (page, url, element, tags) => {
57
+ if (url) {
58
+ await p.navigateTo(url);
59
+ }
60
+
61
+ if (element) {
62
+ element = await selector(element);
63
+ await page.locator(element).waitFor();
64
+ }
65
+ if (tags) {
66
+ tags = validateWCAGTags(tags);
67
+ }
68
+
69
+ expect(accessibilityScanResults.violations).toEqual([]);
70
+ await allure.attachment(
71
+ "Accessibility Results",
72
+ JSON.stringify(accessibilityScanResults, null, 2),
73
+ "application/json",
74
+ );
75
+
76
+ try {
77
+ expect(accessibilityScanResults.violations).toEqual([]);
78
+ } catch (e) {
79
+ e.name = "AssertionError";
80
+ throw e;
81
+ }
82
+ },
18
83
  };
19
84
 
20
85
  module.exports = {
@@ -1,7 +1,74 @@
1
- const { When } = require("../helper/imports/commons");
1
+ const { When, context } = require("../helper/imports/commons");
2
2
  const { browser } = require("../helper/stepFunctions/exporter");
3
3
 
4
4
  // User sets cookies in json format
5
5
  When("User sets {string} cookies", async function (cookies) {
6
6
  await browser.setCookies(cookies);
7
7
  });
8
+
9
+ When("User checks accessibility of current page", async function () {
10
+ await browser.checkAccessibilityOfPage(context.page, null, null);
11
+ });
12
+
13
+ When("User checks accessibility of {string} page", async function (url) {
14
+ await browser.checkAccessibilityOfPage(context.page, url, null);
15
+ });
16
+
17
+ When("User checks accessibility of {string} element", async function (element) {
18
+ await browser.checkAccessibilityOfPage(context.page, null, element);
19
+ });
20
+
21
+ When(
22
+ "User checks accessibility of {string} element on the {string} page",
23
+ async function (element, url) {
24
+ await browser.checkAccessibilityOfPage(context.page, url, element);
25
+ },
26
+ );
27
+
28
+ When(
29
+ "User checks accessibility of current page due to {string} WCAG",
30
+ async function (wcag) {
31
+ await browser.checkAccessibilityOfPageDueToWCAG(
32
+ context.page,
33
+ null,
34
+ null,
35
+ wcag,
36
+ );
37
+ },
38
+ );
39
+
40
+ When(
41
+ "User checks accessibility of {string} page due to {string} WCAG",
42
+ async function (url, wcag) {
43
+ await browser.checkAccessibilityOfPageDueToWCAG(
44
+ context.page,
45
+ url,
46
+ null,
47
+ wcag,
48
+ );
49
+ },
50
+ );
51
+
52
+ When(
53
+ "User checks accessibility of {string} element due to {string} WCAG",
54
+ async function (element, wcag) {
55
+ await browser.checkAccessibilityOfPageDueToWCAG(
56
+ context.page,
57
+ null,
58
+ element,
59
+ wcag,
60
+ );
61
+ },
62
+ );
63
+
64
+ When(
65
+ "User checks accessibility of {string} element on the {string} page due to {string} WCAG",
66
+ async function (element, url, wcag) {
67
+ await browser.checkAccessibilityOfPageDueToWCAG(
68
+ context.page,
69
+ url,
70
+ element,
71
+ wcag,
72
+ );
73
+ },
74
+ );