diff --git a/.changeset/dull-rockets-wave.md b/.changeset/dull-rockets-wave.md new file mode 100644 index 00000000..83f6e240 --- /dev/null +++ b/.changeset/dull-rockets-wave.md @@ -0,0 +1,5 @@ +--- +"@chialab/vitest-axe": patch +--- + +First release. diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index 7b8ed63c..3097d087 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -101,6 +101,10 @@ export default defineConfig({ text: 'postcss-url-rebase', link: '/guide/postcss-url-rebase', }, + { + text: 'vitest-axe', + link: '/guide/vitest-axe', + }, // { // text: 'Write a plugin', // link: '/guide/write-a-plugin', diff --git a/docs/guide/vitest-axe.md b/docs/guide/vitest-axe.md new file mode 100644 index 00000000..3a7776f1 --- /dev/null +++ b/docs/guide/vitest-axe.md @@ -0,0 +1,58 @@ +# Vitest Axe matchers + +Axe violations matchers for Vitest. + +## Install + +::: code-group + +```sh[npm] +npm i -D axe-core @chialab/vitest-axe +``` + +```sh[yarn] +yarn add -D axe-core @chialab/vitest-axe +``` + +```sh[pnpm] +pnpm add -D axe-core @chialab/vitest-axe +``` + +::: + +## Usage + +Use a Vitest setup file to add the matchers to the test runner. + +::: code-group + +```ts[vitest.config.ts] +export default { + test: { + setupFiles: ['./test/setup.ts'], + }, +} +``` + +```ts[test/setup.ts] +import matchers from '@chialab/vitest-axe'; +import { expect } from 'vitest'; + +expect.extend(matchers); +``` + +::: + +## Example + +```ts +import { run as axe } from 'axe-core'; +import { describe, expect, test } from 'vitest'; + +describe('button', () => { + test('accessibility', async () => { + const button = document.createElement('button'); + expect(await axe(button)).toHaveNoViolations(); + }); +}); +``` diff --git a/packages/vitest-axe/LICENSE.md b/packages/vitest-axe/LICENSE.md new file mode 100644 index 00000000..cbaa0376 --- /dev/null +++ b/packages/vitest-axe/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Chialab + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/vitest-axe/README.md b/packages/vitest-axe/README.md new file mode 100644 index 00000000..918ab14f --- /dev/null +++ b/packages/vitest-axe/README.md @@ -0,0 +1,29 @@ +

+ vitest-axe • Axe matchers for Vitest. +

+ +

+ NPM +

+ +--- + +## Install + +```sh +npm i @chialab/vitest-axe -D +``` + +```sh +yarn add @chialab/vitest-axe -D +``` + +## Documentation + +Read the documentation at [chialab.github.io/rna](https://chialab.github.io/rna/guide/vitest-axe). + +--- + +## License + +**vitest-axe** is released under the [MIT](https://github.com/chialab/rna/blob/main/packages/vitest-axe/LICENSE) license. diff --git a/packages/vitest-axe/lib/index.js b/packages/vitest-axe/lib/index.js new file mode 100644 index 00000000..3d224e74 --- /dev/null +++ b/packages/vitest-axe/lib/index.js @@ -0,0 +1,32 @@ +export * from './vitest-axe'; + +export default { + /** + * @param {import('axe-core').AxeResults} results + */ + toHaveNoViolations(results) { + const violations = results.violations ?? []; + + return { + pass: violations.length === 0, + actual: violations, + message() { + if (violations.length === 0) { + return ''; + } + + return `Expected no accessibility violations but received some. + +${violations + .map( + (violation) => `[${violation.impact}] ${violation.id} +${violation.description} +${violation.helpUrl} +` + ) + .join('\n')} +`; + }, + }; + }, +}; diff --git a/packages/vitest-axe/lib/vitest-axe.ts b/packages/vitest-axe/lib/vitest-axe.ts new file mode 100644 index 00000000..81d906d8 --- /dev/null +++ b/packages/vitest-axe/lib/vitest-axe.ts @@ -0,0 +1,10 @@ +interface AxeMatchers { + toHaveNoViolations(): R; +} + +declare module '@vitest/expect' { + interface Assertion extends AxeMatchers {} + interface AsymmetricMatchersContaining extends AxeMatchers {} +} + +export {}; diff --git a/packages/vitest-axe/package.json b/packages/vitest-axe/package.json new file mode 100644 index 00000000..fb7b39ff --- /dev/null +++ b/packages/vitest-axe/package.json @@ -0,0 +1,35 @@ +{ + "name": "@chialab/vitest-axe", + "type": "module", + "version": "0.18.0", + "description": "Axe matchers for Vitest.", + "main": "lib/index.js", + "typings": "./types/index.d.ts", + "author": "Chialab (https://www.chialab.it)", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/chialab/rna", + "directory": "packages/vitest-axe" + }, + "keywords": [], + "files": [ + "lib", + "types", + "package.json", + "README.md", + "LICENSE" + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "axe-core": "^4.0.0", + "vitest": "^1.0.0" + }, + "devDependencies": { + "axe-core": "^4.0.0", + "typescript": "^5.0.0", + "vitest": "^1.0.0" + } +} diff --git a/packages/vitest-axe/tsconfig.json b/packages/vitest-axe/tsconfig.json new file mode 100644 index 00000000..96cc8737 --- /dev/null +++ b/packages/vitest-axe/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./types", + "declarationDir": "./types", + "baseUrl": ".", + "rootDir": "./lib", + "types": ["vitest"] + }, + "include": ["lib/**/*"], + "references": [] +} diff --git a/tsconfig.json b/tsconfig.json index b6452dc8..dacbb583 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -108,6 +108,9 @@ { "path": "./packages/rna-saucelabs-test-runner" }, + { + "path": "./packages/vitest-axe" + }, { "path": "./packages/wds-plugin-hmr" }, diff --git a/yarn.lock b/yarn.lock index e4c0d228..0a4b60e4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2294,6 +2294,19 @@ __metadata: languageName: unknown linkType: soft +"@chialab/vitest-axe@workspace:packages/vitest-axe": + version: 0.0.0-use.local + resolution: "@chialab/vitest-axe@workspace:packages/vitest-axe" + dependencies: + axe-core: ^4.0.0 + typescript: ^5.0.0 + vitest: ^1.0.0 + peerDependencies: + axe-core: ^4.0.0 + vitest: ^1.0.0 + languageName: unknown + linkType: soft + "@chialab/wds-plugin-hmr@^0.18.0, @chialab/wds-plugin-hmr@workspace:packages/wds-plugin-hmr": version: 0.0.0-use.local resolution: "@chialab/wds-plugin-hmr@workspace:packages/wds-plugin-hmr" @@ -5440,7 +5453,7 @@ __metadata: languageName: node linkType: hard -"axe-core@npm:^4.3.3": +"axe-core@npm:^4.0.0, axe-core@npm:^4.3.3": version: 4.8.4 resolution: "axe-core@npm:4.8.4" checksum: 644da2fec17bcf6f834edaab1baa5a75a9a3ee370c323215c73da6d7e45fac11d01470d92d0a3d5f26695e15c1d9b781733dfbe1fe09d505076c58f09ed74e02 @@ -15555,7 +15568,7 @@ __metadata: languageName: node linkType: hard -"vitest@npm:^1.3.1": +"vitest@npm:^1.0.0, vitest@npm:^1.3.1": version: 1.3.1 resolution: "vitest@npm:1.3.1" dependencies: