Skip to content

chore(deps): adopt react-native-testing-library 14 - #192

Merged
simonvanlierde merged 1 commit into
mainfrom
chore/deps-rntl-14
Sep 7, 2026
Merged

chore(deps): adopt react-native-testing-library 14#192
simonvanlierde merged 1 commit into
mainfrom
chore/deps-rntl-14

Conversation

@simonvanlierde

@simonvanlierde simonvanlierde commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Completes #189, on top of the jest 30 that landed in #191.

RNTL v14 drops React 18 for React 19's async rendering. render, renderHook, fireEvent, act, rerender and unmount now return promises, and the renderer produces only host elements.

What changes outside tests

One component, plus the dependency bump itself (@testing-library/react-native 14.0.1, and test-renderer as its new peer).

AppButton wrapped only a lone string child. An interpolated label such as Select all ({onlineCount}) arrives as an array, so bare strings reached a View. React Native throws on that at runtime. v14 validates text placement unconditionally, which is how it surfaced.

Migration

The upstream rntl-v14-async-functions codemod did most of it. Three shapes it does not follow needed sweeping by hand. None of them leaves a type error behind, because a dropped promise just lets the test run on:

  • renderPlayer(), where the result is discarded
  • const result = render(...), where the result is used only at return
  • view.rerender(...), a method call on a result object

The codemod also put await inside a non-async arrow for expect(() => render(...)).toThrow(). An async render rejects rather than throws, so those became rejects.toThrow. I ran both against a wrong expected message to confirm they still fail.

The removed UNSAFE_* queries mostly became accessible queries. Where an assertion covers a prop no user can see, app/src/test-utils/host.ts finds the element by host name: a FlatList is RCTScrollView, an Svg is RNSVGSvgView. createNodeMock turned out unnecessary, because v14 host refs are non-null.

Coverage

Test count drops from 1818 to 1816. Both are the cameras column tests. numColumns never reaches a host element, and getCameraGridColumns already covers the mapping.

Two tests assert a null value before an async read resolves, which an awaited render now flushes past. Their token and storage reads are now held pending, so useAuthedMediaSource and useProductsWelcomeCard still guard what their comments claim.

getPrimaryFabIcon is now tested as the pure element factory it is.

Notes for reviewers

The login suite used to hang for 15 seconds. Its OAuth retry sleeps on setTimeout, fake timers are on globally, and the awaited press waited for a timer nothing advanced. The leaked act scope then failed the 12 tests after it. That file now runs in 1.3 seconds.

Verified locally: just check, just pre-commit, and just test (backend 1812, www 11, docs 161, app 1816). I also pointed the host helper at a bogus host name to confirm it discriminates.

Base automatically changed from chore/deps-major-repo-tooling to main September 7, 2026 06:02
v14 drops React 18 and adopts React 19's async rendering: render, renderHook,
fireEvent, act, rerender and unmount all return promises now, and the renderer
only ever produces host elements.

- run the upstream `rntl-v14-async-functions` codemod, then await what it does
  not follow: helpers defined inside test files, calls whose result is
  discarded, and `view.rerender(...)` on a result object. None of those leave a
  type error behind — a dropped promise simply lets the test run on
- replace the removed UNSAFE_* queries. Most become an accessible query; where
  the assertion is about a prop the user cannot see, src/test-utils/host.ts
  looks the element up by host name (a FlatList is RCTScrollView, an Svg is
  RNSVGSvgView)
- rewrite `expect(() => render(...)).toThrow()` as `rejects.toThrow`: an async
  render rejects, it does not throw, and the codemod left invalid syntax here
- hold the token and storage reads pending in the two tests that assert a
  transient pre-resolution state, which awaiting a render now flushes past
- advance fake timers around the OAuth retry backoff, which otherwise waits on
  a timer nothing advances and hung the suite for 15s
- test getPrimaryFabIcon as the pure element factory it is, rather than
  rendering it to look for composite types
- drop the two cameras column-count tests: numColumns never reaches a host
  element, and getCameraGridColumns already covers the mapping directly

AppButton only wrapped a lone string child, so an interpolated label
("Select all ({count})") reached a View as bare text — a runtime error on
device that v14's always-on text validation surfaced.
Comment on lines +13 to +19
import {
baseProduct,
mockPlatform,
queryAllHostsByProps,
queryAllHostsByType,
renderWithProviders,
} from '@/test-utils/index';
@simonvanlierde
simonvanlierde merged commit ee8a84d into main Sep 7, 2026
24 checks passed
@simonvanlierde
simonvanlierde deleted the chore/deps-rntl-14 branch September 7, 2026 06:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants