I'm trying to test a react component where a fetch call occurs. The component:
class SearchResults extends React.Component<{ tag: string; setSpinner: (value: boolean) => void }> {
state: searchResultsState = {
results: [],
tag: '',
cardFull: null,
};
constructor(props: { tag: string; setSpinner: (value: boolean) => void }) {
super(props);
this.handleCardModal = this.handleCardModal.bind(this);
}
componentDidMount() {
getResponse(
this.props.tag,
(res) => {
this.setState({ results: res, tag: this.props.tag });
},
this.props.setSpinner
);
}
componentDidUpdate(prevProps: { tag: string }) {
if (this.props.tag !== prevProps.tag) {
getResponse(
this.props.tag,
(res) => this.setState({ results: res, tag: this.props.tag }),
this.props.setSpinner
);
}
}
handleCardModal() {
this.setState({ cardFull: null });
}
render() {
return (
<Fragment>
{this.state.cardFull && (
<CardFull data={this.state.cardFull} handleClick={this.handleCardModal} />
)}
{this.state.cardFull && <div className="blackout" onClick={this.handleCardModal} />}
<div className="search-results">
{this.state.results.length === 0 && this.state.tag !== '' && <div>Sorry, no matched</div>}
{this.state.results.map((result) => (
<CardUI
key={result.id}
className="card"
variant="outlined"
sx={{ minWidth: 275 }}
onClick={() => {
const currentCard = this.state.results.filter((res) => res.id === result.id)[0];
this.setState({ ...this.state, cardFull: currentCard });
}}
>
<CardMedia component="img" height="194" image={getUrl(result)} alt={result.title} />
<CardContent>
<p>{result.title}</p>
</CardContent>
</CardUI>
))}
</div>
</Fragment>
);
}
}
First I tried to use jest-fetch-mock.
import '@testing-library/jest-dom';
import { render } from '@testing-library/react';
import renderer from 'react-test-renderer';
import SearchResults from '../../src/components/SearchResults/SearchResults';
import sampleSearchResults from '../__fixtures__/sampleSearchResults';
import fetch from 'jest-fetch-mock';
fetch.enableMocks();
beforeEach(() => {
fetch.resetMocks();
});
const setSpinner = jest.fn();
describe('Search Results component', () => {
fetch.mockResponseOnce(JSON.stringify({ photos: sampleSearchResults }));
test('Search Results matches snapshot', () => {
const searchResults = renderer
.create(<SearchResults tag={''} setSpinner={setSpinner} />)
.toJSON();
expect(searchResults).toMatchSnapshot();
});
test('search results renders correctly', () => {
render(<SearchResults setSpinner={setSpinner} tag={'dove'} />);
});
});
But it gives the error during tests:
console.error
FetchError {
message: 'invalid json response body at reason: Unexpected end of JSON input',
type: 'invalid-json'
}
So, I've decided to mock fetch manually
import React from 'react';
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import renderer from 'react-test-renderer';
import SearchResults from '../../src/components/SearchResults/SearchResults';
import sampleSearchResults from '../__fixtures__/sampleSearchResults';
const setSpinner = jest.fn();
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ photos: sampleSearchResults }),
})
) as jest.Mock;
describe('Search Results component', () => {
test('Search Results matches snapshot', () => {
const searchResults = renderer
.create(<SearchResults tag={''} setSpinner={setSpinner} />)
.toJSON();
expect(searchResults).toMatchSnapshot();
});
test('search results renders correctly', () => {
render(<SearchResults setSpinner={setSpinner} tag={'dove'} />);
const title = screen.getByText(/Eurasian Collared Dove (Streptopelia decaocto)/i);
expect(title).toBeInTheDocument(); //mistake
});
});
Now fetch mock works correct, but it renders only one div - search results and doesn't render card. How can I test my component? Thank you.