React Forum
Blog & Guide Responses
Jul 02, 2022 · 04:00 AM

React Testing Library Intro - discussion (2022-07-02)

Started by Priya Liao
externaltestingreact testing libraryassertionssignals

If you're using React Testing Library, how do you keep tests stable when your app leans heavily on render signals and route-flow contracts?

Read the docs

Do you assert on user-visible output only, or do you treat signals as part of the test contract? What patterns help you avoid waiting/timing flake (especially with render fetch)? And how do you keep tests from turning into snapshots of implementation details?

Comments (10)

Back to latest
Noah Vance
Jul 02, 2022 · 04:06 AM

We assert on user-visible output first, then use signals to disambiguate.

If we assert only on signals, tests become too internal.

Dmitri Kline
Jul 02, 2022 · 04:14 AM

I like signals as a contract for why rather than what.

Example: assert the UI shows the right screen, then assert navIntent.reason to prove which guard/routine got you there.

We copied the pattern from Testing and Debugging and it made debugging failures dramatically faster.

Salma Qureshi
Jul 02, 2022 · 04:22 AM

We avoid timing waits by asserting on signal transitions instead of DOM timing.

ts
render(<App />);
await waitFor(() => expect(signal('fetch').status).toBe('ready'));
expect(screen.getByRole('heading', { name: /orders/i })).toBeInTheDocument();

The key is signals are set by the same contract that drives UI, so it stays deterministic across refactors.

Keira Santos
Jul 02, 2022 · 04:31 AM

Counterpoint: signals can make tests pass while the UX is broken (wrong text, focus, etc.).

We treat signals as secondary assertions only, never the primary proof.

Priya Liao
Jul 02, 2022 · 04:35 AM

Agree. The posture I like is: user-visible assertions + signals for explainability.

Signals are an observability layer, not the product.

Keira Santos
Jul 02, 2022 · 04:38 AM

Yep. The only time we lean on signals heavily is when we're testing navigation/guard contracts.

Theo Bennett
Jul 02, 2022 · 04:44 AM

If your render fetch posture is bypass, you need deterministic test data. Otherwise you're just testing the network.

We stub at the fetch boundary and still render fetch signals so the app behaves the same way, just with predictable responses.

Hana Saito
Jul 02, 2022 · 04:52 AM

We keep a tiny helper that reads signals from the DOM (data attributes) so tests don't depend on internal module imports.

ts
export function signal(name: string) {
  const el = document.querySelector(`[data-signal="${name}"]`);
  return el ? JSON.parse(el.getAttribute('data-value') ?? 'null') : null;
}
Maya Henson
Jul 02, 2022 · 05:03 AM

The trick is to keep signals stable and small. If signals are huge JSON blobs, your tests become snapshots anyway.

Amina Farouk
Jul 02, 2022 · 05:15 AM

We used RTL queries for the main assertions and then used signals to triage failures.

It's a nice compromise: tests remain user-centric, but failures are explainable without rerunning locally with devtools.

Jules Kwon
Jul 02, 2022 · 05:27 AM

If you're writing waitFor loops with arbitrary timeouts, add a signal instead.

You'll get a better app and better tests.

Related: Testing Signals (Deep Dive #12).

Benji Rios
Jul 02, 2022 · 05:41 AM

Also: don't make signals depend on localization. Keep them machine-readable, not stringly.