Reputation: 38652
I want to test a React Native application that I've created based on the default guides, so it's very simple and has not had any changes w.r.t. the initial test configuration. The only difference seems to be that it's using npm
instead of yarn
(so it has a package-lock.json
).
Here is the package.json
:
{
"name": "foo",
"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": "16.9.0",
"react-native": "0.61.5",
"react-native-gesture-handler": "^1.5.2",
"react-navigation": "^4.0.10",
"react-navigation-stack": "^1.10.3"
},
"devDependencies": {
"@babel/core": "^7.7.4",
"@babel/runtime": "^7.7.4",
"@react-native-community/eslint-config": "^0.0.5",
"babel-jest": "^24.9.0",
"eslint": "^6.7.1",
"jest": "^24.9.0",
"license-checker": "^25.0.1",
"metro-react-native-babel-preset": "^0.57.0",
"react-test-renderer": "16.9.0"
},
"jest": {
"preset": "react-native"
}
}
The test file __tests__/App-test.js
is very simple (and auto-generated):
import 'react-native';
import React from 'react';
import App from '../App';
// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';
it('renders correctly', () => {
renderer.create(<App />);
});
I get this error:
➜ npm test
> jest
FAIL __tests__/App-test.js
● Test suite failed to run
Jest encountered an unexpected token
This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
Here's what you can do:
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/en/configuration.html
Details:
/node_modules/@foo/bar/src/main.js:24
export function milliseconds(timeoutInMilliseconds) {
^^^^^^
SyntaxError: Unexpected token 'export'
Now, I don't really understand why it wouldn't work "out of the box". Other guides mention the same steps, too.
Adding a .babelrc
with:
{
"presets": ["react-native"]
}
produces the error:
Cannot find module 'babel-preset-react-native' from '/'
- If you want to resolve "react-native", use "module:react-native"
at Function.module.exports [as sync] (node_modules/resolve/lib/sync.js:74:15)
at resolveStandardizedName (node_modules/@babel/core/lib/config/files/plugins.js:101:31)
at resolvePreset (node_modules/@babel/core/lib/config/files/plugins.js:58:10)
at loadPreset (node_modules/@babel/core/lib/config/files/plugins.js:77:20)
at createDescriptor (node_modules/@babel/core/lib/config/config-descriptors.js:154:9)
at node_modules/@babel/core/lib/config/config-descriptors.js:109:50
at Array.map (<anonymous>)
at createDescriptors (node_modules/@babel/core/lib/config/config-descriptors.js:109:29)
at createPresetDescriptors (node_modules/@babel/core/lib/config/config-descriptors.js:101:10)
at presets (node_modules/@babel/core/lib/config/config-descriptors.js:47:19)
There is already a babel.config.js
file with the following contents (as suggested here):
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
};
What should I do? I've seen this question but the React App has not been upgraded and is not missing anything, AFAICT. Note that when I create a completely new app with the init script, the tests run fine.
Upvotes: 2
Views: 937
Reputation: 37288
You are using "react-navigation": "^4.0.10"
which uses react-native-gesture-handler
. Jest does not know about it. You have to mock react-native-gesture-handler
and add react-navigation
to transformIgnorePatterns
or use react-native-jest-mocks
.
Some examples of mocking react-native-gesture-handler
can be found here: https://github.com/software-mansion/react-native-gesture-handler/issues/344
Add "files": ["jest/setup.js"],"
inside package.json
. Also transformIgnorePatterns
must include react-navigation-stack
, @react-native-community
, react-native-gesture-handler
and react-navigation
.
package.json
:
"files": [
"jest/setup.js"
],
"jest": {
"preset": "react-native",
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js"
},
"setupFiles": ["./jest/setup.js"],
"testPathIgnorePatterns": [
"/node_modules/"
],
"transformIgnorePatterns": [
"node_modules/(?!(jest-)?react-native|react-navigation-stack|@react-native-community|react-native-gesture-handler|react-navigation|@react-navigation/.*)"
]
}
jest/setup.js
:
import { NativeModules as RNNativeModules } from "react-native";
RNNativeModules.UIManager = RNNativeModules.UIManager || {};
RNNativeModules.UIManager.RCTView = RNNativeModules.UIManager.RCTView || {};
RNNativeModules.RNGestureHandlerModule = RNNativeModules.RNGestureHandlerModule || {
State: { BEGAN: "BEGAN", FAILED: "FAILED", ACTIVE: "ACTIVE", END: "END" },
attachGestureHandler: jest.fn(),
createGestureHandler: jest.fn(),
dropGestureHandler: jest.fn(),
updateGestureHandler: jest.fn(),
};
RNNativeModules.PlatformConstants = RNNativeModules.PlatformConstants || {
forceTouchAvailable: false
};
jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper');
Now run jest and it should pass the test. I have created a repo with an example RN 0.61 app using react-navigation
that has jest test passing: https://github.com/clytras/RNJestTest
Or you can try react-native-jest-mocks
but I haven't tried it with RN 0.61 yet.
Upvotes: 2