Jest: Jest React Native - Invariant Violation: Native module cannot be null.

Created on 2 Dec 2016  ·  26Comments  ·  Source: facebook/jest

Do you want to request a feature or report a bug?
bug

What is the current behavior?
When I run 'npm run jest', I got an error like this.
Invariant Violation: Native module cannot be null.

  at invariant (node_modules/fbjs/lib/invariant.js:38:15)
  at Linking.NativeEventEmitter (node_modules/react-native/Libraries/EventEmitter/NativeEventEmitter.js:32:1)
  at new Linking (node_modules/react-native/Libraries/Linking/Linking.js:119:141)
  at Object.<anonymous> (node_modules/react-native/Libraries/Linking/Linking.js:191:16)
  at Object.get Linking [as Linking] (node_modules/react-native/Libraries/react-native/react-native.js:91:22)
  at Object.<anonymous> (node_modules/react-native-experimental-navigation/NavigationRootContainer.js:15:36)

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal repository on GitHub that we can npm install and npm test.

  1. cd react-native-router-flux
  2. npm install
  3. cd Example
  4. npm install
  5. npm run jest

https://github.com/MechanicKim/react-native-router-flux

What is the expected behavior?
Pass the jest test and update snapshot

Run Jest again with --debug and provide the full configuration it prints. Please mention your node and npm version and operating system.
Darwin 16.1.0
node v7.2.0
npm v3.10.9

Most helpful comment

Figured it out

Created a file jest/setup.js with the following content

jest.mock('Linking', () => {
  return {
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    openURL: jest.fn(),
    canOpenURL: jest.fn(),
    getInitialURL: jest.fn(),
  }
})

Add changed my package.json

...
"jest": {
    "preset": "react-native",
    "setupFiles": ["jest/setup.js"]
},
...

Although there has been some change behaviour because previously this mock was not required.

All 26 comments

Set the preset to "react-native" and remove jest-react-native. It isn't needed any more with 0.38!

@cpojer I did it but I got same error.

2016-12-02 22:14 GMT+09:00 Christoph Pojer notifications@github.com:

Closed #2208 https://github.com/facebook/jest/issues/2208.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/facebook/jest/issues/2208#event-879961144, or mute
the thread
https://github.com/notifications/unsubscribe-auth/ALlkF0cZy0p2Dnf-cHN7XkLXpu01K2Caks5rEBm_gaJpZM4LCgV1
.

I am also getting this error.

Steps to reproduce:

  • react-native init a fresh project with 0.39
  • run jest, tests pass
  • Add dependency "react-native-router-flux": "^3.37.0"
  • Add import import { Router, Scene } from 'react-native-router-flux'
  • run jest, get the above error

The current jest setup.js does not mock out Linking.

I was able to get past the error by adding

Linking: {
  addEventListener: jest.fn(),
  removeEventListener: jest.fn(),
  openURL: jest.fn(),
  canOpenURL: jest.fn(),
  getInitialURL: jest.fn(),
},

After AsyncLocalStorage {...},

The problematic line is const Linking = require('react-native').Linking; from the react-native-experimental-navigation fork that react-native-router-flux uses.

package.json:

{
    "name": "test",
    "version": "0.0.1",
    "private": true,
    "scripts": {
        "start": "node node_modules/react-native/local-cli/cli.js start",
        "test": "jest"
    },
    "dependencies": {
        "react": "15.4.1",
        "react-native": "^0.39.0",
        "react-native-router-flux": "^3.37.0"
    },
    "jest": {
        "preset": "react-native"
    },
    "devDependencies": {
        "babel-jest": "17.0.2",
        "babel-preset-react-native": "1.9.0",
        "jest": "17.0.3",
        "react-test-renderer": "15.4.1"
    }
}

@cpojer Is there any way to mock out react native Linking globally without duplicating the setup.js file?

Figured it out

Created a file jest/setup.js with the following content

jest.mock('Linking', () => {
  return {
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    openURL: jest.fn(),
    canOpenURL: jest.fn(),
    getInitialURL: jest.fn(),
  }
})

Add changed my package.json

...
"jest": {
    "preset": "react-native",
    "setupFiles": ["jest/setup.js"]
},
...

Although there has been some change behaviour because previously this mock was not required.

I've got this problem as well on RN 38 with Jest 17.0.3. The problem is coming from NetInfo and react-native-router-flux. This is how i Implemented this from your solution :

jest.mock('Linking', () => {
  return {
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    openURL: jest.fn(),
    canOpenURL: jest.fn(),
    getInitialURL: jest.fn(),
  }
});

jest.mock('NetInfo', () => {
  return {
    isConnected: {
      fetch: () => {
        return new Promise((accept, resolve) => {
          accept(true);
        })
      }
    }
  }
});

@cliedeman Worked me for me thanks! However I feel like RN or Jest needs to figure it out. :)

I think it's more the job of the react-native preset to figure it out, rather than jest itself

We merged this preset back into react-native; please send mocks and PRs directly there.

I'll give it a shot when i'll have some time.

the same thing happened to me, had to

jest.mock('PushNotificationIOS', () => ({
  addEventListener: jest.fn(),
  requestPermissions: jest.fn(),
}));

Cleaner solution using __mocks__
Create __mocks__ directory next to __tests__ and place react-native.js with

const rn = require('react-native')
jest.mock('Linking', () => {
  return {
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    openURL: jest.fn(),
    canOpenURL: jest.fn(),
    getInitialURL: jest.fn(),
  }
})
module.exports = rn

