I'm trying to test a SolidJS component which shows a "Track not found" message when returning 404 from the API. The code works fine when running, but Vitest throws a Vitest caught 1 unhandled error during the test run. This might cause false positive tests.
error.
Similar.tsx:
const Tracks: Component<Params> = (props) => {
return (
<Show
when={!tracks.error}
fallback={<ErrorMessage message="Track not found" />}
>
<div class="tracks">
<For
each={tracks()}
fallback={<ErrorMessage message="No similar tracks found" />}
>
{(track) => (
<Track
name={track.name}
artist={track.artist.name}
image={track.image[3]['#text']}
url={track.url}
/>
)}
</For>
</div>
</Show>
);
};
And this is the test suite I'm running:
it('renders a "Track not found" message if API returns 404', async () => {
vitest
.spyOn(fetchSimilarTracks, 'default')
.mockRejectedValueOnce(new Error('Track not found'));
const { findByText } = renderSimilar({
track: 'hdsauidhas',
artist: 'hdsduhsd',
});
expect(await findByText('Track not found')).toBeInTheDocument();
});
After looking through the docs a bit, I realized that I missed the following entry:
data works like a normal signal getter: use data() to read the last returned value of fetchData. But it also has extra reactive properties: data.loading tells you if the fetcher has been called but not returned, and data.error tells you if the request has errored out; if so, it contains the error thrown by the fetcher. (Note: if you anticipate errors, you may want to wrap createResource in an ErrorBoundary.)
So what I did was, instead of using <Show />
for conditionally rendering the Error Message, wrap Tracks
into an <ErrorBoundary />
and provide <ErrorMessage />
as a fallback there:
<ErrorBoundary fallback={<ErrorMessage message="Track not found" />}>
<Tracks track={params.track} artist={params.artist} />
</ErrorBoundary>
So this is how <Tracks />
should look like:
const Tracks: Component<Params> = (props) => {
return (
<div class="tracks">
<For
each={tracks()}
fallback={<ErrorMessage message="No similar tracks found" />}
>
{(track) => (
<Track
name={track.name}
artist={track.artist.name}
image={track.image[3]['#text']}
url={track.url}
/>
)}
</For>
</div>
);
};