Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react-native-mapbox-gl/maps/setup-jest not working as expected #998

Closed
HughBoert opened this issue Aug 21, 2020 · 17 comments
Closed

react-native-mapbox-gl/maps/setup-jest not working as expected #998

HughBoert opened this issue Aug 21, 2020 · 17 comments
Labels
Needs: Author Feedback Needs: Verify on Latest Version Issue was filed against older version. wontfix This will not be worked on

Comments

@HughBoert
Copy link

HughBoert commented Aug 21, 2020

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?

@ClayC-WeatherBug
Copy link
Contributor

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'
};

@ferdicus
Copy link
Member

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 🙇

@ferdicus ferdicus added Needs: Author Feedback Needs: Verify on Latest Version Issue was filed against older version. labels Oct 23, 2020
@agabriele-radius
Copy link

I can verify that this happens on the latest version:

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

@ferdicus
Copy link
Member

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

@agabriele-radius
Copy link

agabriele-radius commented Nov 13, 2020

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

@ElZombieIsra
Copy link

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

@rossslaney
Copy link

rossslaney commented Dec 7, 2020

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

@ferdicus
Copy link
Member

ferdicus commented Dec 7, 2020

PRs are welcome :)

@stale
Copy link

stale bot commented Feb 8, 2021

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.

@stale stale bot added the wontfix This will not be worked on label Feb 8, 2021
@stale stale bot closed this as completed Feb 16, 2021
@matias91
Copy link

matias91 commented May 4, 2021

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"
  }
}

@ferdicus
Copy link
Member

ferdicus commented May 4, 2021

@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.

@matias91
Copy link

matias91 commented May 4, 2021

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

@ferdicus
Copy link
Member

ferdicus commented May 5, 2021

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

@matias91
Copy link

@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

@ferdicus
Copy link
Member

@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

@Sub-Zero-1
Copy link

Sub-Zero-1 commented Nov 24, 2021

@ferdicus Thank you very much! That mock worked for me!

@rodgomesc
Copy link

rodgomesc commented Jan 14, 2022

I was running into a issue that was blocking me to archive a great test coverage in components that uses a Mapbox.MapView because I can't get any children

in cases that we have

<Mapbox.MapView testID="mapview">
  <View testID="view1" />
  <View testID="view2" />
  <View testID="view3" />
  <MapBox.ETC testID="etc" />
</Mapbox.MapView>

if we try console.log(getByTesId("mapview").children)

the result will be a empty array always, as if none of the children existed, of course you also won't be able to catch any of the children by the id like

getByTesId("view1")
getByTesId("etc")

for now I create this workaround that solved the problem

jest.mock('@react-native-mapbox-gl/maps', () => {
  const MapBox = jest.requireActual('@react-native-mapbox-gl/maps');
  const {View} = jest.requireActual('react-native');
  MapBox.default.MapView = jest
    .fn()
    .mockImplementation(({children, ...rest}) => (
      <View {...rest}>{children}</View>
    ));

  return MapBox;
});

maybe some simpler solution could be implemented and sent in a pull request to @react-native-mapbox-gl/maps/setup-jest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs: Author Feedback Needs: Verify on Latest Version Issue was filed against older version. wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

9 participants