Edited; I had to refer to the file via "./jest/setup.js" since updating, before the "jest/setup.js" was working without any issues (I found the solution here: https://github.com/facebook/react-native/issues/11585)


Any update on this? I was using this workaround:
"jest": { "preset": "react-native", "setupFiles": [ "jest/setup.js" ], "collectCoverage": true, "verbose": true },

But since updating all my packages to the latest versions today, Jest keeps giving this error:
Error: Jest: Module "jest/setup.js" in the "setupFiles" option was not found.

Any clue why it can no longer find the file? It hasn't moved or anything.

Kind regards,

@JeroenNelen I've managed to workaround this with prepending <rootDir>:
"jest": { "preset": "jest-react-native", "setupFiles": [ "<rootDir>/jest-setup.js" ] }

Ugly, but works.

In Jest 18.1, doing ./jest-setup.js will be resolved from the location of package.json.

Should there be a solution to mock custom components directly in jest ? A flow-typed like repository for example.

That might be cool!

I have a similar issue. I have a saga that is importing:

import Camera from 'react-native-camera';

This throws the error:

 FAIL  js/sagas/App/__tests__/watchCheckDevicePermissions-test.js
  ● Test suite failed to run

    TypeError: Cannot read property 'Aspect' of undefined

      at Object.<anonymous> (node_modules/react-native-camera/index.js:254:78)
      at Object.<anonymous> (js/sagas/App/watchCheckDevicePermissions.js:26:95)
      at Object.<anonymous> (js/sagas/App/__tests__/watchCheckDevicePermissions-test.js:2:34)

I tried to define a Camera mock in ./js/jest/setup.js:

jest.mock('Camera', () => {
    return {
        Aspect: {}
    }
});

Which is required in package.json setupFiles. All my tests start throwing the error:

Cannot find module 'Camera' from 'setup.js'

I also get the Invariant error for other libraries. For example, Pusher. I get the Cannot find module warning if I try to mock Pusher:

jest.mock('Pusher', () => {
    return {
        addEventListener: jest.fn(),
        removeEventListener: jest.fn()
    }
});

This is my jest config in package.json:

  "jest": {
    "preset": "react-native",
    "setupFiles": ["./js/jest/setup.js"],
    "transformIgnorePatterns": [
      "node_modules/(?!react-native||@shoutem)"
    ]
  },

React version: 15.4.2
React-native version: ^0.40.0
Jest version: ^19.0.0

I got it working, but had to add the following to my jest/setup.js file (to get my saga tests running):

jest.mock('PushNotificationIOS', () => ({
    addEventListener: jest.fn(),
    requestPermissions: jest.fn(),
}));
jest.mock('react-native', () => ({
    NetInfo: {
        addEventListener: jest.fn(),
        fetch: () => {
            return {
                done: jest.fn()
            }
        }
    },
    NativeModules: {
        RNPasscodeStatus: {
            supported: jest.fn(),
            status: jest.fn(),
            get: jest.fn()
        }
    },
    Dimensions: {
        get: () => ({
            width: jest.fn(),
            height: jest.fn()
        })
    },
}));
jest.mock('react-native-camera', () => {
});

Is this overkill? Also, I need to explicitly call jest.unmock('react-native') in my component tests.

Hmmm, I've had to amend these slightly. I'm using react-native-push-notification version 2.2.1.

jest.mock('PushNotificationIOS', () => {
  return {
    addEventListener: jest.fn(),
    requestPermissions: jest.fn(() => Promise.resolve()),
    getInitialNotification: jest.fn(() => Promise.resolve()),
  }
});

Because requestPermissions and getInitialNotification seem to return a promise now. Would love this to be stable.

For anyone having issues with react-native-router-flux, I had this problem today, and went with this solution https://github.com/facebook/jest/issues/2208#issuecomment-269847217

Quick and painless.

@andrewhl Were you able to successfully mock pusher? Im having trouble getting my tests fixed because of the Invariant Violation: Native module cannot be null. error

@kyangy I think in the end I didn't need to. The library that was causing problems was react-native-push-notification, which I mocked as follows:

jest.mock('react-native-push-notification', () => {
    return {
        addEventListener: jest.fn(),
        removeEventListener: jest.fn(),
        requestPermissions: jest.fn(),
        configure: jest.fn()
    }
});

Have you tried creating a jest/__mocks__/pusher.js file that looks something like:

module.exports = {
    // whatever methods or properties are being accessed via the pusher object
}

I was able to narrow down exactly what libraries and methods needed to be mocked by systematically removing all imports from the component/file under test, and commenting out a lot of code, and reintroducing things one at a time. I mocked whatever caused the test to squawk.

Has any one had the same issue with react-native-callkit ?

 Invariant Violation: Native module cannot be null.

      635 | }
      636 |
    > 637 | export default function app(state = initialState, action) {
      638 |   switch (action.type) {
      639 |     case INIT:
      640 |       return {

      at invariant (node_modules/fbjs/lib/invariant.js:42:15)
      at new NativeEventEmitter (node_modules/react-native/Libraries/EventEmitter/NativeEventEmitter.js:37:1)
      at Object.<anonymous> (node_modules/react-native-callkit/index.js:10:23)

I've tried the solutions above but I gather I'm not mocking the right functions. Does any one have any ideas on what exactly should be mocked?

getting same error message after implementing react-native-gps-state module into the project.can someone please suggest how to mock one.

jest.mock('react-native-gps-state', () => {
  return {
    nativeMethodToMock: jest.fn(),
    anotherNativeMethod: jest.fn()
  }
})

came across this when using react-navigation-drawer. Created __mocks__/react-navigation-drawer.js with

jest.mock('react-navigation-drawer', () => {
    return {
      addEventListener: jest.fn(),
      createDrawerNavigator: jest.fn(),
    }
  });

But then the error gets replaced with createDrawerNavigator is not a function. Am I doing something wrong?

Was this page helpful?
0 / 5 - 0 ratings