Builds a screen-reader test narrative - a step-by-step manual test script for NVDA (Windows), JAWS (Windows), VoiceOver (macOS / iOS), or TalkBack (Android) - that exercises a specific user flow through a component or page and captures the expected announcement at each step. Use when authoring an accessibility-acceptance test the team will run before sign-off, OR when scripting a manual a11y audit.
75
94%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Automated tools (axe-core, pa11y, Lighthouse) catch ~30-40% of accessibility issues - the structural ones. The remaining 60-70% require manual screen-reader testing by an actual human using NVDA / JAWS / VoiceOver / TalkBack. The team needs a repeatable script that any tester (not just the original author) can follow.
This skill takes a user flow and produces that script: per-step keystroke + expected announcement.
Most a11y audit conventions cover at least:
| Screen reader | Platform | Browser pairing |
|---|---|---|
| NVDA | Windows | Firefox or Chrome |
| JAWS | Windows | Chrome or Edge |
| VoiceOver | macOS / iOS / iPadOS | Safari (macOS); Safari (iOS) |
| TalkBack | Android | Chrome |
For the most-coverage-per-effort, test NVDA + Firefox and VoiceOver + Safari - these are also the WAI-recommended pairs.
Start each script by naming the SR + browser + OS combination.
A flow is a sequence of user goals. Don't write step-by-step keystrokes upfront - that's Step 3. The flow is at user-intent level:
flow_name: "User edits their profile email"
preconditions:
- User is logged in.
- User is on the /profile page.
- Screen reader is on; browser virtual cursor is at the page heading.
steps:
- intent: "Navigate to the profile-edit form via main nav"
- intent: "Tab through the form to the email field"
- intent: "Edit the email value to a new valid email"
- intent: "Submit the form"
- intent: "Hear the success confirmation announcement"For each intent, the script row lists three things:
NVDA browse mode navigates with quick-keys (H by heading, F by
form field); VoiceOver uses VO (Ctrl+Option) chords:
| Action | VoiceOver shortcut |
|---|---|
| Read next / previous | VO + Right / Left arrow |
| Next heading | VO + Cmd + H |
| Next form control | VO + Cmd + J |
| Activate (Enter) | VO + Space |
| Web rotor | VO + U (form / heading / link list overlay) |
A minimal NVDA + Firefox excerpt for the flow "User edits their profile email":
| Keystroke | Expected announcement |
|---|---|
| H | "Edit profile, heading level 2" - moves to next heading. |
| F | "Email, edit, blank" - jumps to the first form field. |
| Tab, Enter | "Save changes, button", then a live region announces "Profile saved". |
Full per-reader scripts (NVDA + Firefox and VoiceOver + Safari) for this flow, with the WCAG / APG mapping in the "Why" column: references/screen-reader-scripts.md.
VoiceOver announcements are sometimes more verbose than NVDA's (role words like "edit text" where NVDA says "edit"); that is a vendor convention, not a bug to suppress.
For each step, the announcement should:
id attribute).Failures to flag:
| Failure | Likely cause |
|---|---|
Announcement reads CSS class names or id attributes | Label is missing; SR fell back to other text. |
| Element type is wrong ("link" instead of "button") | <a> used as a button; or role="link" on a button. |
| State is missing | aria-expanded / aria-checked not set. |
| Position-in-set is missing | aria-setsize / aria-posinset not set on list items. |
| Live region announcement doesn't fire | Region added with content already present, OR aria-live="off". |
The script becomes a manual test in the project's test plan. Common formats:
## A11y Acceptance - User edits profile email
### NVDA + Firefox (Windows)
- [ ] Step 1: Pressing H twice lands on "Profile information" heading.
- [ ] Step 2: Pressing F lands on the email field; announces "Email, edit, blank".
- [ ] Step 3: After submit, a live region announces "Profile saved".
### VoiceOver + Safari (macOS)
- [ ] Step 1: VO+Cmd+H twice lands on "Profile information" heading.
- [ ] Step 2: VO+Cmd+J lands on email; announces "Email, edit text".
- [ ] Step 3: After submit, live region announces "Profile saved".
Sign-off: ___________________ Date: __________For teams using TestRail / Xray / Zephyr - encode the flow as a
manual test case with one step per row, expected result per row.
The skill emits the matching format; per
testrail-integration
(when shipped) the test case can be uploaded automatically.
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Testing on only one screen reader | NVDA bugs ≠ JAWS bugs ≠ VoiceOver bugs. | At least two reader/browser pairs (NVDA+Firefox, VoiceOver+Safari). |
| Asking the developer to test their own work | Familiarity bias; the dev knows how it should sound. | Independent tester or accessibility specialist; use the script blindly. |
| Recording expected announcements verbatim from one version | Screen-reader announcement strings change between versions. | Test the announcement contains key elements (label, role, state); avoid string-equality. |
| Skipping the "Why" column | Tester can't generalize from "this announcement was wrong" to "the underlying ARIA pattern is broken." | Always link to the WCAG SC or APG pattern. |
wcag-keyboard-navigation,
aria-authoring-patterns - patterns this skill references for the "Why" column.