5

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.

Ajay Gaur
  • 5,140
  • 6
  • 38
  • 60
  • 1
    You have to mock the `fetchAPICall` and test whether it has been called – sunpietro May 15 '18 at 07:50
  • check this once,it might help https://stackoverflow.com/questions/43245040/using-jest-to-spy-on-method-call-in-componentdidmount – Jayavel May 15 '18 at 09:25

1 Answers1

4

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!

Joshua
  • 3,055
  • 3
  • 22
  • 37