5

I'm trying to run some tests with Jest on my react/react-native library (only some business logic inside).

We are testing actions that uses fetch function (polyfill with whatwg-fetch). I've added whatwg-fetch (thanks to Safari) for react.

Whenever i try to run a test, i'm getting this error:

TypeError: Cannot read property 'fetch' of undefined

  at node_modules/whatwg-fetch/fetch.js:4:11
  at Object.<anonymous> (node_modules/whatwg-fetch/fetch.js:461:3)
  at Object.<anonymous> (node_modules/jest-expo/src/setup.js:138:416)

What can cause this issue? Is there a way in the jest config to avoid this?

Here are some files for debug:

Jest config in package.json

"jest": {
"preset": "jest-expo",
"moduleFileExtensions": [
  "js",
  "jsx",
  "ts",
  "tsx"
],
"verbose": true,
"transform": {
  "^.+\\.(js|ts|tsx)$": "<rootDir>/node_modules/babel-jest"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"testPathIgnorePatterns": [
  "\\.snap$",
  "<rootDir>/node_modules/",
  "<rootDir>/dist/"
],
"transformIgnorePatterns": [
  "node_modules/?!react-native"
]
},

Webpack config:

const config = {
entry: [
    'whatwg-fetch',
    __dirname + '/src/index.ts',
],
devtool: 'source-map',
output: {
    path: path.join(__dirname, '/dist'),
    filename: 'index.js',
    library: 'checkinatwork-module',
    libraryTarget: 'umd',
    umdNamedDefine: true,
},
module: {
    loaders: [
        { test: /\.(tsx|ts)?$/, loader: 'ts-loader', exclude: /node_modules/ },
    ],
},
resolve: {
    modules: [
        './src',
        'node_modules',
    ],
    extensions: ['.js', '.ts', '.jsx', '.tsx', 'json'],
},
plugins: [
],
};

Test file:

import expect from 'expect';
import * as actions from '../../src/components/Checkin/checkin.action';
import * as reducers from '../../src/components/Checkin/checkin.reducer';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import nock from 'nock';

const middlewares = [ thunk ];
const mockStore = configureMockStore(middlewares);

describe('=> ADD CHECKIN ACTIONS', () => {
  describe('- REQUEST', () => {
    it('Action: ADD_CHECKIN_REQUEST should request addCawCheckin', () => {
      const expectedAction = {
        type: actions.ADD_CHECKIN_REQUEST,
        isFetching: true,
      };
      expect(actions.addCheckinRequest())
        .toEqual(expectedAction);
    });
    it('Reducer: newCheckin should trigger ADD_CHECKIN_REQUEST and initiate loading', () => {
      const expectedState = {
        isFetching: true,
        status: null,
      };
      expect(reducers.newCheckin(reducers.newCheckinDefaultState, actions.addCheckinRequest()))
        .toEqual(expectedState);
    });
  });

Action file:

export const getCheckins = (sessionId, date, url, isRefresh) => {
  const config = {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      sessionId: {sessionId},
      date: {date},
    }),
  };

  return dispatch => {
    if (!isRefresh) {
      dispatch(getCheckinsRequest());
    }
    return fetch(url + 'getCAWCheckIns', config)
      .then(response => response.json())
      .then(({ checkins }) => {
        dispatch(getCheckinsSuccess(checkins));
      }).catch(err => {
        dispatch(getCheckinsError('Get checkins failed'));
        console.error('Get checkins failed: ', err);
      });
  };
};

Thanks!

Canta
  • 1,480
  • 1
  • 13
  • 26
clems36
  • 922
  • 1
  • 13
  • 26

4 Answers4

0

I've done it in the spec with:

import { fetch } from 'whatwg-fetch';

global.fetch = fetch;

And it has worked as expected with Jest.

Samuli Hakoniemi
  • 18,740
  • 1
  • 61
  • 74
0

might be late to the game, but this worked for me.

Possible solution #1

Note: React.PropTypes is deprecated as of React v15.5. Please use the prop-types library instead.

If you install the npm package prop-types, it has isomorphic-fetch as a dependency. This will give you fetch as a global. You will still need to import it into your test file. You might need to exclude it from your linter too.

add this to the top of the test file.

import fetch from 'isomorphic-fetch'

I didn't need to call fetch in the test suite, but I needed to make it available.

If you use this approach, I think you would remove the 'whatwg-fetch', from your webpack entry

Hope this helps

Updated: Possible solution #2

Using the example of @zvona from above, but create a MOCKS folder in your app. then a file /globalMock.js. You might not have set it up properly.

   __MOCKS__/globalMock.js

   // use one of these imports 

   import { fetch } from 'whatwg-fetch' // if you want to keep using the polyfill

   import { fetch } from 'isomorphic-fetch' // from a dependency node module that I spoke of in the previous solution.

   global.fetch = fetch

Now in package.json

add this to your Jest configuration:

"jest": {
    "verbose": true,
    "rootDir": "app",
    "setupFiles": ["<rootDir>/__MOCKS__/globalMock.js"]
  }

this will allow the use of fetch in your tests.

I also had to use this same concept for localStorage. Where I keep all of my globals that Jest doesn't have access.

J. Parrish
  • 36
  • 2
  • Not late at all! I di as you said but still have the issue... I also tried putting isomorphic-fetch as my webpack entry but it didn't change anything, the error message is still the same. – clems36 May 23 '17 at 07:16
  • Added an update, also just saw this on the [fetch](https://github.com/github/fetch) github docs: "If this polyfill doesn't work under Node.js environments, that is expected, because this project is meant for web browsers only. You should ensure that your application doesn't try to package and run this on the server." – J. Parrish May 23 '17 at 18:13
  • Hi, I made those changes but still no luck. I'm thinking about moving from fetch to axios as a solution... Thanks for your help. – clems36 May 24 '17 at 07:25
0

Upgrading react-native, jest, and babel-jest to the latest versions fixed this issue for us.

Freewalker
  • 6,329
  • 4
  • 51
  • 70
0

This worked for me. In your expo set up file(node_modules/jest-expo/src/setup.js) where it requires whatwg-fetch, I changed that require to require('fetch-everywhere')

const { Response, Request, Headers, fetch } = 
  require('fetch-everywhere');
global.Response = Response;
global.Request = Request;
global.Headers = Headers;
global.fetch = fetch;

For some reasons, only fetch everywhere was working with expo and jest.

Jolaade Adewale
  • 326
  • 5
  • 10