Usability & Accessibility

Testing Accessible Interactions


Learning Objectives

  • You can turn a specific accessibility finding into a behavioral regression test.
  • You can use roles and accessible names without treating them as proof of complete accessibility.
  • You can test keyboard focus and preserve manual audit responsibilities.

When an accessibility failure has an observable condition, a browser regression can help prevent its return. The test should exercise the affected task and its result. It complements the manual audit rather than replacing it.

The worked example protects the date-range repair examined in the preceding audit. It uses the complete form from Chapter 6.5. Its application controls error rendering, focus and value preservation, so these are useful behaviors to protect.

A browser regression for keyboard form recovery

The application under test renders DateRangeForm.svelte at /date-range. With the component in client/src/lib/components/, this is the complete route component, client/src/routes/date-range/+page.svelte:

<script lang="ts">
import DateRangeForm from "#lib/components/DateRangeForm.svelte";
</script>
<h1>Find a date range</h1>
<DateRangeForm />

The audit’s hypothetical faulty revision cleared the dates after an invalid submission and left focus on the submit button. Run this regression against the repaired component: it checks the retained values and the path through the error summary to a corrected submission.

import { test, expect } from "@playwright/test";
test("an invalid date range can be corrected through the keyboard", async ({ page }) => {
await page.goto("/date-range");
const start = page.getByLabel("Start date");
const end = page.getByLabel("End date");
const submit = page.getByRole("button", { name: "Check dates" });
const summary = page.getByRole("region", { name: "Check the date range" });
await start.fill("2030-06-12");
await end.fill("2030-06-10");
await submit.focus();
await page.keyboard.press("Enter");
await expect(summary).toBeVisible();
await expect(summary).toBeFocused();
await expect(start).toHaveValue("2030-06-12");
await expect(end).toHaveValue("2030-06-10");
await page.keyboard.press("Tab");
const recovery = summary.getByRole("link", {
name: "Choose an end date on or after the start.",
});
await expect(recovery).toBeFocused();
await page.keyboard.press("Enter");
await expect(end).toBeFocused();
await end.fill("2030-06-13");
await submit.focus();
await page.keyboard.press("Enter");
await expect(summary).toHaveCount(0);
await expect(page.getByRole("status")).toHaveText("The date range is ready to search.");
await expect(submit).toBeFocused();
});

This is a complete Playwright test for an application serving that route. Running it assumes that the component and route are in a local application and that an existing Playwright configuration has a baseURL pointing to that running client.

getByLabel finds controls through their labels. getByRole uses the element’s role and accessible name: the summary’s named section is exposed as a region. These queries follow the interface’s semantics rather than its CSS classes. They still do not establish that every user can operate the page.

The initial fill() calls supply test data, and focus() establishes a known starting point. The test then observes keyboard submission, summary focus and link activation. It does not check navigation from the page start or typing into a date control with every keyboard and browser combination.

The Tab step checks navigation from the focused summary to its recovery link. The later focus() starts the accepted-submission check at the button: native date inputs can have several keyboard-editable segments, so one Tab from a date input need not reach the next control. A different form needs its own sequence. Playwright’s retrying assertions wait for the expected result without a fixed sleep.

A test that checks only the error text would miss cleared input or misplaced focus. Derive assertions from the observed barrier and its consequences.

What does a named-button click establish?

0 / 5 points

A component test finds a button by accessible name, clicks it, and observes details becoming visible. What is supported under that test’s conditions?

Regression coverage and manual observations

A background operation should update an existing status region without moving focus away from the task. An explicit failed form submission can instead focus an error summary, as above. If a repair affects pending or rejected requests, extend the relevant existing tests to check that focus and feedback remain appropriate in those states.

DOM state and focus observations do not establish what a screen reader announces. Likewise, an automated interaction test does not establish contrast, comfortable spacing or reflow under every user setting. Retain the manual observations and name the conditions not tested. A passing regression protects the specific behavior it exercises, not complete accessibility.

For optional further reading, the Playwright accessibility-testing guide shows how to integrate an automated accessibility scan. A scan checks rules about page content; the behavioral regression above exercises a particular recovery sequence. Both contribute evidence alongside the manual audit.

The later marketplace project applies these methods and specifies the audit record and keyboard test to submit.

Check Your Understanding

  1. Why are role and name queries preferable to arbitrary style selectors?
  2. Why can a click test miss the recovery behavior shown here?
  3. What is wrong with copying a fixed Tab count into an unrelated page?
  4. Why should a form-recovery test check input values as well as error text?
  5. What evidence remains manual after adding an accessible-interaction test?