I am making my first ever unit tests with Jest and React Testing Library on my react app. This is a project I took over and has some pre-existing configuration and test setup which I'll admit I may not fully understand.
How I got to this error is this: I already had one test up and running testing a component that doesn't use redux. My next test needed to test a component that uses Redux and so I started to look at totally using React Testing Library and dropping Enzyme all together as the Enzyme isnt compatible with the latest React.
I kept getting an error along the lines of 'cannot import modules outside of node modules' and found out that babel cannot parse ES6.
And so I have been scouring the internet looking for solutions...
I have tried a few methods:
@babel/plugin-syntax-jsx
@babel/preset-react
most recently
However it seems it was not being picked up on as I was still getting the same error with the same suggestion which was:
Add @babel/preset-react (https://git.io/JfeDR) to the 'presets' section of your Babel config to enable transformation. If you want to leave it as-is, add @babel/plugin-syntax-jsx (https://git.io/vb4yA) to the 'plugins' section to enable parsing.
I have added this to the presets and plugins of my babel config in my package-lock but still got the same error.
I also tried adding a .babelrc
and babel.config.js
file with the same preset and plugins but still get the same error.
There was some pre-existing code which I think could potentially be screwing things up somehow but I do not entirely understand it I'll be honest.
This is my package-lock:
{
"name": "hiro-flash",
"version": "0.1.0",
"private": true,
"dependencies": {
"@material-ui/core": "^4.11.4",
"@sentry/react": "^5.29.2",
"@sentry/tracing": "^5.29.2",
"autoprefixer": "7.1.6",
"axios": "^0.18.0",
"axios-cache-adapter": "^2.3.3",
"babel-core": "6.26.0",
"babel-eslint": "^8.2.6",
"babel-jest": "20.0.3",
"babel-loader": "7.1.2",
"babel-preset-react-app": "^3.1.2",
"babel-runtime": "6.26.0",
"bluebird": "^3.5.1",
"case-sensitive-paths-webpack-plugin": "2.1.1",
"chalk": "1.1.3",
"copy-to-clipboard": "^3.3.1",
"css-loader": "0.28.7",
"detect-browser": "^2.5.0",
"dotenv": "4.0.0",
"dotenv-expand": "4.2.0",
"eslint": "^4.19.1",
"eslint-config-react-app": "^2.1.0",
"eslint-loader": "1.9.0",
"eslint-plugin-flowtype": "2.39.1",
"eslint-plugin-import": "2.8.0",
"eslint-plugin-jsx-a11y": "5.1.1",
"eslint-plugin-react": "7.4.0",
"export-to-csv": "^0.2.1",
"express": "^4.16.3",
"extract-text-webpack-plugin": "3.0.2",
"file-loader": "1.1.5",
"file-saver": "^2.0.5",
"fs-extra": "3.0.1",
"html-webpack-plugin": "2.29.0",
"jest": "26.6.3",
"jest-cli": "26.6.3",
"jest-esm-transformer": "^1.0.0",
"jquery": "^3.3.1",
"jszip": "^3.6.0",
"jszip-utils": "^0.1.0",
"lodash": "^4.17.10",
"moment": "2.18.1",
"moment-business-days": "^1.1.3",
"moment-timezone": "^0.5.23",
"npm": "^5.10.0",
"object-assign": "4.1.1",
"path": "^0.12.7",
"postcss-flexbugs-fixes": "3.2.0",
"postcss-loader": "2.0.8",
"promise": "8.0.1",
"prop-types": "^15.6.2",
"raf": "3.4.0",
"react": "latest",
"react-accessible-accordion": "^3.3.3",
"react-dates": "^21.2.1",
"react-datetime": "^2.15.0",
"react-dev-utils": "^5.0.2",
"react-device-detect": "^1.9.10",
"react-dom": "latest",
"react-dropzone": "^11.3.2",
"react-ga": "3.2.0",
"react-hotjar": "^2.2.1",
"react-hover-observer": "^2.1.0",
"react-html-parser": "^2.0.2",
"react-quill": "^1.3.1",
"react-redux": "^5.0.7",
"react-responsive-modal": "^2.1.0",
"react-router": "^3.0.0",
"react-router-redux": "^4.0.8",
"react-select": "^2.0.0",
"react-sizes": "^1.0.4",
"react-table": "6.8.6",
"react-throttle-render": "^2.0.0",
"react-tippy": "^1.2.2",
"react-toastify": "^6.0.9",
"react-tooltip": "^4.2.11",
"recharts": "^1.8.5",
"redux": "^3.7.2",
"redux-api-middleware": "^2.3.0",
"redux-logger": "^3.0.6",
"redux-saga": "^0.16.0",
"redux-thunk": "^2.3.0",
"style-loader": "0.19.0",
"sw-precache-webpack-plugin": "0.11.4",
"url-loader": "0.6.2",
"webpack": "3.8.1",
"webpack-dev-server": "2.9.4",
"webpack-manifest-plugin": "1.3.2",
"whatwg-fetch": "2.0.3",
"xlsx": "^0.16.9"
},
"scripts": {
"start": "node scripts/start.js",
"build": "node scripts/build.js",
"test": "node scripts/test.js"
},
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx,mjs}"
],
"setupFiles": [
"<rootDir>/config/polyfills.js"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,mjs}",
"<rootDir>/src/**/?(*.)(spec|test).{js,jsx,mjs}"
],
"testEnvironment": "jsdom",
"testURL": "http://localhost",
"transform": {
"^.+\\.(js|jsx)$": "jest-esm-transformer",
"^.+\\.(mjs)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|mjs|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$"
],
"moduleNameMapper": {
"^react-native$": "react-native-web"
},
"moduleFileExtensions": [
"web.js",
"mjs",
"js",
"json",
"web.jsx",
"jsx",
"node"
]
},
"extensionsToTreatAsEsm": [
".js",
".jsx",
".ts"
],
"globals": {
"window": {
"location": {
"protocol": {}
}
}
},
"babel": {
"plugins": [
"@babel/plugin-syntax-jsx"
],
"presets": [
"@babel/preset-env",
"@babel/preset-react",
"react-app"
]
},
"eslintConfig": {
"extends": "react-app"
},
"devDependencies": {
"@babel/plugin-syntax-jsx": "^7.14.5",
"@testing-library/react": "^12.0.0",
"chai": "^4.2.0",
"enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.6",
"node-sass": "^4.9.3",
"react-test-renderer": "^16.14.0",
"sass-loader": "^6.0.7",
"sinon": "^7.4.1"
}
}
this is my test:
import React from 'react';
import renderer from 'react-test-renderer';
import { PriceMonitor } from '../../components/priceMonitor/PriceMonitor';
describe('Price Monitor', () => {
const getTree = (activeUser = 'Test User 1', isOriginalUser = true, openPriceMonitorModal = jest.fn(),
resetActiveUser = jest.fn()) => {
const props = {
activeUser,
openPriceMonitorModal,
isOriginalUser,
resetActiveUser,
}
const component = renderer.create(<PriceMonitor {...props} />);
return component.toJSON();
}
const mockOnClick = jest.fn((username, newOriginalValue) => getTree(username, newOriginalValue));
it('renders original user (Test User 1)', () => {
const tree = getTree();
expect(tree).toMatchSnapshot();
});
it('changes user onClick (Test User 1 -> Test User 2)', () => {
const tree = getTree();
expect(tree).toMatchSnapshot();
expect(mockOnClick('Test User 2', false)).toMatchSnapshot();
});
it('renders non original user (Test User 2)', () => {
const tree = getTree('Test User 2', false)
expect(tree).toMatchSnapshot();
});
it('resets user onClick (Test User 2 -> Test User 1)', () => {
const tree = getTree('Test User 2', false);
expect(tree).toMatchSnapshot();
expect(mockOnClick('Test User 1', true)).toMatchSnapshot();
});
});
And then 2 files which were pre-existing, this is test.js:
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
process.env.PUBLIC_URL = '';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const jest = require('jest');
const argv = process.argv.slice(2);
// Watch unless on CI or in coverage mode
if (!process.env.CI && argv.indexOf('--coverage') < 0) {
argv.push('--watch');
}
jest.run(argv);
fileTransform.js inside my jest folder:
'use strict';
const path = require('path');
// This is a custom Jest transformer turning file imports into filenames.
// http://facebook.github.io/jest/docs/en/webpack.html
module.exports = {
process(src, filename) {
return `module.exports = ${JSON.stringify(path.basename(filename))};`;
},
};
Theres also a webpack.config.dev.js but Im not sure how much that is effecting this problem
Im a newb so apologies if this isnt clear enough - will be happy to provide more info.