How to configure Jest to work with Expo SDK 32 - react-native

I have an Expo app and was using SDK 28. My team decided we should update to the latest version, that meant updating React Native (Since the latest SDK uses RN 0.57) and Babel.
When we updated our dependencies, and fixed our config files, Jest started to give us this error:
TypeError: Cannot read property 'fetch' of undefined
at node_modules/react-native/Libraries/vendor/core/whatwg-fetch.js:6:12
at Object.<anonymous> (node_modules/react-native/Libraries/vendor/core/whatwg-fetch.js:486:3)
at Object.<anonymous> (node_modules/jest-expo/src/setup.js:125:16)
After a few days debugging I found out this is related to babel-jest's pre-processor not working correctly, even though I followed their installation docs.
I dug around some more and found out that there's a workaround in this GitHub Issue thread.
Implementing the workaround, plus adding babel-hoist to my babel.config.js, made so that the tests started running.
However Jest's behavior is all wonky and the coverage data is not correct (it counts some lines as uncovered, even though we do have tests for them).
I want to know how to configure Jest properly for compatibility with Expo SDK 32.
These are the relevant config files (which are set to use the workaround mentioned previously).
package.json*
"dependencies": {
"#babel/preset-env": "^7.3.1",
"#expo/vector-icons": "6.3.1",
"expo": "^32.0.0",
"prop-types": "15.6.2",
"react": "16.5.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
"sentry-expo": "~1.9.0"
...
},
"devDependencies": {
"#babel/core": "^7.2.2",
"babel-eslint": "9.0.0",
"babel-plugin-jest-hoist": "^24.0.0",
"babel-preset-expo": "^5.0.0",
"enzyme": "3.8.0",
"enzyme-adapter-react-16": "^1.8.0",
"jest-expo": "^32.0.0",
"metro-react-native-babel-preset": "^0.51.1",
"react-dom": "^16.5.1",
...
},
"jest": {
"preset": "jest-expo",
"transform": {
"^.+\\.js$": "<rootDir>/jest.preprocessor.js"
},
"setupFiles": [
"<rootDir>/src/jest.setup.js"
],
...
}
* Some dependecies were omitted.
babel.config.js
module.exports = {
presets: [
'babel-preset-expo',
'module:metro-react-native-babel-preset',
'module:react-native-dotenv',
[
'#babel/preset-env',
{
targets: {
node: 'current',
},
},
],
],
sourceMaps: true,
plugins: [
'jest-hoist',
'#babel/transform-react-jsx-source',
],
};

This is what solved the problem for me:
First thing, install yarn. Follow this link for instructions.
Second, ensure your package.json looks something like this:
"dependencies": {
"#expo/vector-icons": "9.0.0",
"expo": "^32.0.0",
"prop-types": "15.6.2",
"react": "16.5.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
...
},
"devDependencies": {
"babel-preset-expo": "^5.0.0",
"jest-expo": "^32.0.0",
...
}
"scripts": {
"test": "jest",
...
},
"jest": {
"preset": "jest-expo",
"transform": {
"^.+\\.js$": "babel-jest"
},
}
Third, ensure your babel.config.js is setup correctly. Here's the one from my project running Expo's SDK 32:
module.exports = function (api) {
api.cache(true);
return {
presets: [
'babel-preset-expo',
'module:react-native-dotenv',
],
sourceMaps: true,
plugins: [
'#babel/transform-react-jsx-source',
],
};
};
Lastly, use yarn to install your packages (yarn install) and to run your tests yarn test.

Expo automatically do setup of jest.
I think you must do 'Expo init newProject', then read .babelrc and package.json
Below is result of expo init.
It works well.
// package.json
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"eject": "expo eject",
"test": "node ./node_modules/jest/bin/jest.js --watchAll"
},
"jest": {
"preset": "jest-expo"
},
"dependencies": {
"#expo/samples": "2.1.1",
"expo": "^32.0.0",
"react": "16.5.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
"react-navigation": "^3.0.9"
},
"devDependencies": {
"babel-preset-expo": "^5.0.0",
"jest-expo": "^32.0.0"
},
"private": true
}
// babel.config.js
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
};
};

Related

how to Add #babel/plugin-transform-flow-strip-types (https://git.io/vb49g) to the 'plugins' section of your Babel config to enable transformation?

