How would I write a passing test for the following? Where getLifestages is a working get API call that returns an array such as:
[{_id: 1, title: 'School'},{_id: 2, title: 'Work'}]
import { useQuery } from 'react-query';
const useLifestages = () => useQuery(
['GET_LIFESTAGES'],
getLifestages,
{
staleTime: params.staleTime,
keepPreviousData: true
}
);
const LandingScreen = () => {
const { data: lifestages, isLoading } = useLifestages();
if (isLoading) return <Loading />
return (
<ErrorBoundary>
<div className="container">
<header className="header">
Heading
</header>
<input
className="search-bar"
type='search'
role='search'
/>
{lifestages.map(lifestage => (
<div
key={lifestage._id}
lifestage={lifestage}
role='button'
/>
))}
</div>
</ErrorBoundary>
);
};
I want to mock the API response and what I’ve done so far hasn’t worked.
jest.mock('react-query', () => ({
useQuery: jest.fn().mockReturnValue(({
data: [{
_id: 1, title: 'School'
},{
_id: 2, title: 'Work'
}],
isLoading: false
}));
describe("Load landing screen", () => {
it("Renders the buttons", () => {
render(
<LandingScreen />
);
const button = screen.getByRole('button');
expect(button).toBeInTheDocument();
})
});
The error I’m seeing is this:
TypeError: Cannot destructure property 'data' of '(0 , _queries.useLifestages)(...)' as it is undefined.
8 |
9 |
> 10 | const { data: lifestages, isLoading } = useLifestages();
It seems to me that perhaps it’s because the data hasn’t returned from the call yet and is giving undefined. But clearly my mock isn’t working as it shouldn’t be calling the API at all ideally and instead using my mocked data. I’m a little confused as I’m new to testing async code so any help will be much appreciated!
2
Answers
I ran into a simliar error al while back, what i did was instead of using a mock I spied on the ReactQuery; like this:
Hope it helps.
This mocks the whole react-query library and just gives it a
useQuery
hook. I’m thinking that this won’t work because other vital parts are then missing. It’s like mockingReact
and only giving it auseEffect
hook …I think you would be much better off not mocking 3rd party libraries, but mocking what you have control over, which is either how the QueryFunction is implemented, or, by just mocking the network layer.
Mocking the network layer is what is recommended in the docs (e.g. with nock) and in my blog (e.g. with msw)
Advantages of mocking the network layer is that you’ll not only test if your component will work if
useQuery
returnsdata
, but also, what happens if it returns aloading
state. By mockinguseQuery
, this implementation would pass the test:but it would certainly die at runtime.