# Test Layers

taga11y uses a four-layer testing strategy. Each layer targets a different risk surface and runs at a different speed. CI runs the automated layers; manual layers are documented for release verification.

## Layer 1: Unit Tests — Vitest + happy-dom + vitest-axe

| Property | Value |
|----------|-------|
| Runner | Vitest |
| Environment | happy-dom |
| A11y assertions | vitest-axe (`toHaveNoViolations`) |
| Command | `npm test` |
| Location | `tests/` |

### What it tests

- **Pure logic**: SelectionManager, filter utility, debounce utility, ID generator
- **Component managers**: DropdownManager, InputManager, KeyboardManager (each in isolation with mocked DOM callbacks)
- **DOM rendering**: Wrapper structure, ARIA attributes, chip rendering, listbox rendering, announcer, error region
- **Taga11y class**: Init, destroy, addTag, removeTag, clearTags, getTags, addTags, setTags, isTagged, settings(), computed getters, custom events
- **Accessibility**: vitest-axe `toHaveNoViolations` assertions on rendered components
- **Theming**: CSS custom properties, `data-theme` attribute management
- **Serialize option**: Default and custom serializer behavior
- **Rejection paths**: Error chip rendering, error region messages, auto-dismiss, no events fired on rejection
- **Blur-commit and form reset**: Free mode commit, whitelist mode commit, form reset to snapshot
- **Settings() side effects**: Per-option DOM and state changes
- **Custom events**: All five events with correct payloads, bubble, and cancelable flags

### Configuration

- Environment: `happy-dom` (configured in `vitest.config.ts`)
- Setup file: `tests/setup.ts` (provides `vitest-axe` integration)
- Coverage: `@vitest/coverage-v8` available via `npm test -- --coverage`

### When to use

- Every PR
- Before merging any feature or fix
- Local development (fast feedback loop)

## Layer 2: Integration Tests — Playwright + @axe-core

| Property | Value |
|----------|-------|
| Runner | Playwright |
| Browsers | Chromium, Firefox, WebKit |
| A11y assertions | @axe-core/playwright |
| Command | `npm run test:e2e` |
| Location | `e2e/` |

### What it tests

- **Keyboard navigation**: ArrowDown, ArrowUp, Enter, Escape, Tab, Backspace, delimiter keys — all against real browser DOM
- **Screen reader announcements**: `aria-live` region `textContent` verified after each interaction in real browsers
- **Focus management**: Focus stays on combobox during dropdown nav, returns after chip removal, Shift+Tab exits without trapping
- **Form submission**: Hidden input value reflects selected tags, correct name attribute, multiple instances submit independently
- **Accessibility audits**: axe-core checks run across all three browser engines
- **Dynamic suggestions**: Debounce delay fires query after correct interval, loading indicator appears/disappears, AbortError suppression, fetch rejection error display
- **Blur-commit**: Tab key commits pending text, 150ms blur delay prevents double-commit, Tab-as-delimiter commits and moves focus

### Configuration

- Browser matrix: Chromium, Firefox, WebKit (configured in `playwright.config.ts`)
- Dev server: Playwright starts Vite dev server before tests
- Axe-core: `@axe-core/playwright` runs accessibility audits per spec

### When to use

- Every PR (runs in CI)
- After changes to keyboard interaction, focus management, or form behavior
- Before release (must pass across all three browsers)

## Layer 3: Manual Screen Reader Verification

| Property | Value |
|----------|-------|
| Method | Manual testing with real screen readers |
| Tools | NVDA, JAWS, VoiceOver (macOS/iOS), TalkBack, Narrator |
| Command | N/A — manual |
| Location | `docs/guides/sr-verification.md` |

### What it tests

- **Combobox interaction**: Focus announcement, arrow key navigation, selection, escape, tab order
- **Dropdown behavior**: Hidden when closed, result count announcements, loading announcements
- **Chip region**: List announcement, individual chip labels, remove button activation, focus return
- **Error handling**: Assertive announcements on rejection, auto-dismiss behavior
- **Known divergences**: SR/browser-specific behaviors documented in the verification matrix

### Verification matrix

See `docs/guides/sr-verification.md` for the full pairing matrix, verification scope, known divergences, and results log.

### Requirements

- **Before merge**: Verify against at least one pairing from the matrix
- **Before release**: Verify against at least one pairing from each row (NVDA, JAWS, VO macOS, VO iOS, TalkBack, Narrator)

### When to use

- Before merging features that affect ARIA attributes or announcements
- Before every release (full matrix verification)
- When investigating screen reader-specific bugs

## Layer 4: Manual Modality Testing

| Property | Value |
|----------|-------|
| Method | Manual testing with assistive input modalities |
| Modalities | Keyboard-only, Touch/pointer, Voice control, Switch device |
| Command | N/A — manual |
| Location | `docs/guides/modality-checklist.md` |

### What it tests

- **Keyboard-only**: All interactions without pointer — Tab/Shift-Tab/Arrow/Enter/Esc/Backspace/Home/End navigation, visible focus indicator, WCAG 2.2 focus appearance
- **Touch/pointer**: Tap chips, tap suggestions, tap remove buttons, adequate hit targets (≥24x24 CSS px, 44x44 preferred)
- **Voice control**: Dragon / macOS Voice Control — target chip remove buttons by label, commit tags by voice commands
- **Switch device**: Single-switch scanning through combobox, chips, and dropdown; no focus trapping

### Checklists

See `docs/guides/modality-checklist.md` for the four separate checklists.

### When to use

- Before every release
- When adding new interactive elements
- When modifying focus management or keyboard interaction

## Test Coverage Summary

| Layer | Scope | Speed | CI | Manual |
|-------|-------|-------|----|--------|
| Unit (Vitest) | Logic, managers, DOM, a11y assertions | Fast (~seconds) | Yes | — |
| Integration (Playwright) | Real browser interaction, a11y audits, form behavior | Medium (~minutes) | Yes | — |
| Screen Reader | AT behavior across pairings | Slow | — | Yes |
| Modality | Input modality compatibility | Slow | — | Yes |
