Replies: 2 comments 2 replies
-
what aspect of the component are you trying to test? |
Beta Was this translation helpful? Give feedback.
-
The specifics of the component could be anything, but a contrived example below. Obviously, I could just pass it down for this simple example, but pretend it's much deeper. Overall, I just don't want layers of nested components all having to care about the async status. I want gatekeepers higher in the tree so that the majority of them are simply data -> markup The test in this sandbox has a couple of the solutions I mentioned above, so not an insurmountable problem. I like the https://codesandbox.io/s/dreamy-mestorf-k4fyz // apiClient.getFilms does a `fetch`
const useFilms = () => useQuery('films', apiClient.getFilms)
const FilmsPage = () => {
const query = useFilms()
switch(query.status) {
case 'error' : return <div>Something went wrong!</div>
case 'loading': return <div>Loading...</div>
default: {
// Nothing lower in the tree needs to be concerned
// with loading or errors
return <div><FilmsList /></div>
}
}
}
const FilmsList = () => {
// this wouldn't be rendered unless `data` was defined
const films = useFilms().data.results
return (
<ul>
{films.map(({ title }) => (
<li key={title}>{title}</li>
))}
</ul>
)
} But then to render jest.spyOn(apiClient, 'getFilms').mockImplementation(async () => ({ results: mockFilms }))
it('fails to render', async () => {
// useFilms().data will be undefined on initial render
render(<FilmsList />)
}) |
Beta Was this translation helpful? Give feedback.
-
I'm curious how others are handing this issue. It's clear enough in simple examples, but I've been wrestling with the pattern for doing this at scale that's both nice to use in the code and easy to test.
My current pattern is using
react-async
along with contexts, so for each of these, I have a file such asOrderContext.js
that exports:OrderContext
- theReact.createContext()
resultOrderProvider
- loads the data and provides the result ofreact-async#useAsync
useOrder
- exposes thedata
of the contextFor each route, I have a top level
OrderPage
which renders a bunch ofProvider
s, watches the raw contexts, handles errors, and renders a spinner until they're all complete. This is convenient, because then I can write all of my display components to assume that the hooks they use provide a valid, synchronous value.These components are easy to test, as I simply wrap the component with
<OrderContext.Provider value={{ data: { mock: 'value' } }})>
,However, with
react-query
, the suggested pattern is to use the query result directly. I can still do the spinner pattern, which works well enough in the app, but when trying to test... now we have a problem. There is no way to avoid the asynchronicity, so there is always an initial render wheredata
isundefined
. I've played with various solutions, but none of these are particularly nice to use:ReactQueryCacheProvider
as in this discussion, but this means every single test needs to be aware of the structure of query keysjest.mock
is rather wordy when using dynamic resultsBeta Was this translation helpful? Give feedback.
All reactions