Testing navigation
Guidepup is designed around real cursor movement and spoken phrase verification. A navigation test usually moves the current screen reader selection to the next or previous item, optionally uses a semantic browser command such as a heading or link command, and then checks what that reader reported.
The common API surface is documented in the screen reader reference docs:
next([options])nextHeading([options])nextLandmark([options])nextLink([options])previous([options])previousHeading([options])previousLandmark([options])previousLink([options])perform(command[, options])lastSpokenPhrase()
Those methods are available on the concrete implementations, including voiceOver and nvda. The platform screen reader wrapper, screenReader, exposes the same navigation workflow when a test can run against the default environment reader.
Move through the reading order
The simplest cursor movement flow is to advance the focus and immediately examine the last spoken phrase:
import { voiceOver } from "@guidepup/guidepup";
await voiceOver.start();
try {
await voiceOver.next();
expect(await voiceOver.lastSpokenPhrase()).toContain("Products");
} finally {
await voiceOver.stop();
}
The matching API for moving backwards is previous([options]):
await voiceOver.previous();
In practice, next() and previous() are the low-level building blocks for a screen reader style reading order traversal. They are the API equivalents of stepping through what the screen reader would present to a user.
Navigate via popular techniques
According to the annual WebAIM screen reader survey, some of the most popular techniques among screen reader users for finding information are navigating by heading, landmark, and link.
Guidepup supports all three of these navigation techniques:
import { voiceOver } from "@guidepup/guidepup";
await voiceOver.start();
try {
await voiceOver.nextHeading();
await voiceOver.nextLandmark();
await voiceOver.nextLink();
} finally {
await voiceOver.stop();
}
With matching APIs for moving backwards.
Targeted navigation with perform
For predictable page structure checks, perform() is used with a specific command object from the keyboard command catalog:
await voiceOver.perform(voiceOver.keyboardCommands.findNextGraphic);
expect(await voiceOver.lastSpokenPhrase()).toContain("Pricing");
await nvda.perform(nvda.keyboardCommands.moveToNextGraphic);
expect(await nvda.lastSpokenPhrase()).toContain("Pricing");
The command objects in the API docs are commands specific to the chosen screen reader. They describe navigation commands such as heading, link, landmark, form control, table, and similar semantic operations. This keeps the top-level API stable while still exposing each reader's command vocabulary.
Assert on the spoken result
Navigation tests in Guidepup usually pair a cursor operation with a spoken phrase check:
await voiceOver.start();
try {
await voiceOver.nextHeading();
const headingOutput = await voiceOver.lastSpokenPhrase();
expect(headingOutput).toContain("Products");
} finally {
await voiceOver.stop();
}
The same pattern works for NVDA:
await nvda.start();
try {
await nvda.nextHeading();
const headingOutput = await nvda.lastSpokenPhrase();
expect(headingOutput).toContain("Products");
} finally {
await nvda.stop();
}
The exact spoken phrase can vary between readers and browser/OS configurations. In most cases it is more reliable to assert on a stable substring rather than a full literal match.
Navigation checklist
A dependable Guidepup navigation test generally follows the same shape:
- Start the screen reader.
- Move the current cursor with
next(),previous(), common navigation techniques, or an explicitperform()command. - Read the latest result from
lastSpokenPhrase(). - Assert against the expected content.
- Stop the reader in a
finallyblock.
This pattern is the foundation for higher-level accessibility workflows, such as those described in testing VoiceOver, testing NVDA, and testing interactions.