Maps: react-native-mapbox-gl/maps/setup-jest not working as expected

Created on 21 Aug 2020  路  15Comments  路  Source: react-native-mapbox-gl/maps

I followed the instructions to setup jest tests for react-native-mapbox-gl (adding '@react-native-mapbox-gl/maps/setup-jest' to setupFilesAfterEnv), but it destroys hundreds of tests written before.
I get SyntaxError: Unexpected token { on every test.

After adding mapbox-gl to transformIgnorePatterns in the jest config, half of the tests in the project are still failing with the exception Right-hand side of 'instanceof' is not an object.

When I flip the load order of the setupTests.js file and '@react-native-mapbox-gl/maps/setup-jest' I am getting errors Invariant Violation: Native module cannot be null regarding every test which targets components importing MapBoxGL.

It should not destroy my tests, nor break tests regarding the components importing MapboxGL when you do the jest setup shown in docs.

  • Platform: Android
  • react-native-mapbox-gl Version: 8.1.0-rc.2
  • React Native Version: 0.62.1

The package.json:

{
  "name": "my-app",
  "scripts": {
    "start": "react-native start --reset-cache",
    "test": "jest --verbose --collect-coverage",
    "android": "react-native run-android",
  },
  "dependencies": {
    "@react-native-community/async-storage": "^1.6.3",
    "@react-native-community/checkbox": "^0.2.2",
    "@react-native-community/geolocation": "^2.0.2",
    "@react-native-community/masked-view": "^0.1.7",
    "@react-native-community/netinfo": "^4.6.1",
    "@react-native-community/picker": "^1.3.0",
    "@react-native-mapbox-gl/maps": "^8.1.0-rc.2",
    "@react-navigation/native": "^5.1.5",
    "@react-navigation/stack": "^5.2.10",
    "@redux-offline/redux-offline": "^2.5.2-native.1",
    "@voximplant/react-native-foreground-service": "^2.0.0",
    "i18next": "^19.0.0",
    "moment-timezone": "^0.5.27",
    "react": "16.11.0",
    "react-dom": "16.9.0",
    "react-i18next": "^11.2.2",
    "react-native": "0.62.1",
    "react-native-camera": "^3.26.0",
    "react-native-gesture-handler": "^1.5.6",
    "react-native-permissions": "^2.0.4",
    "react-native-reanimated": "^1.2.0",
    "react-native-safe-area-context": "^0.7.3",
    "react-native-screens": "^2.7.0",
    "react-native-svg": "^12.0.3",
    "react-native-svg-transformer": "^0.14.3",
    "react-native-vector-icons": "^6.6.0",
    "react-native-version-check": "^3.4.0",
    "react-redux": "^7.1.1",
    "redux": "^4.0.4",
    "redux-thunk": "^2.3.0"
  },
  "devDependencies": {
    "@babel/core": "^7.9.0",
    "@storybook/addon-actions": "^5.3.1",
    "@storybook/addon-links": "^5.3.1",
    "@storybook/addons": "^5.3.1",
    "@storybook/react-native": "^5.3.1",
    "@storybook/react-native-server": "^5.3.1",
    "babel-eslint": "^10.0.3",
    "babel-jest": "24.9.0",
    "babel-loader": "^8.0.6",
    "babel-preset-expo": "^7.1.0",
    "detox": "^14.9.0",
    "enzyme": "^3.10.0",
    "enzyme-adapter-react-16": "^1.15.0",
    "eslint": "^6.3.0",
    "eslint-config-airbnb": "^18.0.1",
    "eslint-plugin-import": "^2.18.2",
    "eslint-plugin-jsx-a11y": "^6.2.3",
    "eslint-plugin-react": "^7.14.3",
    "eslint-plugin-react-hooks": "^2.2.0",
    "jest": "^24.9.0",
    "jest-enzyme": "^7.1.1",
    "jest-fetch-mock": "^2.1.2",
    "jetifier": "^1.6.4",
    "jsdom": "^15.1.1",
    "metro-react-native-babel-preset": "0.58.0",
    "react-native-dotenv": "^0.2.0",
    "react-test-renderer": "16.11.0",
    "redux-logger": "^3.0.6",
    "redux-mock-store": "^1.5.3"
  },
  "private": true,
  "detox": {
    "test-runner": "jest",
    "configurations": {
      "android.emu.debug": {
        "binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk",
        "build": "cd android ; ./gradlew app:assembleDebug app:assembleAndroidTest -DtestBuildType=debug ; cd -",
        "type": "android.emulator",
        "device": {
          "avdName": "smartphone"
        }
      },
      "android.emu.release": {
        "binaryPath": "android/app/build/outputs/apk/release/app-release.apk",
        "build": "cd android ; ./gradlew app:assembleRelease -Pcleartext='true' app:assembleAndroidTest -Pcleartext='true' -DtestBuildType=release ; cd -",
        "type": "android.emulator",
        "device": {
          "avdName": "smartphone"
        }
      }
    }
  }
}

The jest.config.js:

module.exports = {

  preset: 'react-native',

  testPathIgnorePatterns: [
    '/node_modules/',
  ],


  transformIgnorePatterns: [
    'node_modules/(?!((jest-)?react-native|react-clone-referenced-element|moment|expo(nent)?|@expo(nent)?/.*|@react-navigation|react-navigation|react-native-gesture-handler|@react-native-mapbox-gl/maps|@react-native-community))',
  ],

  automock: false,
  setupFilesAfterEnv: [
    '@react-native-mapbox-gl/maps/setup-jest',
    './setupTests.js',
  ],
};

The App was once an expo app that then got ejected. I do not know if this might cause any problems.
Or eventually there are known conflicts regarding my versions in package.json?

Author Feedback Verify on Latest Version wontfix

Most helpful comment

I have the same issue. It would be good to know if there's a solution in the horizon

All 15 comments

I just set this up a week or two ago and ran into the first issue until I added the transformIgnorePatterns bit. It sounds like maybe we need to update our docs to include that in the jest setup.

For the other issue, I don't remember seeing that particular error. Could you post an example of the code for a failing unit test and its setup? Maybe a stack trace so we can see exactly where it is failing?

I added this to a file in my __mocks__ folder as well, but I'm not sure if it will help fix your problem. You may have other parts of the code that you are using that you need to add to this as well, but even then I'm not sure that it will fix it for you:

export default {
    MapView: 'MapView',
    StyleURL: {
        Street: 'Street',
        Dark: 'Dark',
        Light: 'Light',
        Outdoors: 'Outdoors',
        Satellite: 'Satellite',
        SatelliteStreet: 'SatelliteStreet',
        TrafficDay: 'TrafficDay',
        TrafficNight: 'TrafficNight'
    },
    ShapeSource: 'ShapeSource',
    SymbolLayer: 'SymbolLayer',
    Camera: 'Camera'
};

hey @HughBoert, sorry for the late reply.
The invariant violation comes probably from Logger importing and using NativeEventEmitter.

I've set up a new react-native project and fiddled a bit with it.

I'm not sure what setupTests.js does, however do flip them around to cause the invariant violation issue and put this in node_modules/@react-native-mapbox-gl/maps/setup-jest.js:

jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter.js', () => {
  function MockEventEmitter() {}
  MockEventEmitter.prototype.addListener = jest.fn(() => ({remove: jest.fn()}));
  MockEventEmitter.prototype.removeListener = jest.fn();
  return MockEventEmitter;
});

