AI Tools Compared

Screen reader testing is a critical component of web accessibility validation. This guide covers how to use Claude Code to implement screen reader testing workflows, ensuring your web applications work with assistive technologies.

Understanding Screen Reader Testing Fundamentals

Screen readers interpret web content for users with visual impairments. Unlike automated accessibility checkers that can only validate code patterns, screen reader testing reveals the actual user experience. The major screen readers include NVDA (Windows, free), JAWS (Windows, commercial), and VoiceOver (macOS/iOS, built-in).

Before testing, ensure your development environment includes:

Setting Up Claude Code for Screen Reader Testing

Configure Claude Code to assist with screen reader testing by establishing proper project context:

# Initialize accessibility testing directory
mkdir -p ~/accessibility-testing/{nvda,voiceover,jaws,reports}
cd ~/accessibility-testing

# Create test manifest
cat > test-manifest.json << 'EOF'
{
  "testCases": [],
  "screenReaders": ["nvda", "voiceover", "jaws"],
  "browsers": ["chrome", "firefox", "safari"]
}
EOF

Creating Screen Reader Test Scripts

Use Claude Code to generate test scripts for each screen reader:

// screen-reader-test-suite.js
const { chromium } = require('playwright');
const { VoiceOver } = require('@axe-core/voiceover');

class ScreenReaderTestSuite {
  constructor() {
    this.results = [];
  }

  async testHeadingHierarchy(page) {
    const headings = await page.evaluate(() => {
      const levels = {};
      for (let i = 1; i <= 6; i++) {
        levels[`h${i}`] = document.querySelectorAll(`h${i}`).length;
      }
      return levels;
    });
    return headings;
  }

  async testLandmarkRegions(page) {
    const landmarks = await page.evaluate(() => {
      const regions = ['header', 'nav', 'main', 'footer', 'aside', 'form'];
      return regions.reduce((acc, region) => {
        acc[region] = document.querySelectorAll(region).length;
        return acc;
      }, {});
    });
    return landmarks;
  }

  async testImageAltText(page) {
    const images = await page.evaluate(() => {
      const imgs = document.querySelectorAll('img');
      return Array.from(imgs).map(img => ({
        src: img.src,
        alt: img.alt,
        hasAlt: img.hasAttribute('alt'),
        isDecorative: img.getAttribute('role') === 'presentation'
      }));
    });
    return images;
  }
}

Testing with NVDA on Windows

NVDA is the most widely used free screen reader on Windows. Test your applications:

# NVDA screen reader test command sequence
# Start NVDA before running tests
# Navigate to your application URL
# Use following commands to test:

# Heading navigation: h key (next heading), 1-6 (specific level)
# Landmark navigation: d key (next landmark)
# Link navigation: k key (next link)
# Form field navigation: f key (next form field)
# Table navigation: t (next table), arrows (within table)

# Claude Code can generate test expectations:
const nvdaTestCases = [
  {
    action: "navigate to heading",
    expected: "Page should announce all heading levels in order",
    verification: "h1 → h2 → h3 sequence is logical"
  },
  {
    action: "navigate to link",
    expected: "Links should announce descriptive text",
    verification: "No 'click here' or 'read more' without context"
  },
  {
    action: "enter form field",
    expected: "Field label should be announced",
    verification: "Label is read when field receives focus"
  }
];

Testing with VoiceOver on macOS

VoiceOver comes built into macOS and iOS. Enable and test:

# Enable VoiceOver: Cmd + F5
# Open VoiceOver Utility for detailed configuration

# VoiceOver key commands (VO = Control + Option)
# VO + H: Heading navigation
# VO + J/L: Next/previous link
# VO + U: Rotor (quick navigation)
# VO + Arrows: Navigate within rotor

# Test script example:
const voiceoverTests = [
  {
    test: "page title announcement",
    command: "VO + T",
    expected: "Page title should be announced immediately"
  },
  {
    test: "heading navigation",
    command: "VO + H",
    expected: "All headings announced with level"
  },
  {
    test: "image description",
    command: "VO + shift + down arrow when on image",
    expected: "Alt text or 'graphic' announced"
  }
];

Testing with JAWS on Windows