am using react native web and want to add react navigation 5 to the project. However when I try building the web version upon adding react-navigation I get
./node_modules/react-native-gesture-handler/DrawerLayout.js
SyntaxError: D:\Parentlane\ReactNativeWeb\node_modules\react-native-gesture-handler\DrawerLayout.js: Support for the experimental syntax 'flow' isn't currently enabled (30:8):
28 | const SETTLING = 'Settling';
29 |
> 30 | export type PropType = {
| ^
31 | children: any,
32 | drawerBackgroundColor?: string,
33 | drawerPosition: 'left' | 'right',
Add #babel/plugin-transform-flow-strip-types (https://git.io/vb49g) to the 'plugins' section of your Babel config to enable transformation.
I added plugin-transform-flow-strip-types as a dev dependency but that does not help.
below is my package.json
{
"name": "ReactNativeWeb",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"web": "react-scripts start",
"start": "react-native start",
"test": "jest",
"lint": "eslint ."
},
"dependencies": {
"#react-native-community/masked-view": "^0.1.10",
"#react-navigation/native": "^5.7.6",
"axios": "^0.20.0",
"babel-loader": "^8.1.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"qs": "^6.9.4",
"react": "16.13.1",
"react-dom": "^16.13.1",
"react-native": "0.63.2",
"react-native-gesture-handler": "^1.8.0",
"react-native-reanimated": "^1.13.1",
"react-native-safe-area-context": "^3.1.8",
"react-native-screens": "^2.11.0",
"react-native-vector-icons": "^7.1.0",
"react-native-web": "^0.13.12"
},
"devDependencies": {
"#babel/core": "^7.11.6",
"#babel/plugin-proposal-class-properties": "^7.10.4",
"#babel/plugin-transform-flow-strip-types": "^7.10.4",
"#babel/preset-env": "^7.11.5",
"#babel/preset-react": "^7.10.4",
"#babel/runtime": "^7.11.2",
"#react-native-community/eslint-config": "^2.0.0",
"metro-react-native-babel-preset": "^0.63.0",
"react-scripts": "^3.4.3",
"react-test-renderer": "16.13.1",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0"
},
"jest": {
"preset": "react-native"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
babel.config.js is as follows:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
};
could anyone tell me how to add the plugin inside babel.config.js?or is there any other way to resolve the above error?
Any suggestions would be great and let me know if any other detail is required for better understanding.
You could add it inside your babel config file. Include it in your plugins.
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: ['#babel/plugin-transform-flow-strip-types'],
};
And install it with npm like this
npm install --save-dev #babel/plugin-transform-flow-strip-types
Check the docs here -> https://babeljs.io/docs/en/babel-plugin-transform-flow-strip-types
Apparently this "helpful" message is the default error message when "neither Flow nor Typescript are enabled in Babel".
Personally I came across it when using a Typescript project and attempting to import something from within a monorepo but outside the current scope - it's then throwing this error when it encounters the TS keyword "interface".
Fixing this will probably depend on your own project setup - however, if you're not using Flow it's unlikely that adding any of the recommended Babel/flow plugins will help.
Add plugin plugin-transform-flow-strip-types in file babel.config.js and enable allowDeclareFields
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
...
['#babel/plugin-transform-flow-strip-types', { allowDeclareFields: true }]
],
};
For install plugin:
npm install --save-dev #babel/plugin-transform-flow-strip-types
//or
yarn add --dev #babel/plugin-transform-flow-strip-types

Jest test fails on react-native-screens even after being compiled through transformIgnorePatterns

Description
Even after forcing jest.config.js to compile react-native-screens in transformIgnorePatterns, it still fails on the import statement.
Tech Stack
We initialized a react-native app through expo. We are using jest as our unit test framework supported by babel.
Error Log
/<usr_path>/node_modules/react-native-screens/src/screens.native.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import React from 'react';
^^^^^^
SyntaxError: Cannot use import statement outside a module
package.json
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject",
"test": "jest"
},
"dependencies": {
"expo": "~36.0.0",
"react": "~16.9.0",
"react-dom": "^16.12.0",
"react-native": "^0.61.5",
"react-native-maps": "0.26.1",
"react-native-safe-area-context": "0.6.0",
"react-native-web": "^0.12.1",
"react-navigation": "^4.1.1",
"react-navigation-stack": "^2.1.1",
"react-native-screens": "2.0.0-alpha.20",
"react-native-gesture-handler": "~1.5.0",
"#react-native-community/masked-view": "0.1.5"
},
"devDependencies": {
"#babel/core": "^7.0.0",
"#babel/plugin-proposal-class-properties": "^7.8.3",
"#babel/preset-env": "^7.8.4",
"babel-jest": "24.9.0",
"babel-preset-expo": "~8.0.0",
"jest-expo": "^36.0.1",
"jest-fetch-mock": "3.0.1",
"react-test-renderer": "^16.12.0"
},
"private": true
}
babel.config.js
module.exports = {
presets:
[
[
"#babel/preset-env",
{
"targets": {
"node": "current"
}
}
],
"babel-preset-expo"
],
plugins:
[
"#babel/plugin-proposal-class-properties"
]
};
jest.config.js
module.exports = {
// All imported modules in your tests should be mocked automatically
automock: false,
clearMocks: true,
coverageDirectory: "coverage",
preset: "jest-expo",
testEnvironment: "node",
transform: {
"^.+\\.jsx?$": "babel-jest"
},
transformIgnorePatterns: [
"node_modules/(?!(jest-)?react-native|react-clone-referenced-element|#react-native-community|expo(nent)?|#expo(nent)?/.*|react-navigation|#react-navigation/.*|#unimodules/.*|sentry-expo|native-base|react-native-screens)",
"screens/.*",
],
};