let me know how that works out for you

Thanks 馃檱

I can verify that this happens on the latest version:

"@react-native-mapbox-gl/maps": "^8.1.0-rc.9"

Thanks for the comment @agabriele-radius.
Can you share your setup please?
Also, did you find a workaround?

This fails on an empty react-native init

Here's a sample repo I set up to prove this

package.json

There's a patch as per @ferdicus's comment above on the b/patches branch

This sample repo also fails build on ios as per https://github.com/react-native-mapbox-gl/maps/issues/1097

I have the same issue. It would be good to know if there's a solution in the horizon

jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter.js', () => {
  function MockEventEmitter() {}
  MockEventEmitter.prototype.addListener = jest.fn(() => ({remove: jest.fn()}));
  MockEventEmitter.prototype.removeListener = jest.fn();
  return MockEventEmitter;
});

This fixed the issue for me. Thanks for posting @ferdicus

PRs are welcome :)

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Hi, everyone!
I'm experiencing the same issue when I try to run my tests.
I tried @ferdicus suggestion, but after modifying setup-jest.js I got this error:

TypeError: _reactNative.NativeEventEmitter is not a constructor

    at Object.<anonymous> (node_modules/@react-native-mapbox-gl/maps/javascript/modules/location/locationManager.js:6:43)
    at Object.<anonymous> (node_modules/@react-native-mapbox-gl/maps/javascript/components/UserLocation.js:4:1)