JAWS is widely used in enterprise environments:

# JAWS key commands
# H: Next heading
# 1-6: Specific heading level
# T: Next table
# E: Next edit field
# B: Next button

# JAWS specific tests:
const jawsTestCases = [
  {
    feature: "forms",
    test: "label association",
    verification: "Label text announced with field"
  },
  {
    feature: "tables",
    test: "reading mode",
    verification: "Row and column headers announced"
  },
  {
    feature: "dynamic content",
    test: "live regions",
    verification: "Content changes announced automatically"
  }
];

Automating Screen Reader Tests

Integrate screen reader testing into your CI/CD pipeline:

# .github/workflows/screen-reader-test.yml
name: Screen Reader Tests

on: [push, pull_request]

jobs:
  nvda-test:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup NVDA
        run: |
          choco install nvda -y
      - name: Run tests
        run: |
          npm test -- --screen-reader=nvda

  voiceover-test:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run VoiceOver tests
        run: |
          npm test -- --screen-reader=voiceover

Common Screen Reader Issues and Fixes

Claude Code can help identify and fix common screen reader problems:

Missing or Inaccurate Alt Text

<!-- Problem: Missing alt text -->
<img src="chart.png" />

<!-- Solution: Descriptive alt text -->
<img src="chart.png" alt="Bar chart showing Q4 sales: Product A: $50K, Product B: $35K, Product C: $45K" />

<!-- Solution: Empty alt for decorative images -->
<img src="decoration.png" alt="" role="presentation" />

Improper Heading Structure

<!-- Problem: Skipping heading levels -->
<h1>Main Title</h1>
<h3>Section</h3>

<!-- Solution: Sequential headings -->
<h1>Main Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>

Missing Form Labels

<!-- Problem: No label association -->
<input type="email" placeholder="Email">

<!-- Solution: Proper label association -->
<label for="email">Email address</label>
<input type="email" id="email" placeholder="email@example.com">

Testing Dynamic Content with Live Regions

Ensure dynamic content is announced to screen readers:

<!-- Problem: Dynamic content not announced -->
<div id="status"></div>
<script>
  document.getElementById('status').innerText = 'Message sent';
</script>

<!-- Solution: ARIA live regions -->
<div id="status" role="status" aria-live="polite">Message sent</div>

<!-- For important updates -->
<div id="alert" role="alert" aria-live="assertive">Error: Please correct the form</div>

Best Practices for Screen Reader Compatibility

Follow these guidelines for optimal screen reader support:

  1. Semantic HTML: Use proper HTML elements (header, nav, main, article, section, footer)

  2. ARIA only when needed: Native HTML elements are preferred over ARIA

  3. Focus management: Ensure logical focus order and visible focus indicators

  4. Keyboard accessibility: All functionality should be keyboard accessible

  5. Text alternatives: Provide text alternatives for all non-text content

  6. Testing across readers: Test with NVDA, VoiceOver, and JAWS as they behave differently

Integrating with Claude Code Workflows

Use Claude Code to improve your screen reader testing:

# Ask Claude Code to review accessibility
> Review the HTML in this component for screen reader compatibility. Check heading structure, form labels, alt text, and ARIA attributes.

# Generate test cases
> Create a screen reader test plan for this login form component including NVDA, VoiceOver, and JAWS test cases.

# Fix accessibility issues
> Fix all screen reader issues in this HTML: [paste code]

Measuring and Reporting Screen Reader Compatibility

Track your screen reader testing progress:

// Test results tracker
const testResults = {
  date: new Date().toISOString(),
  page: '/checkout',
  screenReaders: {
    nvda: {
      version: '2024.1',
      browser: 'Chrome 120',
      issues: [],
      passed: true
    },
    voiceover: {
      version: 'macOS 14.2',
      browser: 'Safari 17',
      issues: ['missing form labels'],
      passed: false
    },
    jaws: {
      version: '2024',
      browser: 'Firefox 121',
      issues: [],
      passed: true
    }
  }
};

Screen reader testing requires manual validation alongside automated tools. Use this workflow with Claude Code to systematically test across NVDA, VoiceOver, and JAWS, ensuring your web applications are accessible to all users.

Built by theluckystrike — More at zovo.one