Testing integrations
Test patterns for adapters, runtime behavior, browser delivery, and hands-on screen-reader checks.
Test each layer separately
A runtime transcript shows what core prepared. A DOM test shows how the page changed. Test with a real screen reader to confirm what it speaks.
| Layer | Check | Does not confirm |
|---|---|---|
| Adapter | Events and stable IDs | Announcements |
| Core | Prepared updates, timing, suppression, cancellation | Browser behavior |
| DOM | Browser results and page updates | Screen-reader speech |
| Browser | Keyboard, landmarks, focus, live regions | Every screen reader and browser combination |
| Hands-on screen-reader test | One user workflow | Behavior in every environment |
Test every supported browser engine
In a checkout of this repository, browser fixtures run in Chromium, Firefox, and WebKit. They check keyboard use, stable focus, page landmarks, live regions, and browser delivery. Run these commands from the repository root:
pnpm test:browser:install
pnpm test:browserTest a realistic app workflow
Fixtures cover streaming text, tool updates, stopping, retrying, and browser announcements. Each assertion names the behavior it checks.
- Run the same scenarios in all three browser engines.
- Check that streaming and status updates do not move focus.
- Connect each app event to the runtime update and the resulting page change.
- Keep controls and visible status usable without the library.
Record hands-on screen-reader tests
For each release, record the date, browser, operating system, screen reader and version, workflow, expected result, actual result, and outcome. Repository validation checks every required field.
Evidence and testing note
One test describes one setup and workflow. It does not guarantee the same result with every screen reader and browser.
Use ManualClock for time-dependent behavior
Advance the test clock instead of waiting for real timers. Check diagnostics when the runtime intentionally skips an update.
import { expect, test } from "vitest";
import { createRecorder } from "@generative-a11y/core";
test("stopping discards buffered response text", () => {
const recorder = createRecorder({ preset: "balanced" });
recorder.runtime.dispatch({ type: "response.started", responseId: "r1" });
recorder.runtime.dispatch({
type: "response.text.delta",
responseId: "r1",
delta: "Unfinished",
});
recorder.runtime.dispatch({ type: "response.interrupted", responseId: "r1" });
recorder.clock.runUntilIdle();
expect(recorder.transcript().map(({ text }) => text)).toEqual([
"Response stopped.",
]);
recorder.runtime.dispose();
});