This is a fresh RN project where I added react-native-mapbox-g.

Edited: complete package.json

{
  "name": "dollaridechallenge",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint ."
  },
  "dependencies": {
    "@react-native-mapbox-gl/maps": "^8.2.0-beta2",
    "@reduxjs/toolkit": "^1.5.1",
    "apisauce": "^2.1.1",
    "react": "17.0.1",
    "react-native": "0.64.0",
    "react-native-vector-icons": "^8.1.0",
    "react-redux": "^7.2.4",
    "redux": "^4.1.0",
    "redux-saga": "^1.1.3",
    "reduxsauce": "^1.2.0",
    "seamless-immutable": "^7.1.4"
  },
  "devDependencies": {
    "@babel/core": "^7.12.9",
    "@babel/runtime": "^7.12.5",
    "@react-native-community/eslint-config": "^2.0.0",
    "babel-jest": "^26.6.3",
    "eslint": "7.14.0",
    "jest": "^26.6.3",
    "metro-react-native-babel-preset": "^0.64.0",
    "react-test-renderer": "17.0.1"
  }
}

@matias91, I believe this is still the same issue.
The underlying issue is NativeEventEmitter which is a react-native module.
If you do not mock it, jest will attempt to call it and be like 馃し馃徔 .

You have to mock it in order to run the tests properly.

Thanks for the answer, @ferdicus!
I'll try to mock it

Thanks for the answer, @ferdicus!
I'll try to mock it

Just to be clear, this:

    jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter.js', () => {
      function MockEventEmitter() {}
      MockEventEmitter.prototype.addListener = jest.fn(() => ({remove: jest.fn()}));
      MockEventEmitter.prototype.removeListener = jest.fn();
      return MockEventEmitter;
    });

is supposed to mock it

@ferdicus, sorry for my late answer.
I added that and it didn't mock it. I'll take a look later, maybe I did something wrong.
But I did added that to the setup-jest.js

@matias91 , @agabriele-radius , @ElZombieIsra
coming back to this I noticed, that it doesn't seem to work with newer RN setups anymore 馃槥

However, I was able to mock it successfully by adding an extra setup file for jest like this:

// jest-setup.js
jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter.js', () => 
  require('react-native/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js')
);

then simply add this to your jest config in package.json:

"setupFilesAfterEnv": [
  "@react-native-mapbox-gl/maps/setup-jest",
  "<rootDir>/jest-setup.js"
]

Can you try and let me know if that helps?

Thanks

Was this page helpful?
0 / 5 - 0 ratings

Related issues

magnusburton picture magnusburton  路  3Comments

gmaclennan picture gmaclennan  路  3Comments

jayhaluska picture jayhaluska  路  5Comments

MariaSyed picture MariaSyed  路  4Comments

calypsow777 picture calypsow777  路  5Comments