chore(release): prepare v0.1.0 release for main #16
@@ -0,0 +1,21 @@
|
|||||||
|
import axe from 'axe-core';
|
||||||
|
import type { A11yChecker, A11yCheckResult } from './types';
|
||||||
|
|
||||||
|
export const axeCoreChecker: A11yChecker = {
|
||||||
|
name: 'axe-core',
|
||||||
|
|
||||||
|
async run(rootElement: Element): Promise<A11yCheckResult> {
|
||||||
|
const results = await axe.run(rootElement);
|
||||||
|
|
||||||
|
return {
|
||||||
|
checkerName: 'axe-core',
|
||||||
|
violations: results.violations.map((violations) => ({
|
||||||
|
id: violations.id,
|
||||||
|
impact: violations.impact ?? null,
|
||||||
|
description: violations.help,
|
||||||
|
helpUrl: violations.helpUrl,
|
||||||
|
nodes: violations.nodes.map((node) => node.target.join(' ')),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
export interface A11yViolation {
|
||||||
|
id: string;
|
||||||
|
impact: 'minor' | 'moderate' | 'serious' | 'critical' | null;
|
||||||
|
description: string;
|
||||||
|
helpUrl?: string;
|
||||||
|
nodes: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface A11yCheckResult {
|
||||||
|
checkerName: string;
|
||||||
|
violations: A11yViolation[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface A11yChecker {
|
||||||
|
name: string;
|
||||||
|
run(root: Element): Promise<A11yCheckResult>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import type { A11yChecker, A11yCheckResult } from './checkers/types';
|
||||||
|
import { axeCoreChecker } from './checkers/axe-core.checker';
|
||||||
|
|
||||||
|
const a11yCheckerRegistry: A11yChecker[] = [
|
||||||
|
axeCoreChecker,
|
||||||
|
];
|
||||||
|
|
||||||
|
export async function runA11yChecks(rootElement: Element): Promise<A11yCheckResult[]> {
|
||||||
|
return Promise.all(a11yCheckerRegistry.map((a11yChecker) => a11yChecker.run(rootElement)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export type { A11yChecker, A11yCheckResult, A11yViolation } from './checkers/types';
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { expect } from 'vitest';
|
||||||
|
import type { A11yCheckResult } from './checkers/types';
|
||||||
|
|
||||||
|
expect.extend({
|
||||||
|
toHaveNoA11yViolations(results: A11yCheckResult[]) {
|
||||||
|
const failing = results.filter((results) => results.violations.length > 0);
|
||||||
|
|
||||||
|
if (failing.length === 0) {
|
||||||
|
return {
|
||||||
|
pass: true,
|
||||||
|
message: () => 'expected accessibility violations, but none were found',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = failing
|
||||||
|
.map(
|
||||||
|
(results) =>
|
||||||
|
`[${results.checkerName}] ${results.violations.length} violation(s):\n` +
|
||||||
|
results.violations
|
||||||
|
.map((validation) => ` - ${validation.id} (${validation.impact}): ${validation.description}\n affected: ${validation.nodes.join(', ')}`)
|
||||||
|
.join('\n')
|
||||||
|
)
|
||||||
|
.join('\n\n');
|
||||||
|
|
||||||
|
return {
|
||||||
|
pass: false,
|
||||||
|
message: () => `Accessibility violations found:\n\n${message}`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
declare module 'vitest' {
|
||||||
|
interface Assertion {
|
||||||
|
toHaveNoA11yViolations(): void;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
import { defineCustomElements } from "./loader";
|
import { defineCustomElements } from "./loader";
|
||||||
|
import './src/testing/a11y/matchers';
|
||||||
|
|
||||||
defineCustomElements();
|
defineCustomElements();
|
||||||
Reference in New Issue
Block a user