React Native Jest Error: Cannot find module 'warnOnce' from 'react-native-implementation.js'

I get this error when I run npm test. I've looked at a number of posts, solutions, etc. that suggest making edits to package.json, babel.config.js, jest.config.js and I still receive this error. I thought it could be a version issue with React Native, but I'm on the latest version 0.60.4 and it's mentioned in a few issues that this is solved in master. Perhaps I'm overlooking something, but I'm coming up short on what else it could be.
The following is the test that fails as a result:
import { geolocationRequest } from '../location';
let mockGeoCoding = jest.fn();
jest.mock('react-native-geocoding', () => ({
openURL: mockGeoCoding,
}));
describe('geolocationRequest', () => {
it('creates a properly formatted action', () => {
expect(geolocationRequest()).toMatchSnapshot();
})
})
Thoughts?
package.json
{
"name": "<app-name>",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start --config ../../../../rn-cli.config.js",
"start:ios": "react-native run-ios",
"start:android": "react-native run-android",
"clean:ios": "cd ios/ && pod deintegrate && pod install",
"clean:android": "cd android && ./gradlew clean",
"test": "jest --watch",
"test:coverage": "jest --coverage && open coverage/lcov-report/index.html",
"fix": "eslint --fix .",
"lint:ts": "tslint --fix --project ./tsconfig.json",
"lint:fix": "npm run lint:ts --fix",
"lint:check": "tslint --type-check --project"
},
"dependencies": {
"#react-native-community/async-storage": "1.4.2",
"appcenter": "1.12.2",
"appcenter-analytics": "1.12.2",
"appcenter-crashes": "1.12.2",
"axios": "^0.19.0",
"expo-font": "4.0.0",
"polyline": "0.2.0",
"react": "16.8.6",
"react-devtools": "3.6.1",
"react-native": "0.60.*",
"react-native-animatable": "1.3.2",
"react-native-auth0": "1.4.2",
"react-native-easy-grid": "0.2.1",
"react-native-elements": "1.1.0",
"react-native-geocoding": "0.3.0",
"react-native-gesture-handler": "1.3.0",
"react-native-maps": "0.24.2",
"react-native-vector-icons": "6.4.2",
"react-navigation": "3.9.1",
"react-redux": "7.1.0",
"redux": "4.0.0",
"redux-thunk": "2.3.0",
"scheduler": "0.14.0"
},
"devDependencies": {
"#babel/plugin-proposal-class-properties": "^7.5.5",
"#babel/preset-typescript": "^7.3.3",
"#types/enzyme": "^3.10.3",
"#types/enzyme-adapter-react-16": "^1.0.5",
"#types/jest": "^24.0.17",
"#types/polyline": "0.1.28",
"#types/react": "16.8.13",
"#types/react-native": "0.57.43",
"#types/react-native-auth0": "1.3.0",
"#types/react-native-vector-icons": "6.4.0",
"#types/react-redux": "^7.1.1",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.1",
"babel-jest": "24.3.1",
"babel-preset-expo": "5.1.1",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.14.0",
"enzyme-to-json": "^3.4.0",
"eslint": "5.15.1",
"eslint-config-airbnb": "17.1.0",
"eslint-plugin-import": "2.16.0",
"eslint-plugin-jsx-a11y": "6.2.1",
"eslint-plugin-react": "7.12.4",
"jest": "^24.3.1",
"jest-fetch-mock": "^2.1.2",
"jest-localstorage-mock": "^2.4.0",
"metro-react-native-babel-preset": "0.53.0",
"react-dom": "^16.8.6",
"react-native-typescript-transformer": "1.2.12",
"react-test-renderer": "^16.6.3",
"redux-mock-store": "^1.5.3",
"ts-jest": "^24.0.2",
"tslint": "5.16.0",
"typescript": "3.4.3"
},
"jest": {
"preset": "react-native"
}
}
jest.config.js
module.exports = {
"preset": 'react-native',
"verbose": true,
"setupFilesAfterEnv": ["<rootDir>/__tests__/setup.js", "jest-localstorage-mock"],
"roots": [
"<rootDir>/src"
],
"transform": {
"^.+\\.tsx?$": "ts-jest",
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
],
"testPathIgnorePatterns": ['/node_modules/'],
"snapshotSerializers": ["enzyme-to-json/serializer"],
// "collectCoverageFrom": ["src/**/*.tsx"],
"collectCoverage": true,
};
babel.config.js
module.exports = {
"presets": ["module:metro-react-native-babel-preset"]
}
I've been struggling with the same issue.
Based on this comment on github From harudev
[...] So I tested some files to test project, and find out "react-native.config.js" file was the reason.
If there is someone suffered this issue, try to remove file or options from one of your "*.config.js" 😅
So I did remove all of my *.config.js file and the error is now gone.
Hopefully this could help you.
Note that you can reproduce the behavior of the *.confing.js file with package.json
For me this happened at an update of RN from 0.59.10 to 0.61.4.
I tried several fixes but nothing worked.
The only workaround that I've found was to set metro.config.js as below:
const blacklist = require('metro-config/src/defaults/blacklist');
module.exports = {
resolver: {
blacklistRE: blacklist([
/node_modules\/.*\/node_modules\/react-native\/.*/,
]),
},
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
};
Source: jamalx31's answer from here:
https://github.com/facebook/react-native/issues/24065#issuecomment-537489786
The issue is reported and documented here:
https://github.com/facebook/react-native/issues/24065
and here:
https://github.com/facebook/react-native/issues/23943
Had the same error, after a good amount of soul searching (google searching)
i just ran npx react-native start oposed to runing my local react-native.

