Repository navigation
Adopt Testing Library queries for interactive/accessible-element assertions #135
Description
TL;DR: The recurring test-coverage gap tracked in #133 (new interactive behavior landing untested) keeps taking the same shape: specs assert on wrapper.props(...) passed into a stubbed child, not on the actual rendered DOM/accessible state. @vue/test-utils's API makes that the easy thing to reach for. Testing Library's query-by-role/label/accessible-name style makes the wrong thing hard to write instead of relying on someone remembering to write the right one.
Detail
Why this is a different fix than #133
#133 states the rule ("assert on the rendered effect, not the prop passed into a mock"), but a written rule still depends on someone applying it — and the API itself works against that: item.props('active') is one call away, while asserting on real aria-current/aria-pressed state on the actual rendered element takes more effort with @vue/test-utils alone. Testing Library's design principle is the opposite: getByRole('link', { name: 'Documents', current: 'page' }) structurally cannot pass unless the real DOM has the real attribute — there's no props-only shortcut available.
Concretely, this would have caught the #130 sidebar-dedupe bug (two nav entries both getting aria-current="page"): a query like getByRole('link', { current: 'page' }) returning more than one element is a direct, obvious assertion failure, whereas checking items.map(i => i.props('active')) never touches the actual collision.
Proposed scope
- Add
@testing-library/vue(verified:8.1.0,vue: >= 3peer dep, published 2026-08-07) and@testing-library/jest-dom(verified:7.0.1, published 2026-08-09) alongside the existing@vue/test-utilssuite — not a replacement.@vue/test-utils'sshallowMount/prop-based assertions remain fine for pure logic/wiring checks where DOM fidelity isn't the point. - Use Testing Library queries specifically for assertions on interactive elements and accessible/ARIA state (links, buttons,
aria-current,aria-pressed, accessible names) — the exact category of thing docs: close a testing-trigger gap for existing-file behavior changes #133's rule targets. - One real worked example first, same approach as the composables adoption in Adopt Vue composables for stateful non-rendering logic, starting with TemplateSection's scroll-arrows #134: retrofit the feat: add navigation actions for office #130 nav-dedupe fix (once merged) with a Testing-Library-style regression test, proving the pattern catches what the props-only assertion missed, before it spreads elsewhere.
Related
- docs: close a testing-trigger gap for existing-file behavior changes #133 — states the rule this tooling enforces structurally rather than by convention.
- Adopt Vue composables for stateful non-rendering logic, starting with TemplateSection's scroll-arrows #134 — same "introduce one pattern via one real example, then let it spread opportunistically" shape.
Found during review of #125/#127/#130, all three of which hit this same gap independently.
Activity