diff --git a/test-framework/shared/utils/accessibility/AccessibilityTester.ts b/test-framework/shared/utils/accessibility/AccessibilityTester.ts new file mode 100644 index 0000000..7558eb2 --- /dev/null +++ b/test-framework/shared/utils/accessibility/AccessibilityTester.ts @@ -0,0 +1,71 @@ +import { Page } from '@playwright/test'; +import AxeBuilder from '@axe-core/playwright'; +import { AccessibilityResult, Violation } from '../../types'; + +export class AccessibilityTester { + constructor(private page: Page) {} + + async runAxeScan(pageName: string, url: string): Promise { + const accessibilityScanResults = await new AxeBuilder({ page: this.page }) + .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']) + .analyze(); + + const violations: Violation[] = accessibilityScanResults.violations.map(v => ({ + id: v.id, + impact: v.impact || 'unknown', + description: v.description, + help: v.help, + helpUrl: v.helpUrl, + nodes: v.nodes.length + })); + + const passes = accessibilityScanResults.passes.length; + const incomplete = accessibilityScanResults.incomplete.length; + const score = this.calculateScore(violations, passes, incomplete); + + return { + score, + violations, + passes, + incomplete, + page: pageName, + url + }; + } + + private calculateScore(violations: Violation[], passes: number, incomplete: number): number { + const total = violations.length + passes + incomplete; + if (total === 0) return 100; + return parseFloat(((passes / total) * 100).toFixed(1)); + } + + async checkColorContrast(): Promise { + const results = await new AxeBuilder({ page: this.page }) + .withTags(['wcag2aa']) + .include('#content') + .analyze(); + + return results.violations.filter(v => v.id === 'color-contrast').length === 0; + } + + async checkAltText(): Promise<{ total: number; withAlt: number; withoutAlt: number }> { + const images = await this.page.locator('img').all(); + let withAlt = 0; + let withoutAlt = 0; + + for (const image of images) { + const alt = await image.getAttribute('alt'); + if (alt && alt.trim() !== '') { + withAlt++; + } else { + withoutAlt++; + } + } + + return { + total: images.length, + withAlt, + withoutAlt + }; + } +}