feat(bf-21nd): add axe-core Playwright integration with shared helper
- Add shared accessibility test helper (tests/accessibility/helper.js/ts) - scanAccessibility(): runs axe-core scans with WCAG 2.1 AA tags - formatViolations(): formats violation details for error reporting - expectNoAccessibilityViolations(): asserts no violations - Add smoke tests demonstrating helper usage (tests/accessibility/smoke.spec.js/ts) - Refactor existing accessibility tests to use shared helper - Simplified a11y.spec.js to use expectNoAccessibilityViolations() - Maintains all existing test coverage Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
669d3793aa
commit
fb6e81e135
5 changed files with 183 additions and 21 deletions
|
|
@ -1,5 +1,5 @@
|
|||
const { test, expect } = require('@playwright/test');
|
||||
const AxeBuilder = require('@axe-core/playwright').default;
|
||||
const { test } = require('@playwright/test');
|
||||
const { expectNoAccessibilityViolations } = require('./accessibility/helper');
|
||||
|
||||
const pages = [
|
||||
{ name: 'index', path: '/index.html' },
|
||||
|
|
@ -16,25 +16,8 @@ for (const page of pages) {
|
|||
const pg = await context.newPage();
|
||||
await pg.goto(page.path, { waitUntil: 'load' });
|
||||
|
||||
const results = await new AxeBuilder({ page: pg })
|
||||
.withTags(['wcag2a', 'wcag2aa'])
|
||||
.analyze();
|
||||
|
||||
const violations = results.violations;
|
||||
if (violations.length > 0) {
|
||||
const details = violations
|
||||
.map((v) => ` ${v.id}: ${v.nodes.length} node(s) — ${v.description}`)
|
||||
.join('\n');
|
||||
// Attach full report for debugging
|
||||
await test.info().attach('axe-violations', {
|
||||
body: JSON.stringify(violations, null, 2),
|
||||
contentType: 'application/json',
|
||||
});
|
||||
}
|
||||
|
||||
await expect(violations, `${violations.length} WCAG AA violation(s) on ${page.path}:\n${
|
||||
violations.map((v) => ` ${v.id}: ${v.description}`).join('\n')
|
||||
}`).toEqual([]);
|
||||
// Use the shared accessibility helper
|
||||
await expectNoAccessibilityViolations(pg, page.path);
|
||||
|
||||
await context.close();
|
||||
});
|
||||
|
|
|
|||
69
dashboard/tests/accessibility/helper.js
Normal file
69
dashboard/tests/accessibility/helper.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
const AxeBuilder = require('@axe-core/playwright').default;
|
||||
|
||||
/**
|
||||
* Run an axe-core accessibility scan with WCAG 2.1 AA tags
|
||||
*
|
||||
* @param {Page} page - Playwright Page object to scan
|
||||
* @param {string} context - Optional context selector to limit the scan scope
|
||||
* @returns {Promise<Object>} Axe scan results with violations, passes, and incomplete results
|
||||
*/
|
||||
async function scanAccessibility(page, context) {
|
||||
const builder = new AxeBuilder({ page });
|
||||
|
||||
// Configure with WCAG 2.1 AA tags
|
||||
builder.withTags(['wcag2a', 'wcag2aa']);
|
||||
|
||||
// Limit scan scope if context is provided
|
||||
if (context) {
|
||||
builder.include(context);
|
||||
}
|
||||
|
||||
return await builder.analyze();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format accessibility violations for error reporting
|
||||
*
|
||||
* @param {Array} violations - Array of axe violation results
|
||||
* @returns {string} Formatted string with violation details
|
||||
*/
|
||||
function formatViolations(violations) {
|
||||
return violations
|
||||
.map((v) => ` ${v.id}: ${v.nodes.length} node(s) — ${v.description}`)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a page has no accessibility violations
|
||||
*
|
||||
* @param {Page} page - Playwright Page object to scan
|
||||
* @param {string} pageName - Name of the page for error reporting
|
||||
* @param {string} context - Optional context selector to limit the scan scope
|
||||
*/
|
||||
async function expectNoAccessibilityViolations(page, pageName, context) {
|
||||
const results = await scanAccessibility(page, context);
|
||||
const violations = results.violations;
|
||||
|
||||
if (violations.length > 0) {
|
||||
// Attach full report for debugging
|
||||
const { test } = require('@playwright/test');
|
||||
await test.info().attach('axe-violations', {
|
||||
body: JSON.stringify(violations, null, 2),
|
||||
contentType: 'application/json',
|
||||
});
|
||||
}
|
||||
|
||||
const { expect } = require('@playwright/test');
|
||||
await expect(
|
||||
violations,
|
||||
`${violations.length} WCAG AA violation(s) on ${pageName}:\n${
|
||||
violations.map((v) => ` ${v.id}: ${v.description}`).join('\n')
|
||||
}`
|
||||
).toEqual([]);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
scanAccessibility,
|
||||
formatViolations,
|
||||
expectNoAccessibilityViolations,
|
||||
};
|
||||
68
dashboard/tests/accessibility/helper.ts
Normal file
68
dashboard/tests/accessibility/helper.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import { Page } from '@playwright/test';
|
||||
import AxeBuilder from '@axe-core/playwright';
|
||||
|
||||
/**
|
||||
* Run an axe-core accessibility scan with WCAG 2.1 AA tags
|
||||
*
|
||||
* @param page - Playwright Page object to scan
|
||||
* @param context - Optional context selector to limit the scan scope
|
||||
* @returns Axe scan results with violations, passes, and incomplete results
|
||||
*/
|
||||
export async function scanAccessibility(page: Page, context?: string) {
|
||||
const builder = new AxeBuilder({ page });
|
||||
|
||||
// Configure with WCAG 2.1 AA tags
|
||||
builder.withTags(['wcag2a', 'wcag2aa']);
|
||||
|
||||
// Limit scan scope if context is provided
|
||||
if (context) {
|
||||
builder.include(context);
|
||||
}
|
||||
|
||||
return await builder.analyze();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format accessibility violations for error reporting
|
||||
*
|
||||
* @param violations - Array of axe violation results
|
||||
* @returns Formatted string with violation details
|
||||
*/
|
||||
export function formatViolations(violations: any[]): string {
|
||||
return violations
|
||||
.map((v) => ` ${v.id}: ${v.nodes.length} node(s) — ${v.description}`)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a page has no accessibility violations
|
||||
*
|
||||
* @param page - Playwright Page object to scan
|
||||
* @param pageName - Name of the page for error reporting
|
||||
* @param context - Optional context selector to limit the scan scope
|
||||
*/
|
||||
export async function expectNoAccessibilityViolations(
|
||||
page: Page,
|
||||
pageName: string,
|
||||
context?: string
|
||||
): Promise<void> {
|
||||
const results = await scanAccessibility(page, context);
|
||||
const violations = results.violations;
|
||||
|
||||
if (violations.length > 0) {
|
||||
// Attach full report for debugging
|
||||
const { test } = require('@playwright/test');
|
||||
await test.info().attach('axe-violations', {
|
||||
body: JSON.stringify(violations, null, 2),
|
||||
contentType: 'application/json',
|
||||
});
|
||||
}
|
||||
|
||||
const { expect } = require('@playwright/test');
|
||||
await expect(
|
||||
violations,
|
||||
`${violations.length} WCAG AA violation(s) on ${pageName}:\n${
|
||||
violations.map((v) => ` ${v.id}: ${v.description}`).join('\n')
|
||||
}`
|
||||
).toEqual([]);
|
||||
}
|
||||
21
dashboard/tests/accessibility/smoke.spec.js
Normal file
21
dashboard/tests/accessibility/smoke.spec.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
const { test, expect } = require('@playwright/test');
|
||||
const { scanAccessibility, expectNoAccessibilityViolations } = require('./helper');
|
||||
|
||||
test.describe('Accessibility Helper Smoke Test', () => {
|
||||
test('helper functions are available', async ({ page }) => {
|
||||
// Basic smoke test to verify the helper is working
|
||||
await page.goto('/index.html', { waitUntil: 'load' });
|
||||
|
||||
// Test the scanAccessibility function
|
||||
const results = await scanAccessibility(page);
|
||||
expect(results).toHaveProperty('violations');
|
||||
expect(results).toHaveProperty('passes');
|
||||
expect(Array.isArray(results.violations)).toBe(true);
|
||||
expect(Array.isArray(results.passes)).toBe(true);
|
||||
});
|
||||
|
||||
test('index page has no WCAG AA violations (using helper)', async ({ page }) => {
|
||||
await page.goto('/index.html', { waitUntil: 'load' });
|
||||
await expectNoAccessibilityViolations(page, 'index page');
|
||||
});
|
||||
});
|
||||
21
dashboard/tests/accessibility/smoke.spec.ts
Normal file
21
dashboard/tests/accessibility/smoke.spec.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import { scanAccessibility, expectNoAccessibilityViolations } from './helper';
|
||||
|
||||
test.describe('Accessibility Helper Smoke Test', () => {
|
||||
test('helper functions are available', async ({ page }) => {
|
||||
// Basic smoke test to verify the helper is working
|
||||
await page.goto('/index.html', { waitUntil: 'load' });
|
||||
|
||||
// Test the scanAccessibility function
|
||||
const results = await scanAccessibility(page);
|
||||
expect(results).toHaveProperty('violations');
|
||||
expect(results).toHaveProperty('passes');
|
||||
expect(Array.isArray(results.violations)).toBe(true);
|
||||
expect(Array.isArray(results.passes)).toBe(true);
|
||||
});
|
||||
|
||||
test('index page has no WCAG AA violations (using helper)', async ({ page }) => {
|
||||
await page.goto('/index.html', { waitUntil: 'load' });
|
||||
await expectNoAccessibilityViolations(page, 'index page');
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue