How to unit test API calls with mocked fetch() in

2020-02-11 17:26发布

In React Native I use fetch to perform network requests, however fetch is not an explicitly required module, so it is seemingly impossible to mock in Jest.

Even trying to call a method which uses fetch in a test will result in:

ReferenceError: fetch is not defined

Is there a way to test such API requests in react native with Jest?

7条回答
干净又极端
2楼-- · 2020-02-11 17:36

As @ArthurDenture recommended, you can use fetch-mock, but there are some additional packages you will need to install to make it work with React Native and Jest:

$ npm install --save-dev fetch-mock
$ npm install --save-dev babel-plugin-transform-runtime
$ npm install --save-dev babel-preset-env

You can then mock fetch requests in your tests. Here is an example:

// __tests__/App.test.js
import React from 'react';
import App from '../App';
import fetchMock from 'fetch-mock';
import renderer from 'react-test-renderer';

it('renders without crashing', () => {
  fetchMock.mock('*', 'Hello World!');
  const rendered = renderer.create(<App />).toJSON();
  expect(rendered).toBeTruthy();
});
查看更多
Summer. ? 凉城
3楼-- · 2020-02-11 17:38

Another approach where you mock the global fetch object:

const mockSuccesfulResponse = (
  status = 200,
  method = RequestType.GET,
  returnBody?: object
) => {
  global.fetch = jest.fn().mockImplementationOnce(() => {
    return new Promise((resolve, reject) => {
      resolve({
        ok: true,
        status,
        json: () => {
          return returnBody ? returnBody : {};
        },
      });
    });
  });
};

The above helper method can be modified any way you want :-) Hope it helps someone

查看更多
在下西门庆
4楼-- · 2020-02-11 17:40

Rather than rolling your own mock, you can use the jest-fetch-mock npm package to override the global fetch object. That package allows you to set up fake responses and verify sent requests. See that link for extensive usage examples.

查看更多
可以哭但决不认输i
5楼-- · 2020-02-11 17:42

Inside your test case you can mock any function you want by using Jest's mocks:

fetch = jest.fn(() => Promise.resolve());

This approach works only for the promise-based test cases (see pit in the Jest docs).

As far as fetch is an async function, you need to run all your tests using pit (read more about async tests here).

查看更多
爷的心禁止访问
6楼-- · 2020-02-11 17:47

As shown in the react-testing-library documentation, you can use the jest.spyOn() function, which will mock the fetch function only for the next time it is called.

const fakeUserResponse = {token: 'fake_user_token'}
jest.spyOn(window, 'fetch').mockImplementationOnce(() => {
  return Promise.resolve({
    json: () => Promise.resolve(fakeUserResponse),
  })
})

react-testing-library

查看更多
SAY GOODBYE
7楼-- · 2020-02-11 17:53

Suppose you want to test resolve and reject cases, for this first you mock the fetch behaviour and then use Jest's rejects and resolves methods with with assertion block


function fetchTodos() {
  return fetch(`${window.location.origin}/todos.json`)
    .then(response => response.json())
    .catch(error => console.log(error))
}
describe('fetchTodos', () => {
  it('returns promise resolving to parsed response', () => {
    global.fetch = jest.fn(() => Promise.resolve({ json: () => ''}))
    expect(fetchTodos()).resolves.toBe('');
  })
  it('returns promise handling the error', async () => {
    global.fetch = jest.fn(() => Promise.reject(''))
    expect(fetchTodos()).rejects.toBe('')
  })
})

查看更多
登录 后发表回答