Q43 of 48 · Cypress
What testability requirements would you push for as part of code review?
Short answer
Short answer: Stable test attributes (`data-test`) on every interactive element, deterministic IDs (no random UUIDs in DOM), no hard-coded `Date.now()` for displayed values, hooks for resetting state in test environments, and avoidance of CSS-only behaviour that tests can't observe.
Detail
Testability isn't a QA concern handed off to developers — it's an architectural property the whole team owns. As a Cypress lead reviewing PRs, the testability changes I push for:
1. data-test attributes on every interactive element. Buttons, links, form fields, important containers. Naming convention: data-test=feature-action (kebab case, scoped). Lint or pre-commit can warn about new buttons without one.
2. Deterministic test IDs in lists. data-test=cart-row-{itemId} rather than data-test=cart-row for multi-item lists. Tests can address specific rows without .eq(N).
3. No live time in DOM strings. "2 hours ago", "Today at 3pm" — these break tests every hour. Either use stable format ("2026-05-10 13:00") or expose the timestamp as data-timestamp for tests to read.
4. Stable IDs in URLs and attributes. A new UUID per page load means the URL after click is unpredictable. Prefer stable slugs / paths where possible; if UUIDs are unavoidable, expose them as data-id attributes.
5. Test-mode hooks. A window.__test__ namespace (only populated in non-prod) where the app exposes utilities — clear local cache, dispatch a synthetic event, fast-forward animations. Don't bake test-only logic into prod paths.
6. Animations toggleable for tests. A CSS class .no-animations on html that the test environment sets, disabling transition and animation globally. Removes a major source of flake.
7. Avoid CSS-only state. A "selected" state expressed only as background-color is hard to assert on (colours change with themes). Add a class or attribute (aria-selected).
8. Network requests over local-only state. A computed value rendered from Math.random() on each render is hostile to tests. If it's user-meaningful, derive it from server state. If it's not, hide it.
9. ARIA roles and accessible names. getByRole-friendly markup (a meaningful <button>, a labelled <input>) helps both tests and users. A11y and testability are usually aligned.
10. Idempotent endpoints with explicit keys. Test setup often hits the API to seed state; idempotent endpoints with caller-supplied keys (POST /orders with Idempotency-Key header) make seed scripts safer to retry.
The cultural piece: framing these as shared engineering quality, not "QA's wishlist". A test-friendly app is also easier to debug, document, and maintain.