Q39 of 42 · Playwright
What testability changes would you push for as a Playwright lead reviewing app code?
Short answer
Short answer: Accessible markup (real `<button>`s with names, labels on inputs, ARIA roles) so `getByRole` works. Stable test IDs as a fallback. No live timestamps in DOM strings; expose timestamps as attributes. Animations toggleable. Idempotent endpoints with caller-supplied keys. A test-mode hook for cache reset and synthetic events.
Detail
Playwright's recommended locator hierarchy starts with semantic markup. As a lead, the testability asks I prioritise:
1. Accessible markup. Real <button>s, properly labelled inputs (<label for> or aria-label), meaningful headings, ARIA roles where native semantics don't cover it. getByRole('button', { name: 'Submit' }) works only if the markup has the role and name. The same investment improves a11y for users with assistive tech — a virtuous cycle.
2. Stable test IDs as fallback. data-testid (or your team's chosen attribute) on icon-only buttons, generic divs, and disambiguating list items. Convention: data-testid=feature-element. Lint rule warns when a new interactive element ships without one.
3. No live timestamps in DOM strings. "2 hours ago", "Today at 3pm" — break tests every hour. Either a stable format ("2026-05-10 13:00") or expose the underlying timestamp as data-timestamp so tests can read it deterministically.
4. Stable IDs over UUIDs in URLs and DOM where possible. If UUIDs are unavoidable, expose them as data-id so tests can reference them without brittle URL parsing.
5. Test-mode hooks. A non-prod-only window.__test__ namespace exposing utilities — clear local cache, dispatch a synthetic event, fast-forward animations. Built into the app under if (env !== 'production') so prod paths aren't polluted.
6. Animations toggleable. A CSS class .no-animations on <html> (set by tests via page.addStyleTag or test mode) that disables transitions/animations globally. Removes a major source of flake.
7. Idempotent endpoints. Test setup hits APIs to seed state; endpoints that take a caller-supplied Idempotency-Key make seed scripts safer to retry without dupes.
8. Predictable empty / loading / error states. Each state has a data-testid so tests can wait for the right one rather than racing on visual cues.
9. Avoid CSS-only state. "Selected" via colour change is hard to assert on (theme dependence). Add a class or attribute (aria-selected).
10. Clear authentication backdoor for non-prod. A POST /api/test-login that takes a role and returns a session. Speeds up tests dramatically vs full SSO.
The cultural piece: framing these as shared engineering quality, not "QA's wishlist". Test-friendly apps are also better for a11y, debugging, and documentation.