React Testing Library Intro - discussion (2023-02-09)
RTL's intro is still the best antidote to tests that mirror component structure instead of user behavior. In apps that rely on explicit lanes, route contracts, and visible evidence keys, RTL gets even better because you can assert on "what the user sees" plus a tiny slice of contract truth.
What do you assert on first: roles/text, or evidence attributes/lane indicators? How do you keep async tests stable without waitFor loops and arbitrary timeouts? Do you treat evidence keys as a public UI surface (support/debug) or as testing-only helpers?
Comments (14)
Back to latestRoles/text first, then one evidence key if it explains a lane or posture.
If you assert too much evidence, you couple tests to vocabulary churn.
We stopped using timeouts when we made lane transitions explicit and testable. The logs and the UI evidence align, so failures are diagnosable:
txt
[tips] lane=pending reason=submit:blur
[tips] lane=ok reason=server:confirm
Then the test just waits for lane=ok (via content or attribute).
Counterpoint: evidence keys can become a second API that nobody maintains.
If evidence doesn't help humans debug, it shouldn't exist. Tests should benefit from human evidence, not drive it.
Yes. I like the rule: evidence must be readable in a screenshot.
If the evidence key isn't meaningful to a human, it's probably too implementation-y for tests too.
Async stability came from making pending states real UI states.
If the UI renders pending and ok, tests can be deterministic without mock timers.
Long-form: RTL succeeds when the UI is accessible and semantic.
If you can't query by role, it's often a sign the UI doesn't have a good user-level contract. Improving semantics improves both tests and UX.
We also like a visually-hidden debug element that prints a compact contract summary (lane/posture/identity).
RTL can query it like normal content and it stays accessible.
Counterpoint: sometimes tests should reach into explicit contracts (like a vault) to set up a state quickly.
But assertions should still be user-level plus evidence-level, not internal-level.
We treat contract logs as the companion to tests.
When a test fails, a stable log line like [tips] lane=... reason=... is faster than stepping through a debugger.
Long-form counterpoint: if your tests are flaky, it might be because your app has hidden async work.
The fix isn't more retries; it's exposing the work as a lane and making the lane observable in UI.
Docs tie-in: the forum's evidence posture is basically a testing posture.
Related: Testing and Debugging and Performance and Rendering (Best Practices).
We also test "posture" changes (hot/warm/cool) by asserting on the evidence key rather than trying to measure performance in unit tests.
E2E can validate performance; unit tests validate contract decisions.
Counterpoint: evidence keys can tempt teams to stop writing good assertions (they assert on one attribute and call it a day).
We require one user-level assertion per test so we don't drift into contract-only testing.
RTL is still the best way to keep tests from turning into a UI implementation mirror.
If you pair it with a small evidence layer, you get both user truth and contract truth in a stable way.
A good test suite reads like the contract story: intent -> lane -> result.
RTL helps you keep it user-shaped, and evidence/logs help you keep it debuggable.