DEV Community

Cover image for A11y Unlocked: Screen Reader Automation Tests
Craig Morten
Craig Morten

Posted on • Updated on

A11y Unlocked: Screen Reader Automation Tests

In the past year since my last post A11y Testing: Automating ScreenReaders on the topic of automating screen readers, we're now in a better place with progress made in standards and tooling.

It is exciting to see the W3C ARIA-AT Community Group formed with a mission to improve screen reader interoperability by building out a suite of specifications, test standards, and test automation to mature the screen reader ecosystem towards first-class tooling.

"Enabling AT interoperability is a large, ongoing endeavor that requires industry-wide collaboration and support. The W3C ARIA-AT Community Group is focusing on a stable and mature test suite for five screen readers by the end of 2023. In the future, we plan to test additional screen readers and other kinds of assistive technologies with a broader set of web design patterns and test material."


While the standards community slowly work towards their long term goal, I am pleased to share some screen reader automation tooling which you can use today! πŸš€

Guidepup for playwright

In this tutorial we're going to make use of the package @guidepup/playwright to write e2e tests for testing the accessibility of pages for people who use the VoiceOver screen reader for MacOS.

GitHub logo guidepup / guidepup-playwright

Screen reader driver for Playwright tests.

Guidepup Playwright

Screen reader driver for Playwright tests.

@guidepup/playwright available on NPM @guidepup/playwright available on NPM @guidepup/playwright test workflows @guidepup/playwright uses the MIT license

Reliable automation for your screen reader a11y workflows in Playwright supporting

VoiceOver on MacOS

NVDA on Windows - Coming Soon!


A11y static analysis tools only cover 25% of WCAG and don't assure on the quality of the user experience for screen reader users. This means teams need to perform lots of manual tests with multiple screen readers to ensure great UX which can take a lot of time... not anymore!

With Guidepup you can automate your screen reader test workflows the same you as would for mouse or keyboard based scenarios, no sweat!

Quick Features

  • Full Control - if a screen reader has a keyboard command, then Guidepup supports it.
  • Mirrors Real User Experience - assert on what users really do and hear when using screen readers.
  • Framework Agnostic - run with Jest, with Playwright, as an independent script, no vendor…

The package provides a reliable set of APIs to automate your screen reader a11y workflows when using Playwright. It does this by providing both Playwright configuration as well as a custom Playwright test instance that exposes a voiceOver object for controlling VoiceOver with.

Getting setup

Let's create a new project:

npm init
Enter fullscreen mode Exit fullscreen mode

Install the @guidepup/playwright package as a dependency:

npm install @guidepup/playwright
Enter fullscreen mode Exit fullscreen mode

We'll also need Playwright as the test runner for our browser:

npm install @playwright/test
Enter fullscreen mode Exit fullscreen mode

Last but not least we'll want to test against Safari using Playwright, so let's use their tool get grab the browser:

npx playwright install webkit
Enter fullscreen mode Exit fullscreen mode

We now have all the dependencies we need! πŸš€

A touch of config

Create a new playwright.config.js file:

import { voConfig } from "@guidepup/playwright";

const config: PlaywrightTestConfig = {

  // Your custom config ...

export default config;
Enter fullscreen mode Exit fullscreen mode

Here we're pulling in the minimum recommended Playwright config for using Guidepup - you can check it out in the source code. This sets the number of workers to 1 and sets Playwright to use "headed" mode because when we're using VoiceOver we can only control one browser at a time (and ideally it's visible!).

We should now be completely set to get going with our first test! πŸŽ‰

Writing your first screen-reader test

Create a new file voiceover.spec.js and copy in the following contents:

// We use a special test instance from the Guidepup package
// that gives us access to VoiceOver!
import { voTest as test } from "@guidepup/playwright";
import { expect } from "@playwright/test";

// The test setup is exactly the same as normal for
// Playwright, expect we now get a `voiceOver` object as well
// as the `page` object!
test.describe("Playwright VoiceOver", () => {
  test("I can navigate the Guidepup Github page", async ({
  }) => {
    // Let's navigate to Guidepup GitHub page and wait for
    // page to be ready, nothing special here!
    await page.goto("", {
      waitUntil: "domcontentloaded",
    await expect(

    // This is where things start to get awesome! Let's tell
    // VoiceOver to interact with the main page content, just 
    // the same as you would when use VoiceOver normally.
    await voiceOver.interact();

    // Let's do something a lil more exciting - move across
    // the page's headings until we reach the main Guidepup
    // repo title in the README using VoiceOver!
    while ((await voiceOver.itemText()) !== "Guidepup heading level 1") {
      await voiceOver.perform(
Enter fullscreen mode Exit fullscreen mode

Check out the comments in the code for what will happen in each part - pretty awesome huh? πŸ™Œ

Last checks before we launch

In order to automate screen-readers a few OS level settings need to be sorted first!

You can head over to the Guidepup environment setup docs for more details, but I recommend trying out the @guidepup/setup package which is designed to get you setup no faff!

npx @guidepup/setup
Enter fullscreen mode Exit fullscreen mode

You're now ready to rock! 🀘

Running your first screen-reader test

No special commands needed here, just the same as with any other Playwright test! Fire off the command then hold tight - we don't want to interact with the machine while the test is running as it might move VoiceOver's focus!

npx playwright test
Enter fullscreen mode Exit fullscreen mode

Gif over Playwright controlled Safari browser being driven with VoiceOver. Announcements read: "heading level 2, Latest commit", "heading level 2, Git stats", "You are currently on a heading level 2.", "heading level 2, Files", "You are currently on a heading level 2.", "heading level 2, link,", "heading level 1, Guidepup"

What's next?

To find out more there's a whole load of reading, modules, and docs - check some of these out:

Time to try out some e2e screen-reader tests?

Let me know your thoughts, questions, and opinions in the comments below!

Till next time folks πŸ‘‹

Top comments (1)

scottnath profile image
Scott Nath

@craigmorten FYI, I did a copypasta of the code above and discovered that voConfig is no longer the exported method from guidepup and the url ( gives a 404 on GitHub.
Just an FYI that this article needs updating to use voiceOverTest.

Cheers and thanks for a great set of libraries!