axe-playwright 1.1.11 → 1.2.1

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.The idea is highly inspired by [Andy Van Slaars](https://github.com/avanslaars) cypress-axe project.
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.
10
10
 
11
11
  ## Install and configure
12
12
 
@@ -95,11 +95,11 @@ The `page` instance of `playwright`.
95
95
 
96
96
  Defines the scope of the analysis - the part of the DOM that you would like to analyze. This will typically be the document or a specific selector such as class name, ID, selector, etc.
97
97
 
98
- ##### options (optional)
98
+ ##### axeOptions (optional)
99
99
 
100
100
  Set of options passed into rules or checks, temporarily modifying them. This contrasts with axe.configure, which is more permanent.
101
101
 
102
- The keys consist of [those accepted by `axe.run`'s options argument](https://www.deque.com/axe/documentation/api-documentation/#parameters-axerun) as well as custom `includedImpacts`, `detailedReport`, and `detailedReportOptions` keys.
102
+ The keys consist of [those accepted by `axe.run`'s options argument](https://www.deque.com/axe/documentation/api-documentation/#parameters-axerun) as well as custom `includedImpacts`, `detailedReport`, `verbose`, and `detailedReportOptions` keys.
103
103
 
104
104
  The `includedImpacts` key is an array of strings that map to `impact` levels in violations. Specifying this array will only include violations where the impact matches one of the included values. Possible impact values are "minor", "moderate", "serious", or "critical".
105
105
 
@@ -116,14 +116,21 @@ The `detailedReport` key is a boolean whether to print the more detailed report
116
116
  }
117
117
  ```
118
118
 
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
+
119
121
  ##### reporter (optional)
120
122
 
121
- A class instance that implements the `Reporter` interface. Custom reporter instances can be supplied to override default reporting behaviour dictated by `DefaultTerminalReporter`.
123
+ A class instance that implements the `Reporter` interface or values `default` and `v2`. 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).
122
124
 
123
125
  ##### skipFailures (optional, defaults to false)
124
126
 
125
127
  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.
126
128
 
129
+ ##### options (dedicated for axe-html-reporter)
130
+
131
+ Options dedicated for HTML reporter.
132
+ [axe-html-reporter](https://www.npmjs.com/package/axe-html-reporter)
133
+
127
134
  ### getAxeResults
128
135
 
129
136
  This will run axe against the document at the point in which it is called, then returns the full set of results as reported by `axe.run`.
@@ -213,11 +220,9 @@ describe('Playwright web page accessibility test', () => {
213
220
 
214
221
  it('gets and reports a11y for the specific element', async () => {
215
222
  const violations = await getViolations(page, 'input[name="password"]', {
216
- axeOptions: {
217
- runOnly: {
218
- type: 'tag',
219
- values: ['wcag2a'],
220
- },
223
+ runOnly: {
224
+ type: 'tag',
225
+ values: ['wcag2a'],
221
226
  },
222
227
  })
223
228
 
@@ -280,6 +285,34 @@ describe('Playwright web page accessibility test', () => {
280
285
 
281
286
  ![Detailed Report with HTML](./docs/detailed-report-html-example.png)
282
287
 
288
+ #### HTML Report
289
+
290
+ Thanks to [axe-html-reporter](https://www.npmjs.com/package/axe-html-reporter) you can generate HTML report(s).
291
+ From default HTML file(s) will be generated under `/artifacts/accessibilityReport.html`.
292
+ Report's options can customized from `checkAlly` level:
293
+
294
+ ```
295
+ await checkA11y(
296
+ page,
297
+ 'form',
298
+ {
299
+ axeOptions: {
300
+ runOnly: {
301
+ type: 'tag',
302
+ values: ['wcag2a'],
303
+ },
304
+ },
305
+ },
306
+ true, 'default',
307
+ {
308
+ outputDirPath: 'results',
309
+ outputDir: 'accessibility',
310
+ reportFileName: 'accessibility-audit.html'
311
+ }
312
+ )
313
+ ```
314
+
315
+
283
316
  ## Before you Go
284
317
 
285
318
  If it works for you , leave a [Star](https://github.com/abhinaba-ghosh/axe-playwright)! :star:
@@ -0,0 +1,56 @@
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' | 'v2', options?: Options | undefined) => Promise<void>;
56
+ export { DefaultTerminalReporter };
package/dist/index.js CHANGED
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[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);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -31,10 +35,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
31
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
32
36
  };
33
37
  Object.defineProperty(exports, "__esModule", { value: true });
34
- exports.checkA11y = exports.reportViolations = exports.getViolations = exports.getAxeResults = exports.configureAxe = exports.injectAxe = void 0;
38
+ exports.DefaultTerminalReporter = exports.checkA11y = exports.reportViolations = exports.getViolations = exports.getAxeResults = exports.configureAxe = exports.injectAxe = void 0;
35
39
  const fs = __importStar(require("fs"));
36
40
  const utils_1 = require("./utils");
37
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");
38
45
  /**
39
46
  * Injects axe executable commands in the active window
40
47
  * @param page
@@ -73,7 +80,7 @@ exports.getAxeResults = getAxeResults;
73
80
  * @param options
74
81
  */
75
82
  const getViolations = (page, context, options) => __awaiter(void 0, void 0, void 0, function* () {
76
- const result = yield exports.getAxeResults(page, context, options);
83
+ const result = yield (0, exports.getAxeResults)(page, context, options);
77
84
  return result.violations;
78
85
  });
79
86
  exports.getViolations = getViolations;
@@ -90,19 +97,32 @@ exports.reportViolations = reportViolations;
90
97
  * Performs Axe validations
91
98
  * @param page
92
99
  * @param context
93
- * @param options
100
+ * @param axeOptions
94
101
  * @param skipFailures
95
102
  * @param reporter
103
+ * @param options
96
104
  */
97
- const checkA11y = (page, context, options, skipFailures, reporter) => __awaiter(void 0, void 0, void 0, function* () {
98
- var _a;
99
- if (context === void 0) { context = undefined; }
100
- if (options === void 0) { options = undefined; }
101
- if (skipFailures === void 0) { skipFailures = false; }
102
- if (reporter === void 0) { reporter = new defaultTerminalReporter_1.default(options === null || options === void 0 ? void 0 : options.detailedReport, (_a = options === null || options === void 0 ? void 0 : options.detailedReportOptions) === null || _a === void 0 ? void 0 : _a.html); }
103
- const violations = yield exports.getViolations(page, context, options === null || options === void 0 ? void 0 : options.axeOptions);
104
- const impactedViolations = utils_1.getImpactedViolations(violations, options === null || options === void 0 ? void 0 : options.includedImpacts);
105
- yield exports.reportViolations(impactedViolations, reporter);
106
- utils_1.testResultDependsOnViolations(impactedViolations, skipFailures);
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
+ if (violations.length > 0) {
109
+ yield (0, axe_html_reporter_1.createHtmlReport)({ results: { violations }, options });
110
+ }
111
+ else
112
+ console.log("There were no violations to save in report");
113
+ const impactedViolations = (0, utils_1.getImpactedViolations)(violations, axeOptions === null || axeOptions === void 0 ? void 0 : axeOptions.includedImpacts);
114
+ let reporterWithOptions;
115
+ if (reporter === 'default') {
116
+ 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);
117
+ }
118
+ else if (reporter === 'v2') {
119
+ reporterWithOptions = new terminalReporterV2_1.default((_c = axeOptions === null || axeOptions === void 0 ? void 0 : axeOptions.verbose) !== null && _c !== void 0 ? _c : false);
120
+ }
121
+ else {
122
+ reporterWithOptions = reporter;
123
+ }
124
+ yield (0, exports.reportViolations)(impactedViolations, reporterWithOptions);
125
+ if (reporter !== 'v2')
126
+ (0, utils_1.testResultDependsOnViolations)(impactedViolations, skipFailures);
107
127
  });
108
128
  exports.checkA11y = checkA11y;
@@ -0,0 +1,9 @@
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
+ }
@@ -11,9 +11,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const utils_1 = require("../utils");
13
13
  class DefaultTerminalReporter {
14
- constructor(detailedReport, includeHtml) {
14
+ constructor(detailedReport, includeHtml, verbose) {
15
15
  this.detailedReport = detailedReport;
16
16
  this.includeHtml = includeHtml;
17
+ this.verbose = verbose;
17
18
  }
18
19
  report(violations) {
19
20
  return __awaiter(this, void 0, void 0, function* () {
@@ -29,7 +30,7 @@ class DefaultTerminalReporter {
29
30
  // summary
30
31
  console.table(violationData);
31
32
  if (this.detailedReport) {
32
- const nodeViolations = utils_1.describeViolations(violations).map(({ target, html, violations }) => {
33
+ const nodeViolations = (0, utils_1.describeViolations)(violations).map(({ target, html, violations }) => {
33
34
  if (!this.includeHtml) {
34
35
  return {
35
36
  target,
@@ -43,7 +44,7 @@ class DefaultTerminalReporter {
43
44
  }
44
45
  }
45
46
  else {
46
- console.log(`No accessibility violations detected!`);
47
+ this.verbose && console.log(`No accessibility violations detected!`);
47
48
  }
48
49
  });
49
50
  }
@@ -0,0 +1,7 @@
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
+ }
@@ -0,0 +1,69 @@
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;
@@ -0,0 +1,45 @@
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;
@@ -0,0 +1,5 @@
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/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "axe-playwright",
3
- "version": "1.1.11",
3
+ "version": "1.2.1",
4
4
  "description": "Custom Playwright commands to inject axe-core and test for a11y",
5
5
  "main": "dist/index.js",
6
- "types": "index.d.ts",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist/**/*",
9
+ "README.md"
10
+ ],
7
11
  "keywords": [
8
12
  "a11y",
9
13
  "accessibility",
@@ -20,24 +24,25 @@
20
24
  "release": "npm cache clean --force && npm version patch && npm publish --force"
21
25
  },
22
26
  "peerDependencies": {
23
- "playwright-core": ">1.0.0"
27
+ "playwright": ">1.0.0"
24
28
  },
25
29
  "author": "Abhinaba Ghosh",
26
30
  "license": "MIT",
27
31
  "devDependencies": {
28
- "@types/is-ci": "^3.0.0",
29
- "@types/jest": "^27.0.3",
30
- "@types/node": "^17.0.4",
31
- "jest": "^26.6.3",
32
- "jest-each": "^27.0.2",
33
- "jest-playwright-preset": "^1.3.1",
34
- "playwright": "^1.1.1",
35
- "prettier": "^2.0.5",
36
- "ts-jest": "^26.5.0",
37
- "typescript": "^4.1.3"
32
+ "@types/jest": "^28.1.1",
33
+ "@types/node": "^18.11.9",
34
+ "jest": "^28.1.3",
35
+ "jest-each": "^28.1.3",
36
+ "jest-playwright-preset": "^2.0.0",
37
+ "playwright": "^1.27.1",
38
+ "prettier": "^2.7.1",
39
+ "ts-jest": "^28.0.8",
40
+ "typescript": "^4.8.4"
38
41
  },
39
42
  "dependencies": {
40
- "axe-core": "^4.0.1"
43
+ "picocolors": "^1.0.0",
44
+ "axe-core": "^4.5.1",
45
+ "axe-html-reporter": "2.2.3"
41
46
  },
42
47
  "repository": {
43
48
  "type": "git",
@@ -1,19 +0,0 @@
1
- version: 2
2
- jobs:
3
- build:
4
- docker:
5
- - image: qawolf/playwright-ci:v1.0.0
6
- steps:
7
- - checkout
8
-
9
- - run:
10
- command: npm install
11
-
12
- - run:
13
- command: |
14
- # # Start local server
15
- # npm run start &
16
- # npx wait-on http://localhost:3000
17
- # replace below with command you want to run, example for running a script below
18
- # node myScript.js
19
- npm test
@@ -1,12 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: npm
4
- directory: "/"
5
- schedule:
6
- interval: daily
7
- time: "23:30"
8
- open-pull-requests-limit: 10
9
- ignore:
10
- - dependency-name: "@types/node"
11
- versions:
12
- - 15.0.0
package/index.d.ts DELETED
@@ -1,93 +0,0 @@
1
- import { AxeResults, Check, ElementContext, ImpactValue, Locale, Result, Rule, RunOptions } from 'axe-core'
2
- import { Page } from 'playwright'
3
-
4
- export interface axeOptionsConfig {
5
- axeOptions: RunOptions
6
- }
7
-
8
- export interface ConfigOptions {
9
- branding?: {
10
- brand?: string
11
- application?: string
12
- }
13
- reporter?: 'v1' | 'v2' | 'no-passes'
14
- checks?: Check[]
15
- rules?: Rule[]
16
- locale?: Locale
17
- axeVersion?: string
18
- }
19
-
20
- /**
21
- * Implement this interface to be able to specific custom reporting behaviour for checkA11y method.
22
- * @see checkA11y
23
- */
24
- export default interface Reporter {
25
- report(violations: Result[]): Promise<void>
26
- }
27
-
28
- /**
29
- * Default implementation of a reporter which prints a summary to the console.
30
- */
31
- export class DefaultTerminalReporter implements Reporter {
32
- constructor(detailedReport: boolean | undefined, includeHtml: boolean | undefined)
33
- report(violations: Result[]): Promise<void>
34
- }
35
-
36
- export type Options = {
37
- includedImpacts?: ImpactValue[]
38
- detailedReport?: boolean
39
- detailedReportOptions?: { html?: boolean }
40
- } & axeOptionsConfig
41
-
42
- declare module 'axe-core' {
43
- interface Node {}
44
- }
45
-
46
- /**
47
- * Injects axe into browser-context
48
- */
49
- export function injectAxe(page: Page): Promise<void>
50
-
51
- /**
52
- * Performs accessibility checks in the web page
53
- * @param page
54
- * @param context
55
- * @param options
56
- * @param skipFailures
57
- */
58
- export function checkA11y(
59
- page: Page,
60
- context?: ElementContext,
61
- options?: Options,
62
- skipFailures?: boolean,
63
- ): Promise<void>
64
-
65
- /**
66
- * configure different axe configurations
67
- * @param page
68
- * @param options
69
- */
70
- export function configureAxe(page: Page, options?: ConfigOptions): Promise<void>
71
-
72
- /**
73
- * Runs axe-core tools on the relevant page and returns all results
74
- * @param page
75
- * @param context
76
- * @param options
77
- */
78
- export function getAxeResults(page: Page, context?: ElementContext, options?: RunOptions): Promise<AxeResults>
79
-
80
- /**
81
- * Runs axe-core tools on the relevant page and returns all accessibility violations detected on the page
82
- * @param page
83
- * @param context
84
- * @param options
85
- */
86
- export function getViolations(page: Page, context?: ElementContext, options?: RunOptions): Promise<Result[]>
87
-
88
- /**
89
- * Report violations given the reporter.
90
- * @param violations
91
- * @param reporter
92
- */
93
- export function reportViolations(violations: Result[], reporter: Reporter): Promise<void>
package/jest.config.js DELETED
@@ -1,10 +0,0 @@
1
- module.exports = {
2
- preset: 'jest-playwright-preset',
3
- testEnvironment: 'node',
4
- testMatch: ['**/tests/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[tj]s?(x)'],
5
- testPathIgnorePatterns: ['/node_modules/'],
6
- testTimeout: 30000,
7
- transform: {
8
- '^.+\\.tsx?$': 'ts-jest',
9
- },
10
- }
package/src/index.ts DELETED
@@ -1,115 +0,0 @@
1
- import { Page } from 'playwright'
2
- import * as fs from 'fs'
3
- import { AxeResults, ElementContext, Result, RunOptions, Spec } from 'axe-core'
4
- import { ConfigOptions, Options } from '../index'
5
- import { getImpactedViolations, testResultDependsOnViolations } from './utils'
6
- import DefaultTerminalReporter from './reporter/defaultTerminalReporter'
7
- import Reporter from './types'
8
-
9
- declare global {
10
- interface Window {
11
- axe: any
12
- }
13
- }
14
-
15
- /**
16
- * Injects axe executable commands in the active window
17
- * @param page
18
- */
19
- export const injectAxe = async (page: Page): Promise<void> => {
20
- const axe: string = fs.readFileSync(
21
- require.resolve('axe-core/axe.min.js'),
22
- 'utf8',
23
- )
24
- await page.evaluate((axe: string) => window.eval(axe), axe)
25
- }
26
-
27
- /**
28
- * Configures axe runtime options
29
- * @param page
30
- * @param configurationOptions
31
- */
32
- export const configureAxe = async (
33
- page: Page,
34
- configurationOptions: ConfigOptions = {},
35
- ): Promise<void> => {
36
- await page.evaluate(
37
- (configOptions: Spec) => window.axe.configure(configOptions),
38
- configurationOptions as Spec,
39
- )
40
- }
41
-
42
- /**
43
- * Runs axe-core tools on the relevant page and returns all results
44
- * @param page
45
- * @param context
46
- * @param options
47
- */
48
- export const getAxeResults = async (
49
- page: Page,
50
- context?: ElementContext,
51
- options?: RunOptions,
52
- ): Promise<AxeResults> => {
53
- const result = await page.evaluate(
54
- ([context, options]) => {
55
- return window.axe.run(context || window.document, options)
56
- },
57
- [context, options],
58
- )
59
-
60
- return result
61
- }
62
-
63
- /**
64
- * Runs axe-core tools on the relevant page and returns all accessibility violations detected on the page
65
- * @param page
66
- * @param context
67
- * @param options
68
- */
69
- export const getViolations = async (
70
- page: Page,
71
- context?: ElementContext,
72
- options?: RunOptions,
73
- ): Promise<Result[]> => {
74
- const result = await getAxeResults(page, context, options)
75
- return result.violations
76
- }
77
-
78
- /**
79
- * Report violations given the reporter.
80
- * @param violations
81
- * @param reporter
82
- */
83
- export const reportViolations = async (violations: Result[], reporter: Reporter): Promise<void> => {
84
- await reporter.report(violations)
85
- }
86
-
87
- /**
88
- * Performs Axe validations
89
- * @param page
90
- * @param context
91
- * @param options
92
- * @param skipFailures
93
- * @param reporter
94
- */
95
- export const checkA11y = async (
96
- page: Page,
97
- context: ElementContext | undefined = undefined,
98
- options: Options | undefined = undefined,
99
- skipFailures: boolean = false,
100
- reporter: Reporter = new DefaultTerminalReporter(options?.detailedReport, options?.detailedReportOptions?.html),
101
- ): Promise<void> => {
102
- const violations = await getViolations(page, context, options?.axeOptions)
103
-
104
- const impactedViolations = getImpactedViolations(
105
- violations,
106
- options?.includedImpacts,
107
- )
108
-
109
- await reportViolations(
110
- impactedViolations,
111
- reporter,
112
- )
113
-
114
- testResultDependsOnViolations(impactedViolations, skipFailures)
115
- }
@@ -1,43 +0,0 @@
1
- import Reporter from '../types'
2
- import { Result } from 'axe-core'
3
- import { describeViolations } from '../utils'
4
-
5
- export default class DefaultTerminalReporter implements Reporter {
6
- constructor(
7
- protected detailedReport: boolean | undefined,
8
- protected includeHtml: boolean | undefined,
9
- ) {}
10
-
11
- async report(violations: Result[]): Promise<void> {
12
- const violationData = violations.map(({ id, impact, description, nodes }) => {
13
- return {
14
- id,
15
- impact,
16
- description,
17
- nodes: nodes.length,
18
- }
19
- })
20
-
21
- if (violationData.length > 0) {
22
- // summary
23
- console.table(violationData)
24
- if (this.detailedReport) {
25
- const nodeViolations = describeViolations(violations).map(
26
- ({ target, html, violations }) => {
27
- if (!this.includeHtml) {
28
- return {
29
- target,
30
- violations,
31
- }
32
- }
33
- return { target, html, violations }
34
- },
35
- )
36
- // per node
37
- console.table(nodeViolations)
38
- }
39
- } else {
40
- console.log(`No accessibility violations detected!`)
41
- }
42
- }
43
- }
package/src/types.ts DELETED
@@ -1,19 +0,0 @@
1
- import { Result } from 'axe-core'
2
-
3
- export interface NodeViolation {
4
- target: string
5
- html: string
6
- violations: string
7
- }
8
-
9
- export interface Aggregate {
10
- [key: string]: {
11
- target: string
12
- html: string
13
- violations: number[]
14
- }
15
- }
16
-
17
- export default interface Reporter {
18
- report(violations: Result[]): Promise<void>
19
- }
package/src/utils.ts DELETED
@@ -1,61 +0,0 @@
1
- import { Aggregate, NodeViolation } from './types'
2
- import { ImpactValue, Result } from 'axe-core'
3
- import assert from 'assert'
4
-
5
- export const getImpactedViolations = (
6
- violations: Result[],
7
- includedImpacts: ImpactValue[] = [],
8
- ): Result[] => {
9
- return Array.isArray(includedImpacts) && includedImpacts.length
10
- ? violations.filter(
11
- (v: Result) => v.impact && includedImpacts.includes(v.impact),
12
- )
13
- : violations
14
- }
15
-
16
- export const testResultDependsOnViolations = (
17
- violations: Result[],
18
- skipFailures: boolean,
19
- ) => {
20
- if (!skipFailures) {
21
- assert.strictEqual(
22
- violations.length,
23
- 0,
24
- `${violations.length} accessibility violation${
25
- violations.length === 1 ? '' : 's'
26
- } ${violations.length === 1 ? 'was' : 'were'} detected`,
27
- )
28
- } else {
29
- if (violations.length) {
30
- console.warn({
31
- name: 'a11y violation summary',
32
- message: `${violations.length} accessibility violation${
33
- violations.length === 1 ? '' : 's'
34
- } ${violations.length === 1 ? 'was' : 'were'} detected`,
35
- })
36
- }
37
- }
38
- }
39
-
40
- export const describeViolations = (violations: Result[]): NodeViolation[] => {
41
- const aggregate: Aggregate = {}
42
-
43
- violations.map(({ nodes }, index) => {
44
- nodes.forEach(({ target, html }) => {
45
- const key = JSON.stringify(target) + html
46
-
47
- if (aggregate[key]) {
48
- aggregate[key].violations.push(index)
49
- } else {
50
- aggregate[key] = {
51
- target: JSON.stringify(target),
52
- html,
53
- violations: [index],
54
- }
55
- }
56
- })
57
- })
58
- return Object.values(aggregate).map(({ target, html, violations }) => {
59
- return { target, html, violations: JSON.stringify(violations) }
60
- })
61
- }
package/tsconfig.json DELETED
@@ -1,17 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "es6",
4
- "module": "commonjs",
5
- "strict": true,
6
- "declaration": false,
7
- "rootDir": "src",
8
- "moduleResolution": "node",
9
- "typeRoots": ["node_modules/@types"],
10
- "esModuleInterop": true,
11
- "outDir": "dist",
12
- "noImplicitAny": false,
13
- "types": ["node", "jest"]
14
- },
15
- "exclude": ["node_modules"],
16
- "include": ["src/"]
17
- }