Unable to resolve module `metro/src/lib/bundle-modules/HMRClient`

I just upgraded from RN 0.55.4 to 0.59.3.....now Im getting following error:
Error: Unable to resolve module metro/src/lib/bundle-modules/HMRClient from ....\node_modules\react-native\Libraries\Utilities\HMRClient.js: Module metro/src/lib/bundle-modules/HMRClient does not exist in the Haste module map
The HMRClient.js file does include the following require statement: const MetroHMRClient = require('metro/src/lib/bundle-modules/HMRClient');.....and I cant see that path beginning with 'metro' anywhere so I guess I need to add it somehow. There is also another require statement as follows: const invariant = require('invariant'); ....no file name 'invariant' exists either.
Facebook say this was fixed back in 0.53.0 master but looks like its back
https://github.com/facebook/react-native/issues/17742
Below is my package.json
{
"name": "xs",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest",
"flow": "flow",
"flow start": "flow start",
"flow stop": "flow stop",
"flow status": "flow status",
"flow coverage": "flow coverage"
},
"dependencies": {
"firebase": "^5.11.1",
"flow": "^0.2.3",
"flow-bin": "^0.65.0",
"prop-types": "^15.6.1",
"react": "16.8.3",
"react-native": "0.59.3",
"react-native-elements": "^0.19.0",
"react-native-google-places-autocomplete": "^1.3.9",
"react-native-maps": "git://github.com/react-native-community/react-native-maps.git#master",
"react-native-switch": "^1.4.0",
"react-native-vector-icons": "^4.5.0",
"react-navigation": "^2.5.5",
"react-redux": "^5.1.0",
"redux": "^4.0.1",
"redux-thunk": "^2.3.0"
},
"devDependencies": {
"babel-eslint": "^8.2.6",
"babel-preset-flow": "^6.23.0",
"eslint": "^4.9.0",
"eslint-config-airbnb": "^16.1.0",
"eslint-plugin-import": "^2.17.3",
"eslint-plugin-jsx-a11y": "^6.2.1",
"eslint-plugin-react": "^7.13.0",
"prettier-eslint": "^8.8.2",
"#babel/core": "^7.4.3",
"#babel/runtime": "^7.4.3",
"babel-jest": "^24.7.1",
"jest": "^24.7.1",
"metro-react-native-babel-preset": "^0.53.1",
"react-test-renderer": "16.8.3"
},
"jest": {
"preset": "react-native"
}
}
Please help!
p.s. the below suggestion does not work
To resolve try the following:
1. Clear watchman watches: watchman watch-del-all.
2. Delete the node_modules folder: rm -rf node_modules && npm install.
3. Reset Metro Bundler cache: rm -rf /tmp/metro-bundler-cache-* or npm start -- --reset-cache.
4. Remove haste cache: rm -rf /tmp/haste-map-react-native-packager-*.
Pay attention when running npm install to see if there is any need for a specific version of something.
First check babel config files then if it doesn't work try the changes in package.json.
Try config files and deps as below.
This is a config that worked for me for an update from 0.54 to 0.59.5:
package.json:
" dependencies": {
"react": "16.8.3",
"react-native": "0.59.5",
// ...
},
"devDependencies": {
"#babel/core": "^7.0.0-0",
"babel-core": "^7.0.0-bridge.0",
"metro-react-native-babel-preset": "0.53.0",
"react-test-renderer": "16.6.3",
// ...
}
babel.config.js:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
};
.babelrc:
{
"presets": ["module:metro-react-native-babel-preset"]
}
The only useful info I could find in the RN release notes about babel and metro changes was at [0.57] here:
https://github.com/react-native-community/releases/blob/master/CHANGELOG.md
UPDATE NOTE:
Trying config files as the ones from a new working project (created with 0.59.9) doesn't seem to work for an update from 0.54 to 0.59
babel.config.js:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
};
metro.config.js:
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
};
and no .babelrc file.
package.json:
"devDependencies": {
"#babel/core": "^7.4.5",
"#babel/runtime": "^7.4.5",
"metro-react-native-babel-preset": "^0.54.1",
},

