|
@@ -1,5 +1,11 @@
|
|
|
-import { AxeResults } from 'axe-core';
|
|
|
-import { sortAxeViolations } from './a11y-result';
|
|
|
+import axe, { AxeResults, Spec } from 'axe-core';
|
|
|
+import {
|
|
|
+ sortAxeViolations,
|
|
|
+ WagtailAxeConfiguration,
|
|
|
+ addCustomChecks,
|
|
|
+ checkImageAltText,
|
|
|
+ getA11yReport,
|
|
|
+} from './a11y-result';
|
|
|
|
|
|
const mockDocument = `
|
|
|
<div id="a"></div>
|
|
@@ -55,3 +61,109 @@ describe('sortAxeViolations', () => {
|
|
|
]);
|
|
|
});
|
|
|
});
|
|
|
+
|
|
|
+describe('addCustomChecks', () => {
|
|
|
+ it('should integrate custom checks into the Axe spec', () => {
|
|
|
+ const spec: Spec = {
|
|
|
+ checks: [{ id: 'check-id', evaluate: 'functionName' }],
|
|
|
+ rules: [
|
|
|
+ {
|
|
|
+ id: 'rule-id',
|
|
|
+ impact: 'serious',
|
|
|
+ any: ['check-id'],
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ const modifiedSpec = addCustomChecks(spec);
|
|
|
+ const customCheck = modifiedSpec?.checks?.find(
|
|
|
+ (check) => check.id === 'check-id',
|
|
|
+ );
|
|
|
+ expect(customCheck).toBeDefined();
|
|
|
+ expect(customCheck?.evaluate).toBe('functionName');
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should return spec unchanged if no custom checks match', () => {
|
|
|
+ const spec: Spec = {
|
|
|
+ checks: [{ id: 'non-existent-check', evaluate: '' }],
|
|
|
+ };
|
|
|
+ const modifiedSpec = addCustomChecks(spec);
|
|
|
+ expect(modifiedSpec).toEqual(spec);
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+// Options for checkImageAltText function
|
|
|
+const options = {
|
|
|
+ pattern: '\\.(avif|gif|jpg|jpeg|png|svg|webp)$',
|
|
|
+};
|
|
|
+
|
|
|
+describe.each`
|
|
|
+ text | result
|
|
|
+ ${'Good alt text with words like GIFted and motif'} | ${true}
|
|
|
+ ${'Bad alt text.png'} | ${false}
|
|
|
+ ${''} | ${true}
|
|
|
+`('checkImageAltText', ({ text, result }) => {
|
|
|
+ const resultText = result ? 'should not be flagged' : 'should be flagged';
|
|
|
+ test(`alt text: "${text}" ${resultText}`, () => {
|
|
|
+ const image = document.createElement('img');
|
|
|
+ image.setAttribute('alt', text);
|
|
|
+ expect(checkImageAltText(image, options)).toBe(result);
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+describe('checkImageAltText edge cases', () => {
|
|
|
+ test('should not flag images with no alt attribute', () => {
|
|
|
+ const image = document.createElement('img');
|
|
|
+ expect(checkImageAltText(image, options)).toBe(true);
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+jest.mock('axe-core', () => ({
|
|
|
+ configure: jest.fn(),
|
|
|
+ run: jest.fn(),
|
|
|
+}));
|
|
|
+
|
|
|
+describe('getA11yReport', () => {
|
|
|
+ beforeEach(() => {
|
|
|
+ jest.clearAllMocks();
|
|
|
+ });
|
|
|
+ it('should configure Axe with custom rules and return the accessibility report', async () => {
|
|
|
+ const mockResults = {
|
|
|
+ violations: [
|
|
|
+ {
|
|
|
+ nodes: [{}, {}, {}], // 3 nodes with violations
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ (axe.run as jest.Mock).mockResolvedValue(mockResults);
|
|
|
+ const config: WagtailAxeConfiguration = {
|
|
|
+ context: 'body',
|
|
|
+ options: {},
|
|
|
+ messages: {},
|
|
|
+ spec: {
|
|
|
+ checks: [{ id: 'check-image-alt-text', evaluate: '' }],
|
|
|
+ },
|
|
|
+ };
|
|
|
+ const report = await getA11yReport(config);
|
|
|
+ expect(axe.configure).toHaveBeenCalled();
|
|
|
+ expect(axe.run).toHaveBeenCalledWith(config.context, config.options);
|
|
|
+ expect(report.results).toEqual(mockResults);
|
|
|
+ expect(report.a11yErrorsNumber).toBe(3);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should return an accessibility report with zero errors if there are no violations', async () => {
|
|
|
+ const mockResults = {
|
|
|
+ violations: [],
|
|
|
+ };
|
|
|
+ (axe.run as jest.Mock).mockResolvedValue(mockResults);
|
|
|
+ const config: WagtailAxeConfiguration = {
|
|
|
+ context: 'body',
|
|
|
+ options: {},
|
|
|
+ messages: {},
|
|
|
+ spec: {
|
|
|
+ checks: [{ id: 'check-image-alt-text', evaluate: '' }],
|
|
|
+ },
|
|
|
+ };
|
|
|
+ const report = await getA11yReport(config);
|
|
|
+ expect(report.a11yErrorsNumber).toBe(0);
|
|
|
+ });
|
|
|
+});
|