I'm using React in my application. I'm making an API call in my componentDidMount
but it is conditional. My code in component is
componentDidMount() {
if (!this.props.fetch) {
fetchAPICall()
.then(() => {
/** Do something **/
});
}
}
I've written test as :
it('should not fetch ', () => {
const TFCRender = mount(<Component fetch />);
const didMountSpy = jest.spyOn(TFCRender.prototype, 'componentDidMount');
expect(didMountSpy).toHaveBeenCalledTimes(1);
expect(fetchAPICall).toHaveBeenCalledTimes(0);
});
The test is throwing me error as
TypeError: Cannot read property 'componentDidMount' of undefined
What am I doing wrong and what is the right way to test such case.
Make the API Call in componentDidMount()You should populate data with AJAX calls in the componentDidMount lifecycle method. So you can use setState to update your component when the data is retrieved.
Calling API in constructor() or componentWillMount() is not a syntax error but increases code complexity and hampers performance. So, to avoid unnecessary re-rendering and code complexity, it's better to call API after render(), i.e componentDidMount().
An example of when to use componentDidUpdate() is when we need to call an external API on condition that the previous state and the current state have changed. The call to the API would be conditional to the state being changed. If there is no state change, no API is called.
Using componentWillMount() to Make API Calls One of the primary usages of componentWillMount() is to make API calls once the component is initiated and configure the values into the state. To make an API call, use an HttpClient such as Axios , or or you can use fetch() to trigger the AJAX call.
From the official docs, you need to spy
the component before mounting it.
Following is a working example that I have created with create-react-app. I've also added some comments in the example code:
App.js
import { fetchAPICall } from './api';
class App extends Component {
componentDidMount() {
if (!this.props.fetch) {
fetchAPICall().then(console.log);
}
}
render() {
return <div>Testing the result</div>;
}
}
export default App;
api.js
export const fetchAPICall = () => {
return Promise.resolve('Getting some data from the API endpoint');
};
App.test.js
import Component from './App';
import * as apis from './api'; // assuming you have a separate file for these APIs
// Mock the fetchAPICall, and since the data fetching is asynchronous
// you have to mock its implementation with Promise.resolve()`
apis.fetchAPICall = jest.fn(() => Promise.resolve('test'));
describe('spyOn', () => {
let didMountSpy; // Reusing the spy, and clear it with mockClear()
afterEach(() => {
didMountSpy.mockClear();
});
didMountSpy = jest.spyOn(Component.prototype, 'componentDidMount');
test('should not fetch ', () => {
// Ensure the componentDidMount haven't called yet.
expect(didMountSpy).toHaveBeenCalledTimes(0);
const TFCRender = mount(<Component fetch />);
expect(didMountSpy).toHaveBeenCalledTimes(1);
expect(apis.fetchAPICall).toHaveBeenCalledTimes(0);
});
test('should fetch', () => {
expect(didMountSpy).toHaveBeenCalledTimes(0);
const TFCRender = mount(<Component fetch={false} />);
expect(didMountSpy).toHaveBeenCalledTimes(1);
expect(apis.fetchAPICall).toHaveBeenCalledTimes(1);
});
});
Not sure if this is the best practice, but this is how I usually write my own tests.
Hope this help!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With