/** * WCAG 2.1 AAA compliance test using Playwright and axe-core * * This script uses Playwright to load pages and axe-core to test them for accessibility issues. * It's an alternative to the axe-test.js script that properly injects axe-core into the page. */ const { chromium } = require('playwright'); const fs = require('fs'); const path = require('path'); const axeCore = require('axe-core'); // URLs to test const BASE_URL = process.argv[2] || 'http://localhost:8080'; const PAGES = [ '/', '/stories/', '/stories/open-source-success.html', '/stories/viperwire.html', '/one-pager-tools/csv-tool.html' ]; // Create reports directory if it doesn't exist const reportsDir = path.join(__dirname, '../reports'); if (!fs.existsSync(reportsDir)) { fs.mkdirSync(reportsDir, { recursive: true }); } async function runAxe(page, pageUrl) { // Inject axe-core into the page await page.evaluate(axeSource => { const script = document.createElement('script'); script.text = axeSource; document.head.appendChild(script); }, axeCore.source); // Run axe with WCAG 2.1 AAA rules const results = await page.evaluate(() => { return new Promise(resolve => { axe.run(document, { runOnly: { type: 'tag', values: ['wcag2aaa'] }, resultTypes: ['violations', 'incomplete', 'inapplicable'], rules: { 'color-contrast': { enabled: true, options: { noScroll: true } } } }) .then(results => resolve(results)) .catch(err => resolve({ error: err.toString() })); }); }); return results; } async function testPage(browser, pageUrl) { const page = await browser.newPage(); console.log(`Testing ${pageUrl}...`); try { // Navigate to the page await page.goto(pageUrl, { waitUntil: 'networkidle' }); // Run axe-core tests const results = await runAxe(page, pageUrl); // Save results to file const fileName = pageUrl === BASE_URL ? 'index' : pageUrl.replace(BASE_URL, '').replace(/\//g, '-').replace(/^-/, ''); const reportPath = path.join(reportsDir, `axe-${fileName || 'index'}.json`); fs.writeFileSync(reportPath, JSON.stringify(results, null, 2)); // Log results summary if (results.error) { console.error(`Error running axe-core on ${pageUrl}:`, results.error); return { url: pageUrl, success: false, error: results.error }; } const { violations, incomplete, passes, inapplicable } = results; console.log(`Results for ${pageUrl}:`); console.log(`- Violations: ${violations.length}`); console.log(`- Incomplete: ${incomplete.length}`); console.log(`- Passes: ${passes.length}`); console.log(`- Inapplicable: ${inapplicable.length}`); // Print violations if (violations.length > 0) { console.log('\nViolations:'); violations.forEach((violation, i) => { console.log(`${i + 1}. ${violation.id} - ${violation.help} (Impact: ${violation.impact})`); console.log(` ${violation.description}`); console.log(` WCAG: ${violation.tags.filter(t => t.startsWith('wcag')).join(', ')}`); console.log(` Elements: ${violation.nodes.length}`); }); } return { url: pageUrl, success: violations.length === 0, violations: violations.length, incomplete: incomplete.length, passes: passes.length }; } catch (error) { console.error(`Error testing ${pageUrl}:`, error); return { url: pageUrl, success: false, error: error.toString() }; } finally { await page.close(); } } async function runTests() { const browser = await chromium.launch(); const results = []; try { // Test each page for (const pagePath of PAGES) { const pageUrl = `${BASE_URL}${pagePath}`; const result = await testPage(browser, pageUrl); results.push(result); } // Save overall results const overallReport = { timestamp: new Date().toISOString(), baseUrl: BASE_URL, pages: results, summary: { total: results.length, passed: results.filter(r => r.success).length, failed: results.filter(r => !r.success).length } }; fs.writeFileSync(path.join(reportsDir, 'axe-summary.json'), JSON.stringify(overallReport, null, 2)); // Print overall summary console.log('\n=== Overall Summary ==='); console.log(`Total pages tested: ${overallReport.summary.total}`); console.log(`Pages passed: ${overallReport.summary.passed}`); console.log(`Pages failed: ${overallReport.summary.failed}`); // Exit with appropriate code process.exit(overallReport.summary.failed > 0 ? 1 : 0); } catch (error) { console.error('Error running tests:', error); process.exit(1); } finally { await browser.close(); } } runTests();