React Native & Relay, compatibility. Official way to get them to work together?

Preface: I am new to Javascript, Babel and React-Native.
I have been developing my app using the TodoMVC example from the relay source. I was wondering if it's possible to get React-Native + Relay to work together easily?
I setup my babelRelayPlugin and added it to my .babelrc. I installed the npm packages for "react-relay":"^0.7.3" and "babel-relay-plugin": "^0.7.3" but after running "npm install" and "react-native start" I either get an error saying "Unrecognized module 'react-relay'" OR "Relay is not defined".
From reading this thread and looking at the last comment ( https://github.com/facebook/relay/issues/26#issuecomment-194570137 ) it looks like at the moment I should just use TodoMVC as my base for new React-Native + Relay projects.
Is this correct?
Here is my .babelrc
{
"env": {
"development": {
"passPerPreset": true,
"presets": [
{
"plugins": [
"./plugins/babelRelayPlugin"
]
},
"react-native"
]
},
"server": {
"plugins": [
"./plugins/babelRelayPlugin"
],
"presets": [
"es2015",
"stage-0"
]
}
}
}
Here is my package.json
{
"name": "testApp",
"version": "1.0.0",
"private": true,
"scripts": {
"clean:babelrc": "find ./node_modules -name react-packager -prune -o -name '.babelrc' -print | xargs rm -f",
"postinstall": "npm run clean:babelrc",
"start": "BABEL_ENV=server babel-node ./server.js",
"update-schema": "babel-node ./scripts/updateSchema.js"
},
"dependencies": {
"babel-preset-es2015": "^6.5.0",
"babel-preset-react-native": "^1.5.1",
"babel-preset-stage-0": "^6.5.0",
"babel-relay-plugin": "^0.7.3",
"express": "4.13.4",
"express-graphql": "0.4.9",
"graphql": "0.4.17",
"graphql-relay": "0.3.6",
"moment": "^2.12.0",
"node-fetch": "^1.4.1",
"react": "^0.14.5",
"react-native": "^0.22.2",
"react-native-animatable": "^0.5.2",
"react-native-aws3": "0.0.1",
"react-native-camera": "git+https://github.com/lwansbrough/react-native-camera.git",
"react-native-console-panel": "0.0.7",
"react-native-contacts": "^0.2.3",
"react-native-keyboard-aware-scroll-view": "0.0.6",
"react-relay": "^0.7.3",
"sync-request": "^3.0.0",
"uuid-v4": "^0.1.0"
},
"devDependencies": {
"babel-cli": "^6.6.4",
"flow-bin": "^0.22.1"
},
"engines": {
"npm": ">=3"
}
}
I managed to fix the issue. I added "babel-core": "^6.7.6" as a dev dependency. Removed all the scripts and cloned the project from git to a new folder. Everything runs perfectly now!