简体   繁体   中英

How to mock a function of React Component and mount the component?

I have a react component that uses fetch API to get posts. Now while "jest testing" I want to mock fetch API method to return json data from a file. Mount the component for testing to count the number of posts by finding the class count. Below is the code.

Test file code

    import React from 'react';
    import { mount } from 'enzyme';
    import dummyjson from '../dummydata.json';
    import DemoApp from '../index';

    describe('xxxx test component', () => {
  it('first test', async () => {
    global.fetch = jest.fn(() => Promise.resolve(dummyjson));
    const wrapper = shallow(<DemoApp />, { disableLifecycleMethods: true });
    expect(wrapper.state('isLoaded')).toBe(false);
    await wrapper.instance().loadPosts();
    expect(wrapper.state('isLoaded')).toBe(true);
  });
    });

React component code

        import React from 'react';
    /* eslint class-methods-use-this: ['error', { 'exceptMethods': ['fetch'] }] */

    export default class DemoApp extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          error: null,
          isLoaded: false,
          items: [],
        };
      }

   componentDidMount() {
    this.loadPosts().then(
      (result) => {
        this.setState({
          isLoaded: true,
          items: result,
        });
      },
      (error) => {
        this.setState({
          isLoaded: true,
          error,
        });
      },
    );
  }

  loadPosts() {
    return fetch('https://jsonplaceholder.typicode.com/posts')
      .then(res => res.json()).then(result => result)
      .catch(error => error);
  }

      render() {
        const { error, isLoaded, items } = this.state;
        if (error) {
          return <div>Error: {error.message}</div>;
        } else if (!isLoaded) {
          return <div>Loading...</div>;
        }
        return (
          <div>
            {items.map(item => <div className="somecssclass"> {item.title} {item.title}</div>)}
          </div>
        );
      }
    }

Below is dummydata json

    [
    {
      "userId": 1,
      "id": 1,
      "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
      "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
    },
    {
      "userId": 1,
      "id": 2,
      "title": "qui est esse",
      "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
    }
]

I am getting below error below error/warning even though I provided below exception for fetch method in react component class file. /* eslint class-methods-use-this: ['error', { 'exceptMethods': ['fetch'] }] */

在此处输入图片说明

How can we fix this warning/error?

Any help is highly appreciated. Thanks.

There is race condition. loadPosts is asynchronous, while test is synchronous, and there is no promise to chain to wait for fetch promise chain to be fulfilled.

There are problems with control flow and testing methodology. loadPosts needs to return a promise, so it could be chained:

  loadPosts() {
    return fetch('https://jsonplaceholder.typicode.com/posts')...;
  }

A proper way to unit-test it is to test loadPosts in one test and test it directly:

  it('...', async () => {
    global.fetch = jest.fn(() => Promise.resolve(dummyjson));
    const wrapper = shallow(<DemoApp />, { disableLifecycleMethods: true });
    expect(wrapper.state('isLoaded').toBe(false);
    await wrapper.instance().loadPosts();
    expect(wrapper.state('isLoaded').toBe(true);
  });

And in another test loadPosts can be stubbed/mocked and asserted that it's called in componentDidMount .

Also notice that global.fetch = replaces it once and for all. It should preferably be mocked with jest.stub .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM