axe-playwright 1.2.3 → 2.0.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
@@ -6,7 +6,7 @@
6
6
  [![NPM release](https://img.shields.io/npm/v/axe-playwright.svg 'NPM release')](https://www.npmjs.com/package/axe-playwright)
7
7
  [![NPM Downloads](https://img.shields.io/npm/dt/axe-playwright.svg?style=flat-square)](https://www.npmjs.com/package/axe-playwright)
8
8
 
9
- [Axe](https://www.deque.com/axe/) is an accessibility testing engine for websites and other HTML-based user interfaces. This package provides simple axe analyser commands which you can incorporate in your [Playwright](https://www.npmjs.com/package/playwright) tests.
9
+ [Axe](https://www.deque.com/axe/) is an accessibility testing engine for websites and other HTML-based user interfaces. This package provides simple axe analyser commands which you can incorporate in your [Playwright](https://www.npmjs.com/package/playwright) tests. [Axe](https://www.deque.com/axe/) seamlessly functions across all Playwright browsers: Chromium, Firefox, and WebKit.
10
10
 
11
11
  ## Install and configure
12
12
 
@@ -118,16 +118,16 @@ The `detailedReport` key is a boolean whether to print the more detailed report
118
118
 
119
119
  The `verbose` key is a boolean to whether to print the message `No accessibility violations detected!` when there aren't accessibility violations present in the test. For the `DefaultTerminalReporter` this is true and for the `v2 Reporter` this is false.
120
120
 
121
+ ##### skipFailures (optional, defaults to false)
122
+
123
+ Disables assertions based on violations and only logs violations to the console output. If you set `skipFailures` as `true`, although accessibility check is not passed, your test will not fail. It will simply print the violations in the console, but will not make the test fail.
124
+
121
125
  ##### reporter (optional)
122
126
 
123
127
  A class instance that implements the `Reporter` interface or values `default`, `v2` and `html`. Custom reporter instances can be supplied to override default reporting behaviour dictated by `DefaultTerminalReporter` set by the value `default`. `v2` is the new TerminalReporter inspired by the reports from [jest-axe](https://github.com/nickcolley/jest-axe). `html` reporter will generate external HTML file.
124
128
 
125
129
  Note! `html` reporter will disable printed to logs violations.
126
130
 
127
- ##### skipFailures (optional, defaults to false)
128
-
129
- Disables assertions based on violations and only logs violations to the console output. If you set `skipFailures` as `true`, although accessibility check is not passed, your test will not fail. It will simply print the violations in the console, but will not make the test fail.
130
-
131
131
  ##### options (dedicated for axe-html-reporter)
132
132
 
133
133
  Options dedicated for HTML reporter.
@@ -305,7 +305,8 @@ await checkA11y(
305
305
  },
306
306
  },
307
307
  },
308
- true, 'default',
308
+ true,
309
+ 'html',
309
310
  {
310
311
  outputDirPath: 'results',
311
312
  outputDir: 'accessibility',
@@ -313,8 +314,29 @@ await checkA11y(
313
314
  }
314
315
  )
315
316
  ```
317
+ #### JUnit Report
316
318
 
317
-
319
+ ```
320
+ await checkA11y(
321
+ page,
322
+ 'form',
323
+ {
324
+ axeOptions: {
325
+ runOnly: {
326
+ type: 'tag',
327
+ values: ['wcag2a'],
328
+ },
329
+ },
330
+ },
331
+ true,
332
+ 'junit',
333
+ {
334
+ outputDirPath: 'results',
335
+ outputDir: 'accessibility',
336
+ reportFileName: 'accessibility-audit.xml',
337
+ },
338
+ )
339
+ ```
318
340
  ## Before you Go
319
341
 
320
342
  If it works for you , leave a [Star](https://github.com/abhinaba-ghosh/axe-playwright)! :star:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "axe-playwright",
3
- "version": "1.2.3",
3
+ "version": "2.0.0",
4
4
  "description": "Custom Playwright commands to inject axe-core and test for a11y",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -40,9 +40,11 @@
40
40
  "typescript": "^4.8.4"
41
41
  },
42
42
  "dependencies": {
43
- "picocolors": "^1.0.0",
43
+ "@types/junit-report-builder": "^3.0.0",
44
44
  "axe-core": "^4.5.1",
45
- "axe-html-reporter": "2.2.3"
45
+ "axe-html-reporter": "2.2.3",
46
+ "junit-report-builder": "^3.0.1",
47
+ "picocolors": "^1.0.0"
46
48
  },
47
49
  "repository": {
48
50
  "type": "git",
package/dist/index.d.ts DELETED
@@ -1,56 +0,0 @@
1
- import { Page } from 'playwright';
2
- import { AxeResults, ElementContext, Result, RunOptions } from 'axe-core';
3
- import DefaultTerminalReporter from './reporter/defaultTerminalReporter';
4
- import Reporter, { ConfigOptions, AxeOptions } from './types';
5
- import { Options } from 'axe-html-reporter';
6
- declare global {
7
- interface Window {
8
- axe: any;
9
- }
10
- }
11
- declare module 'axe-core' {
12
- interface Node {
13
- }
14
- }
15
- /**
16
- * Injects axe executable commands in the active window
17
- * @param page
18
- */
19
- export declare const injectAxe: (page: Page) => Promise<void>;
20
- /**
21
- * Configures axe runtime options
22
- * @param page
23
- * @param configurationOptions
24
- */
25
- export declare const configureAxe: (page: Page, configurationOptions?: ConfigOptions) => Promise<void>;
26
- /**
27
- * Runs axe-core tools on the relevant page and returns all results
28
- * @param page
29
- * @param context
30
- * @param options
31
- */
32
- export declare const getAxeResults: (page: Page, context?: ElementContext, options?: RunOptions) => Promise<AxeResults>;
33
- /**
34
- * Runs axe-core tools on the relevant page and returns all accessibility violations detected on the page
35
- * @param page
36
- * @param context
37
- * @param options
38
- */
39
- export declare const getViolations: (page: Page, context?: ElementContext, options?: RunOptions) => Promise<Result[]>;
40
- /**
41
- * Report violations given the reporter.
42
- * @param violations
43
- * @param reporter
44
- */
45
- export declare const reportViolations: (violations: Result[], reporter: Reporter) => Promise<void>;
46
- /**
47
- * Performs Axe validations
48
- * @param page
49
- * @param context
50
- * @param axeOptions
51
- * @param skipFailures
52
- * @param reporter
53
- * @param options
54
- */
55
- export declare const checkA11y: (page: Page, context?: ElementContext | undefined, axeOptions?: AxeOptions | undefined, skipFailures?: boolean, reporter?: Reporter | 'default' | 'html' | 'v2', options?: Options | undefined) => Promise<void>;
56
- export { DefaultTerminalReporter };
package/dist/index.js DELETED
@@ -1,131 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
- return new (P || (P = Promise))(function (resolve, reject) {
28
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
- step((generator = generator.apply(thisArg, _arguments || [])).next());
32
- });
33
- };
34
- var __importDefault = (this && this.__importDefault) || function (mod) {
35
- return (mod && mod.__esModule) ? mod : { "default": mod };
36
- };
37
- Object.defineProperty(exports, "__esModule", { value: true });
38
- exports.DefaultTerminalReporter = exports.checkA11y = exports.reportViolations = exports.getViolations = exports.getAxeResults = exports.configureAxe = exports.injectAxe = void 0;
39
- const fs = __importStar(require("fs"));
40
- const utils_1 = require("./utils");
41
- const defaultTerminalReporter_1 = __importDefault(require("./reporter/defaultTerminalReporter"));
42
- exports.DefaultTerminalReporter = defaultTerminalReporter_1.default;
43
- const terminalReporterV2_1 = __importDefault(require("./reporter/terminalReporterV2"));
44
- const axe_html_reporter_1 = require("axe-html-reporter");
45
- /**
46
- * Injects axe executable commands in the active window
47
- * @param page
48
- */
49
- const injectAxe = (page) => __awaiter(void 0, void 0, void 0, function* () {
50
- const axe = fs.readFileSync(require.resolve('axe-core/axe.min.js'), 'utf8');
51
- yield page.evaluate((axe) => window.eval(axe), axe);
52
- });
53
- exports.injectAxe = injectAxe;
54
- /**
55
- * Configures axe runtime options
56
- * @param page
57
- * @param configurationOptions
58
- */
59
- const configureAxe = (page, configurationOptions = {}) => __awaiter(void 0, void 0, void 0, function* () {
60
- yield page.evaluate((configOptions) => window.axe.configure(configOptions), configurationOptions);
61
- });
62
- exports.configureAxe = configureAxe;
63
- /**
64
- * Runs axe-core tools on the relevant page and returns all results
65
- * @param page
66
- * @param context
67
- * @param options
68
- */
69
- const getAxeResults = (page, context, options) => __awaiter(void 0, void 0, void 0, function* () {
70
- const result = yield page.evaluate(([context, options]) => {
71
- return window.axe.run(context || window.document, options);
72
- }, [context, options]);
73
- return result;
74
- });
75
- exports.getAxeResults = getAxeResults;
76
- /**
77
- * Runs axe-core tools on the relevant page and returns all accessibility violations detected on the page
78
- * @param page
79
- * @param context
80
- * @param options
81
- */
82
- const getViolations = (page, context, options) => __awaiter(void 0, void 0, void 0, function* () {
83
- const result = yield (0, exports.getAxeResults)(page, context, options);
84
- return result.violations;
85
- });
86
- exports.getViolations = getViolations;
87
- /**
88
- * Report violations given the reporter.
89
- * @param violations
90
- * @param reporter
91
- */
92
- const reportViolations = (violations, reporter) => __awaiter(void 0, void 0, void 0, function* () {
93
- yield reporter.report(violations);
94
- });
95
- exports.reportViolations = reportViolations;
96
- /**
97
- * Performs Axe validations
98
- * @param page
99
- * @param context
100
- * @param axeOptions
101
- * @param skipFailures
102
- * @param reporter
103
- * @param options
104
- */
105
- const checkA11y = (page, context = undefined, axeOptions = undefined, skipFailures = false, reporter = 'default', options = undefined) => __awaiter(void 0, void 0, void 0, function* () {
106
- var _a, _b, _c;
107
- const violations = yield (0, exports.getViolations)(page, context, axeOptions === null || axeOptions === void 0 ? void 0 : axeOptions.axeOptions);
108
- const impactedViolations = (0, utils_1.getImpactedViolations)(violations, axeOptions === null || axeOptions === void 0 ? void 0 : axeOptions.includedImpacts);
109
- let reporterWithOptions;
110
- if (reporter === 'default') {
111
- reporterWithOptions = new defaultTerminalReporter_1.default(axeOptions === null || axeOptions === void 0 ? void 0 : axeOptions.detailedReport, (_a = axeOptions === null || axeOptions === void 0 ? void 0 : axeOptions.detailedReportOptions) === null || _a === void 0 ? void 0 : _a.html, (_b = axeOptions === null || axeOptions === void 0 ? void 0 : axeOptions.verbose) !== null && _b !== void 0 ? _b : true);
112
- }
113
- else if (reporter === 'v2') {
114
- reporterWithOptions = new terminalReporterV2_1.default((_c = axeOptions === null || axeOptions === void 0 ? void 0 : axeOptions.verbose) !== null && _c !== void 0 ? _c : false);
115
- }
116
- else if (reporter === 'html') {
117
- if (violations.length > 0) {
118
- yield (0, axe_html_reporter_1.createHtmlReport)({ results: { violations }, options });
119
- }
120
- else
121
- console.log("There were no violations to save in report");
122
- }
123
- else {
124
- reporterWithOptions = reporter;
125
- }
126
- if (reporter !== 'html')
127
- yield (0, exports.reportViolations)(impactedViolations, reporterWithOptions);
128
- if (reporter === 'v2' || reporter !== 'html')
129
- (0, utils_1.testResultDependsOnViolations)(impactedViolations, skipFailures);
130
- });
131
- exports.checkA11y = checkA11y;
@@ -1,9 +0,0 @@
1
- import Reporter from '../types';
2
- import { Result } from 'axe-core';
3
- export default class DefaultTerminalReporter implements Reporter {
4
- protected detailedReport: boolean | undefined;
5
- protected includeHtml: boolean | undefined;
6
- protected verbose: boolean | undefined;
7
- constructor(detailedReport: boolean | undefined, includeHtml: boolean | undefined, verbose: boolean | undefined);
8
- report(violations: Result[]): Promise<void>;
9
- }
@@ -1,52 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- const utils_1 = require("../utils");
13
- class DefaultTerminalReporter {
14
- constructor(detailedReport, includeHtml, verbose) {
15
- this.detailedReport = detailedReport;
16
- this.includeHtml = includeHtml;
17
- this.verbose = verbose;
18
- }
19
- report(violations) {
20
- return __awaiter(this, void 0, void 0, function* () {
21
- const violationData = violations.map(({ id, impact, description, nodes }) => {
22
- return {
23
- id,
24
- impact,
25
- description,
26
- nodes: nodes.length,
27
- };
28
- });
29
- if (violationData.length > 0) {
30
- // summary
31
- console.table(violationData);
32
- if (this.detailedReport) {
33
- const nodeViolations = (0, utils_1.describeViolations)(violations).map(({ target, html, violations }) => {
34
- if (!this.includeHtml) {
35
- return {
36
- target,
37
- violations,
38
- };
39
- }
40
- return { target, html, violations };
41
- });
42
- // per node
43
- console.table(nodeViolations);
44
- }
45
- }
46
- else {
47
- this.verbose && console.log(`No accessibility violations detected!`);
48
- }
49
- });
50
- }
51
- }
52
- exports.default = DefaultTerminalReporter;
@@ -1,7 +0,0 @@
1
- import Reporter from '../types';
2
- import { Result } from 'axe-core';
3
- export default class TerminalReporterV2 implements Reporter {
4
- protected verbose: boolean | undefined;
5
- constructor(verbose: boolean | undefined);
6
- report(violations: Result[]): Promise<void>;
7
- }
@@ -1,69 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- const assert_1 = __importDefault(require("assert"));
16
- const picocolors_1 = __importDefault(require("picocolors"));
17
- class TerminalReporterV2 {
18
- constructor(verbose) {
19
- this.verbose = verbose;
20
- }
21
- report(violations) {
22
- return __awaiter(this, void 0, void 0, function* () {
23
- const lineBreak = '\n\n';
24
- const message = violations.length === 0
25
- ? 'No accessibility violations detected!'
26
- : `Found ${violations.length} accessibility violations: \n`;
27
- const horizontalLine = picocolors_1.default.bold('-'.repeat(message.length));
28
- const reporter = (violations) => {
29
- if (violations.length === 0) {
30
- return [];
31
- }
32
- return violations
33
- .map((violation) => {
34
- const errorBody = violation.nodes
35
- .map((node) => {
36
- const selector = node.target.join(', ');
37
- const expectedText = `Expected the HTML found at $('${selector}') to have no violations:` +
38
- '\n';
39
- return (picocolors_1.default.bold(expectedText) +
40
- picocolors_1.default.gray(node.html) +
41
- lineBreak +
42
- `Received:\n` +
43
- picocolors_1.default.red(`${violation.help} (${violation.id})`) +
44
- lineBreak +
45
- picocolors_1.default.bold(picocolors_1.default.yellow(node.failureSummary)) +
46
- lineBreak +
47
- (violation.helpUrl
48
- ? `You can find more information on this issue here: \n${picocolors_1.default.bold(picocolors_1.default.blue(violation.helpUrl))}`
49
- : '') +
50
- '\n' +
51
- horizontalLine);
52
- })
53
- .join(lineBreak);
54
- return errorBody;
55
- })
56
- .join(lineBreak);
57
- };
58
- const formatedViolations = reporter(violations);
59
- const pass = formatedViolations.length === 0;
60
- if (pass) {
61
- this.verbose && console.log(message);
62
- }
63
- else {
64
- assert_1.default.fail(message + horizontalLine + '\n' + formatedViolations);
65
- }
66
- });
67
- }
68
- }
69
- exports.default = TerminalReporterV2;
package/dist/types.d.ts DELETED
@@ -1,45 +0,0 @@
1
- import { Result, Check, ImpactValue, Locale, Rule, RunOptions } from 'axe-core';
2
- export interface NodeViolation {
3
- target: string;
4
- html: string;
5
- violations: string;
6
- }
7
- export interface Aggregate {
8
- [key: string]: {
9
- target: string;
10
- html: string;
11
- violations: number[];
12
- };
13
- }
14
- export default interface Reporter {
15
- report(violations: Result[]): Promise<void>;
16
- }
17
- export interface axeOptionsConfig {
18
- axeOptions?: RunOptions;
19
- }
20
- export interface ConfigOptions {
21
- branding?: {
22
- brand?: string;
23
- application?: string;
24
- };
25
- reporter?: 'v1' | 'v2' | 'no-passes';
26
- checks?: Check[];
27
- rules?: Rule[];
28
- locale?: Locale;
29
- axeVersion?: string;
30
- }
31
- /**
32
- * Implement this interface to be able to specific custom reporting behaviour for checkA11y method.
33
- * @see checkA11y
34
- */
35
- export default interface Reporter {
36
- report(violations: Result[]): Promise<void>;
37
- }
38
- export type AxeOptions = {
39
- includedImpacts?: ImpactValue[];
40
- detailedReport?: boolean;
41
- detailedReportOptions?: {
42
- html?: boolean;
43
- };
44
- verbose?: boolean;
45
- } & axeOptionsConfig;
package/dist/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
package/dist/utils.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import { NodeViolation } from './types';
2
- import { ImpactValue, Result } from 'axe-core';
3
- export declare const getImpactedViolations: (violations: Result[], includedImpacts?: ImpactValue[]) => Result[];
4
- export declare const testResultDependsOnViolations: (violations: Result[], skipFailures: boolean) => void;
5
- export declare const describeViolations: (violations: Result[]) => NodeViolation[];
package/dist/utils.js DELETED
@@ -1,49 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.describeViolations = exports.testResultDependsOnViolations = exports.getImpactedViolations = void 0;
7
- const assert_1 = __importDefault(require("assert"));
8
- const getImpactedViolations = (violations, includedImpacts = []) => {
9
- return Array.isArray(includedImpacts) && includedImpacts.length
10
- ? violations.filter((v) => v.impact && includedImpacts.includes(v.impact))
11
- : violations;
12
- };
13
- exports.getImpactedViolations = getImpactedViolations;
14
- const testResultDependsOnViolations = (violations, skipFailures) => {
15
- if (!skipFailures) {
16
- assert_1.default.strictEqual(violations.length, 0, `${violations.length} accessibility violation${violations.length === 1 ? '' : 's'} ${violations.length === 1 ? 'was' : 'were'} detected`);
17
- }
18
- else {
19
- if (violations.length) {
20
- console.warn({
21
- name: 'a11y violation summary',
22
- message: `${violations.length} accessibility violation${violations.length === 1 ? '' : 's'} ${violations.length === 1 ? 'was' : 'were'} detected`,
23
- });
24
- }
25
- }
26
- };
27
- exports.testResultDependsOnViolations = testResultDependsOnViolations;
28
- const describeViolations = (violations) => {
29
- const aggregate = {};
30
- violations.map(({ nodes }, index) => {
31
- nodes.forEach(({ target, html }) => {
32
- const key = JSON.stringify(target) + html;
33
- if (aggregate[key]) {
34
- aggregate[key].violations.push(index);
35
- }
36
- else {
37
- aggregate[key] = {
38
- target: JSON.stringify(target),
39
- html,
40
- violations: [index],
41
- };
42
- }
43
- });
44
- });
45
- return Object.values(aggregate).map(({ target, html, violations }) => {
46
- return { target, html, violations: JSON.stringify(violations) };
47
- });
48
- };
49
- exports.describeViolations = describeViolations;