| name | accessibility-tester |
| version | 1.0.0 |
| description | Accessibility Tester for AI Native Full-Stack Software Factory Layer 11 - specializes in WCAG 2.1 compliance testing, screen reader compatibility, keyboard navigation, color contrast, and ARIA validation. Ensures applications are accessible to all users. |
| triggers | ["accessibility testing","WCAG compliance","a11y testing","screen reader","keyboard navigation","color contrast","ARIA validation","accessibility audit"] |
| role | specialist |
| scope | system |
| output-format | structured |
Accessibility Tester - ASF Layer 11
Purpose in AI Native Full-Stack Software Factory
Position: Layer 11 (Automated Validation) - Accessibility Specialist
Purpose: Ensure applications meet accessibility standards (WCAG 2.1/2.2), work with assistive technologies, and provide inclusive user experiences.
Relationship with tester-agent (L10-L11):
tester-agent: Orchestrates all testing activities
accessibility-tester: Specializes in accessibility/a11y testing
Architecture Overview
┌─────────────────────────────────────────────────────────┐
│ ACCESSIBILITY TESTER (L11) │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ WCAG 2.1/2.2 Rule Engine │ │
│ │ - Level A (25 criteria) │ │
│ │ - Level AA (13 criteria) │ │
│ │ - Level AAA (23 criteria) │ │
│ └─────────────────┬───────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Testing Modules │ │
│ │ ┌─────────┐ ┌─────────┐ ┌───────┐ │ │
│ │ │ Keyboard│ │ Screen │ │ Color │ │ │
│ │ │ Nav │ │ Reader │ │Contrast││ │
│ │ └─────────┘ └─────────┘ └───────┘ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌───────┐ │ │
│ │ │ ARIA │ │ Focus │ │ Forms │ │ │
│ │ │ │ │ Mgmt │ │ │ │ │
│ │ └─────────┘ └─────────┘ └───────┘ │ │
│ └─────────────────┬───────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Assistive Technology Simulation │ │
│ │ - Screen reader emulation │ │
│ │ - Keyboard-only navigation │ │
│ │ - High contrast mode │ │
│ │ - Magnification simulation │ │
│ └────────────────────┬────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Compliance Report Generator │ │
│ │ - WCAG score │ │
│ │ - Issue severity │ │
│ │ - Remediation guidance │ │
│ │ - Legal compliance status │ │
│ └─────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
WCAG 2.1/2.2 Compliance Matrix
| Level | Criteria Count | Status |
|---|
| Level A | 25 | ✅ Covered |
| Level AA | 13 | ✅ Covered |
| Level AAA | 23 | ✅ Covered |
| Total | 61 | |
Key WCAG Principles (POUR)
- Perceivable - Information must be presentable to users' senses
- Operable - UI must be operable by all users
- Understandable - Information and operation must be clear
- Robust - Content must work with assistive technologies
Core Capabilities
1. WCAG Rule Engine
interface WCAGRule {
id: string;
name: string;
level: 'A' | 'AA' | 'AAA';
principle: 'perceivable' | 'operable' | 'understandable' | 'robust';
guideline: string;
description: string;
howToMeet: string;
test: (context: TestContext) => Promise<TestResult>;
}
interface WCAGTestResult {
ruleId: string;
status: 'pass' | 'fail' | 'warning' | 'not-applicable';
severity: 'critical' | 'serious' | 'moderate' | 'minor';
impact: 'critical' | 'serious' | 'moderate' | 'minor';
description: string;
helpUrl: string;
elements: [];
: {
: ;
: ;
: ;
};
}
{
: ;
: ;
: ;
: ;
: ;
?: ;
}
{
: <, >;
() {
. = .();
}
(: ): <[]> {
: [] = [];
( [ruleId, rule] .) {
{
result = rule.(context);
results.(result);
} (error) {
results.({
ruleId,
: ,
: ,
: ,
: ,
: .(ruleId),
: [],
: { : , : , : }
});
}
}
results;
}
(: , : | | ): <[]> {
allResults = .(context);
allResults.( {
rule = ..(result.);
rule && rule. === level;
});
}
(): <, > {
rules = ();
rules.(, {
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: (context) => .(context)
});
rules.(, {
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: (context) => .(context)
});
rules.(, {
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: (context) => .(context)
});
rules.(, {
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: (context) => .(context)
});
rules;
}
(: ): <> {
elements = context..$$();
: [] = [];
( element elements) {
html = context..( el., element);
selector = .(element);
failingElements.({
html,
selector,
: html.(, ),
: ,
:
});
}
{
: ,
: failingElements. > ? : ,
: failingElements. > ? : ,
: failingElements. > ? : ,
: failingElements. >
?
: ,
: ,
: failingElements,
: {
: failingElements. === ? : ,
: failingElements.,
:
}
};
}
(: ): <> {
elements = context..$$();
: [] = [];
( element elements) {
styles = context..( {
computed = .(el);
{
: computed.,
: computed.,
: computed.,
: computed.,
: el.?.() ||
};
}, element);
(!styles. || styles. === ) {
;
}
contrastRatio = .(
.(styles.),
.(styles.)
);
requiredRatio = .(styles., styles.);
(contrastRatio < requiredRatio) {
selector = .(element);
failingElements.({
: context..( el., element),
selector,
: styles..(, ),
: ,
:
});
}
}
{
: ,
: failingElements. > ? : ,
: failingElements. > ? : ,
: failingElements. > ? : ,
: failingElements. >
?
: ,
: ,
: failingElements,
: {
: failingElements. === ? : ,
: failingElements.,
:
}
};
}
(: , : ): {
l1 = .(color1);
l2 = .(color2);
lighter = .(l1, l2);
darker = .(l1, l2);
(lighter + ) / (darker + );
}
(: ): {
[r, g, b] = [color., color., color.].( {
c = c / ;
c <= ? c / : .((c + ) / , );
});
* r + * g + * b;
}
(: , : ): {
size = (fontSize);
isBold = (fontWeight) >= ;
(size >= || (size >= && isBold)) {
;
}
;
}
}
2. Keyboard Navigation Testing
interface KeyboardNavigationTest {
tabOrder: {
elements: TabStop[];
logical: boolean;
issues: TabOrderIssue[];
};
focus: {
visible: boolean;
trapped: boolean;
restored: boolean;
issues: FocusIssue[];
};
interactions: {
enterKey: boolean;
spaceKey: boolean;
arrowKeys: boolean;
escapeKey: boolean;
shortcuts: KeyboardShortcut[];
};
}
interface TabStop {
index: number;
selector: string;
tagName: string;
role?: string;
tabindex?: number;
accessibleName?: string;
}
class KeyboardNavigationTester {
async test(page: Page): <> {
tabOrder = .(page);
focus = .(page);
interactions = .(page);
{ tabOrder, focus, interactions };
}
(: ): <> {
: [] = [];
index = ;
(index < ) {
page..();
page.();
focusedElement = page.( {
el = .;
(!el || el === .) ;
{
: .(el),
: el..(),
: el.(),
: el.(),
: el.() ||
el.() ||
el.?.().(, )
};
});
(!focusedElement) {
;
}
tabStops.({
: ++index,
...focusedElement
});
}
issues = .(tabStops);
logical = .(tabStops);
{
: tabStops,
logical,
issues
};
}
(: ): <> {
focusVisible = page.( {
style = .();
style. = ;
..(style);
button = .() ;
(!button) ;
button.();
styles = .(button);
styles. !== || styles. !== ;
});
focusTrapped = .(page);
focusRestored = .(page);
{
: focusVisible,
: !focusTrapped,
: focusRestored,
: []
};
}
(: ): <> {
interactions = {
: .(page),
: .(page),
: .(page),
: .(page),
: .(page)
};
interactions;
}
(: ): <> {
buttons = page.$$();
( button buttons.(, )) {
button.();
page..();
wasActivated = .(page, button);
(!wasActivated) {
;
}
}
;
}
}
3. Screen Reader Compatibility
interface ScreenReaderTest {
aria: {
landmarks: LandmarkInfo[];
liveRegions: LiveRegionInfo[];
relationships: RelationshipInfo[];
};
readingOrder: {
logical: boolean;
issues: ReadingOrderIssue[];
};
announcements: {
dynamic: boolean;
accurate: boolean;
timely: boolean;
};
}
class ScreenReaderTester {
async test(page: Page): Promise<ScreenReaderTest> {
const aria = await this.testARIA(page);
const readingOrder = await this.testReadingOrder(page);
const announcements = await this.testAnnouncements(page);
return { aria, readingOrder, announcements };
}
(: ): <> {
landmarks = page.( {
landmarkRoles = [, , , , , ];
: [] = [];
( role landmarkRoles) {
elements = .();
elements.( {
found.({
role,
: .(el),
: el.() || el.?.().(, )
});
});
}
found;
});
hasMain = landmarks.( l. === );
liveRegions = page.( {
regions = .();
.(regions).( ({
: .(el),
: el.(),
: el.() ===
}));
});
{
landmarks,
liveRegions,
: []
};
}
(: ): <> {
domOrder = page.( {
.(.())
.( ({
: el..(),
: el.?.().(, ),
: .(.()).(el)
}));
});
: [] = [];
headings = domOrder.( el..());
( i = ; i < headings.; i++) {
prevLevel = (headings[i-].[]);
currLevel = (headings[i].[]);
(currLevel > prevLevel + ) {
issues.({
: ,
: ,
: headings[i]
});
}
}
{
: issues. === ,
issues
};
}
(: ): <> {
dynamicTest = page.( () => {
liveRegion = .();
liveRegion.(, );
liveRegion. = ;
..(liveRegion);
liveRegion. = ;
( (resolve, ));
liveRegion. === ;
});
{
: dynamicTest,
: ,
:
};
}
}
4. Form Accessibility Testing
interface FormAccessibilityTest {
labels: {
allHaveLabels: boolean;
missingLabels: FormElement[];
implicitLabels: FormElement[];
};
errors: {
associated: boolean;
described: boolean;
liveAnnounced: boolean;
};
validation: {
accessible: boolean;
clear: boolean;
};
}
class FormAccessibilityTester {
async test(page: Page): Promise<FormAccessibilityTest> {
const labels = await this.testLabels(page);
const errors = await this.testErrorHandling(page);
const validation = await this.testValidation(page);
return { labels, errors, validation };
}
private (: ): <> {
inputs = page.$$();
: [] = [];
: [] = [];
( input inputs) {
hasExplicitLabel = .(page, input);
hasImplicitLabel = .(page, input);
hasAriaLabel = .(page, input);
(!hasExplicitLabel && !hasImplicitLabel && !hasAriaLabel) {
selector = .(input);
= page.( el.() || el., input);
missingLabels.({
selector,
,
:
});
} (hasImplicitLabel) {
implicitLabels.({
: .(input),
: page.( el., input),
:
});
}
}
{
: missingLabels. === ,
missingLabels,
implicitLabels
};
}
(: ): <> {
forms = page.$$();
results = {
: ,
: ,
:
};
( form forms) {
form.( f.());
errorElements = form.$$();
( error errorElements) {
describedBy = .(error);
(describedBy. === ) {
results. = ;
}
}
}
results;
}
}
5. Compliance Report Generator
interface AccessibilityReport {
summary: {
score: number;
level: 'A' | 'AA' | 'AAA';
passed: number;
failed: number;
warnings: number;
notApplicable: number;
};
principles: {
perceivable: PrincipleScore;
operable: PrincipleScore;
understandable: PrincipleScore;
robust: PrincipleScore;
};
issues: {
critical: WCAGTestResult[];
serious: WCAGTestResult[];
moderate: WCAGTestResult[];
minor: WCAGTestResult[];
};
remediation: {
quickWins: RemediationItem[];
shortTerm: RemediationItem[];
longTerm: RemediationItem[];
};
compliance: {
wcag21A: ;
: ;
: ;
: ;
: ;
};
}
{
(: [], : ): <> {
summary = .(results);
principles = .(results);
issues = .(results);
remediation = .(issues);
compliance = .(results);
{
summary,
principles,
issues,
remediation,
compliance
};
}
(: []): {
passed = results.( r. === ).;
failed = results.( r. === ).;
warnings = results.( r. === ).;
notApplicable = results.( r. === ).;
totalWeight = results.;
passedWeight = passed + (warnings * );
score = .((passedWeight / totalWeight) * );
level = .(results);
{
score,
level,
passed,
failed,
warnings,
notApplicable
};
}
(: ): {
: [] = [];
: [] = [];
: [] = [];
( issue issues.) {
(.(issue)) {
quickWins.(.(issue, ));
} {
shortTerm.(.(issue, ));
}
}
( issue issues.) {
shortTerm.(.(issue, ));
}
( issue [...issues., ...issues.]) {
longTerm.(.(issue, ));
}
{ quickWins, shortTerm, longTerm };
}
(: , : | | ): {
{
: issue.,
: issue.,
: issue.,
: timeframe === ? : timeframe === ? : ,
: ,
: .(issue),
: [issue.]
};
}
}
Integration with Other ASF Components
With tester-agent (L10-L11)
interface TesterAgentIntegration {
runAccessibilityTests(suite: TestSuite): Promise<AccessibilityReport>;
addAccessibilityToCI(config: CIConfig): Promise<void>;
trackAccessibilityTrends(reports: AccessibilityReport[]): Promise<TrendAnalysis>;
}
With builder-agent (L10)
interface BuilderAgentIntegration {
fixAccessibilityIssues(issues: WCAGTestResult[]): Promise<FixReport>;
generateAccessibleComponent(spec: ComponentSpec): Promise<AccessibleComponent>;
}
Configuration
{
"accessibilityTester": {
"enabled": true,
"wcag": {
"level": "AA",
"version": "2.1"
},
"testing": {
"viewport": {
"width": 1920,
"height": 1080
},
"timeout": 30000,
"waitForLoad": true
},
"reporting": {
"format": ["json", "html", "pdf"]
Usage Examples
Example 1: Run Full Accessibility Audit
const tester = new AccessibilityTester();
const report = await tester.audit('http://localhost:3000', {
level: 'AA',
viewport: { width: 1920, height: 1080 }
});
console.log(`Accessibility Score: ${report.summary.score}/100`);
console.log(`WCAG 2.1 AA Compliance: ${report.compliance.wcag21AA ? '✅' : '❌'}`);
console.log(`Critical Issues: ${report.issues.critical.length}`);
console.log(`Serious Issues: ${report.issues.serious.length}`);
Example 2: Test Specific Component
const componentReport = await tester.testComponent('#main-form', {
rules: ['1.1.1', '1.4.3', '2.1.1', '4.1.2']
});
console.log('Form Accessibility Issues:');
for (const issue of componentReport.issues.critical) {
console.log(` - ${issue.ruleId}: ${issue.description}`);
console.log(` Fix: ${issue.elements[0]?.fix}`);
}
Example 3: CI/CD Integration
const report = await tester.audit('http://staging.example.com');
if (report.summary.score < 80) {
console.error('Accessibility score below threshold!');
process.exit(1);
}
if (report.issues.critical.length > 0) {
console.error('Critical accessibility issues found!');
process.exit(1);
}
console.log('✅ Accessibility checks passed');
Remember: Accessibility is not a feature—it's a fundamental requirement for inclusive software.