I'm using Jest to test my React app.
Recently, I added DeckGL to my app. My tests fail with this error:
Test suite failed to run
/my_project/node_modules/deck.gl/src/react/index.js:21
export {default as DeckGL} from './deckgl';
^^^^^^
SyntaxError: Unexpected token export
at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:318:17)
at Object.<anonymous> (node_modules/deck.gl/dist/react/deckgl.js:9:14)
at Object.<anonymous> (node_modules/deck.gl/dist/react/index.js:7:15)
This looks like an issue with Jest transforming a node module before running it's tests.
Here is my .babelrc:
{
"presets": ["react", "es2015", "stage-1"]
}
Here is my jest setup:
"jest": {
"testURL": "http://localhost",
"setupFiles": [
"./test/jestsetup.js"
],
"snapshotSerializers": [
"<rootDir>/node_modules/enzyme-to-json/serializer"
],
"moduleDirectories": [
"node_modules",
"/src"
],
"moduleNameMapper": {
"\\.(css|scss)$": "<rootDir>/test/EmptyModule.js"
}
},
I seem to have the correct things necessary to transform export {default as DeckGL }. So any ideas whats going wrong?
This means, that a file is not transformed through TypeScript compiler, e.g. because it is a JS file with TS syntax, or it is published to npm as uncompiled source files. Here's what you can do.
Adjust your transformIgnorePatterns allowed list:
{
"jest": {
"transformIgnorePatterns": [
"node_modules/(?!#ngrx|(?!deck.gl)|ng-dynamic)"
]
}
}
By default Jest doesn't transform node_modules, because they should be valid JavaScript files. However, it happens that library authors assume that you'll compile their sources. So you have to tell this to Jest explicitly. Above snippet means that #ngrx, deck and ng-dynamic will be transformed, even though they're node_modules.
And if you are using 'create-react-app', it won't allow you to specify 'transformIgnorePatterns' via Jest property in package.json
As per this https://github.com/facebook/create-react-app/issues/2537#issuecomment-390341713
You can use CLI as below in your package.json to override and it works :
"scripts": {
"test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!your-module-name)/\"",
},
This is because Node.js cannot handle ES6 modules.
You should transform your modules to CommonJS therefore.
Babel 7 >=
Install
npm install --save-dev #babel/plugin-transform-modules-commonjs
And to use only for test cases add to .babelrc,
Jest automatically gives NODE_ENV=test global variable.
"env": {
"test": {
"plugins": ["#babel/plugin-transform-modules-commonjs"]
}
}
Babel 6 >=
npm install --save-dev babel-plugin-transform-es2015-modules-commonjs
to .babelrc
"env": {
"test": {
"plugins": ["transform-es2015-modules-commonjs"]
}
}
Jest by default won't compile files in the node_modules directory.
transformIgnorePatterns [array]
Default: ["/node_modules/"]
An array of regexp pattern strings that are matched against all source
file paths before transformation. If the test path matches any of the
patterns, it will not be transformed.Default: ["/node_modules/"]
DeckGL seems to be in ES6, to make jest able to read it, you need to compile this as well.
To do that, just add an exception for DeckGL in the transformignorePatterns
"transformIgnorePatterns": ["/node_modules/(?!deck\.gl)"]
https://facebook.github.io/jest/docs/en/configuration.html#transformignorepatterns-array-string
I was having this issue with a monorepo. A package in the root node_modules was breaking my tests. I fixed by changing my local .babelrc file to babel.config.js. Explanation: https://github.com/facebook/jest/issues/6053#issuecomment-383632515
It was work around #1 on this page that fixed it for me though workaround #2 on that page is mentioned in above answers so they may also be valid.
"Specify the entry for the commonjs version of the corresponding package in the moduleNameMapper configuration"
jest.config.js
moduleNameMapper: {
"^uuid$": require.resolve("uuid"),
"^jsonpath-plus$": require.resolve("jsonpath-plus")
...
In my case I use this config in the file package.json:
"jest": {
"transformIgnorePatterns": [
"!node_modules/"
]
}
This code worked for me
// .babelrc
{
"presets": [
["env", {
"modules": "commonjs", // <- Check and see if you have this line
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-vue-jsx", "transform-runtime"],
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"]
}
}
}
jest understands commonJs so it needs babel to transform the code for it before use. Also jest uses caching when running code. So make sure you run jest --clearCache before running jest.
Tested Environment:
Node v8.13.0
Babel v6+
Jest v27
I'm using a monorepo (it contains multiple packages for the frontend and backend).
The package I'm testing imports a file from another package that uses the dependency uuid.
All the files are in Typescript (not Javascript).
The package I'm testing has a tsconfig file for testing only, called tsconfig.test.json. It has the properties commonjs and allowJs. Adding allowJs solves the problem when importing uuid, I don't know why.
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": [
"jest",
"node"
],
// Necessary to import dependency uuid using CommonJS
"allowJs": true
},
"include": [
"jest.config.ts",
"**/*.test.ts",
"**/*.d.ts"
]
}
I was upgrading a project that uses a version of babel that reads the config from .babelrc, when I upgraded to a newer version I read:
https://babeljs.io/docs/en/configuration#whats-your-use-case
What's your use case?
You are using a monorepo?
You want to compile node_modules?
babel.config.json is for you!
On top of:
{
"jest": {
"transformIgnorePatterns": [
"node_modules/(?!(module))"
]
}
}
I renamed .babelrc to babel.config.json too.
I had the same error of importing dataSet from vis-data.js library
import { DataSet } from 'vis-data/esnext';
So I just removed /esnext from the path and now it works:
import { DataSet } from 'vis-data';
Related
I am struggling to properly stub/mock unit tests when using es6 modules along with a project with mixed .js and .ts files.
According to this post, testdouble should be able to provide the ESM mocking I need. However, it requires using --loader=testdouble to work, and I am currently using --loader=ts-node/esm. If I attempt to replace ts-node/esm, it is unable to find Typescript files:
Error [ERR_MODULE_NOT_FOUND]: Cannot find module
'/Users/repos/my-repo/src/models/connectionModel.js'
imported from
/Users/repos/my-repo/test/constants.tjs
(connectionModel is ts and imported as .js per esm convention)
Due to project requirements, I would need the project to be compiled in es6+, so removing type: module or setting module: cjs are not viable options for me.
Is there a viable way to use both loaders, or some other viable way to mock with es6?
package.json:
{
"type": "module",
"scripts": {
"test": mocha test/*.js test/*.spec.ts -r dotenv/config
}
}
tsconfig.json:
{
"compilerOptions": {
"target": "es2016",
"module": "es6,
"moduleResolution": "node16"
"allowJs": true,
"esModuleInterop": true
},
"ts-node": {
"esm": true
}
"include": [
"./src/**/*",
"test/**/*/.ts",
"test/**/*.js"
}
}
.mocharc.json: (grabbing from this answer)
{
"node-option": [
"experimental-specifier-resolution=node",
"loader=ts-node/esm"
]
}
I'm trying to make use of the jsonapi-vuex npm package. I import it within my code like so:
import { jsonapiModule } from "jsonapi-vuex";
Jest however stumbles over this package. This package uses es6 modules. The index.js for that node module looks like this:
export { jsonapiModule, utils } from './src/jsonapi-vuex'
Jest fails on this even though babel-jest is installed with the following error:
Jest encountered an unexpected token
/node_modules/jsonapi-vuex/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){export { jsonapiModule, utils } from './src/jsonapi-vuex'
^^^^^^
I've tried various things:
Tried adding to jest config so that just shouldn't ignore this library when transpiling:
transformIgnorePatterns: [
"<rootDir>/node_modules/(?!jsonapi-vuex)"
],
Tried the babel-plugin-transform-es2015-modules-commonjs plugin
As far as I can tell, babel-jest makes use of .babelrc. I have this configured with the #babel/preset-env preset, which is supposed to handle es6 modules... so I really don't understand why it is failing. Here's the .babelrc
{
"presets": [
[
"#babel/preset-env",
{
"modules": "commonjs",
"targets": {
"node": "current"
}
}
]
]}
Desired Behaviour
I am trying to import code from one file into another with:
lib.js
// generate unique id
export const guid = () => {
const s4 = () => {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
// get current date as ISO string
export const currentDateTimeISOString = () => {
var iso_string = new Date().toISOString();
return iso_string;
}
// convert boolean string to boolean
export const stringToBoolean = (val) => {
var a = {
'true': true,
'false': false
};
return a[val];
}
app_es6.js
import { guid, currentDateTimeISOString, stringToBoolean } from './src/js/lib';
Actual Behaviour
After build I get the error:
export const guid = () => {
^^^^^^
SyntaxError: Unexpected token export
What I've Tried
I've googled this error and come across various solutions.
The most up to date approach seems to be:
npm install babel-register babel-preset-env --save-dev
source
I currently have the following babel related dev dependencies in package.json:
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.4",
"babel-preset-env": "^1.7.0",
"babel-preset-stage-0": "^6.24.1",
And .babelrc is:
{
"presets": [
[
"env",
{
"targets":
{
"node": "current"
}
}
]
]
}
I recently changed .babelrc to the above in order to handle async/await usage, it used to be:
{
"presets": [
"env",
"stage-0"
]
}
My build script in package.json is:
"build-server-file": "babel app_es6.js --out-file app.js",
I'm concerned about implementing a solution that is outdated or breaks functionality with another part of the codebase (ie, if i revert to my previous version of .babelrc then async/await will throw errors). I've also read that stage-x is depreciated.
Question
What is the most up to date way to import/export modules in ES6 in a Node.js environment whilst still supporting the .babelrc requirements for async/await?
Notice that the SyntaxError is being thrown from within lib.js and not app.js --this is almost certainly the result of that file not being transformed.
The babel command you're using, babel app_es6.js --out-file app.js is processing app_es6.js; however, lib.js is untouched and that's likely why you still see ESM export syntax when require()ing the file.
I set up a minimal gist with updates to what I know about your current setup to make this work the way (I think) you intended: https://gist.github.com/knksmith57/a554defde2d3d7cf64c4f453565352a0
The trick is to process the entire source directory and not just your entrypoint file.
tl;dr:
process the entire source directory, not just the entrypoint
tell preset-env to use cjs (alias for commonjs) as the target module type
enable a plugin to transform async functions to generator functions (in babel 7.x, that's #babel/plugin-transform-async-to-generator)
look at that gist for a complete working example
If you run into trouble backporting my example to babel 6.x, let me know and I can make some time to follow up.
Hope this helps!
which version of node are you using?
you can easily update your node to version >= 10v to use official ES6 features support.
Actually, I had the same problem and I fix it by a babel plugin that name is transform-runtime, and my .babelrc the file became like below:
{
"presets": [
"es2015",
"es2016",
"es2017",
"react",
"env",
"stage-0"
],
"plugins": [
"transform-class-properties",
"transform-object-rest-spread",
[
"transform-runtime",
{
"helpers": true,
"polyfill": true,
"regenerator": true
}
]
],
"env": {
"development": {
"compact": false
}
}
}
For more information about this plugin read this link.
It looks like you're trying to run a node.js "server".
npm install --save-dev #babel/core #babel/cli #babel/preset-env #babel/node #babel/plugin-transform-async-to-generator
Using the #babel/ namespace will upgrade you from babel 6 to babel 7, the current latest version. The plugin does the async transformation
Setup a .babelrc or now with 7, especially if you're using node_modules with their own babel configurations, you can use a babel.config.js like this:
module.exports = {
presets: [ '#babel/preset-env'],
plugins: [
'#babel/plugin-transform-async-to-generator'
]
};
Update your package.json build scripts to something more like this:
"scripts": {
"build": "babel src --out-dir dist",
"start": "node dist/app_es6.js"
}
You want to compile your /lib/ folder into a /dist/ one. This is the most common pattern you'll see in the community.
As you are looking to make an es6 web-app, I would not recommend actually compiling everything to commonjs (cjs), as that will break webpack (via the babel-loader) from performing tree-shaking. It only works when you use import/exports and setting babel to cjs instead of the default ems will make everything require/module.exports.
I'm at a boiling point with getting Jest to understand ES6 modules import/export syntax and it is hindering my project development progress. My project structure is the following:
root module
org-domain (ES6)
org-services (ES6)
react-ui-module (React via CRA2)
org-services has a local path dependency on org-domain in its package json:
// in org-services package.json
"dependencies": {
"#org/domain": "file:../org-domain",
},
My .babelrc in org-services is the following:
{
"env": {
"test": {
"presets": ["#babel/preset-flow", "#babel/preset-env"]
"plugins": ["#babel/plugin-transform-modules-commonjs"]
}
},
"presets": [
"#babel/preset-flow",
["#babel/preset-env", {
"targets": {
"esmodules": true
}
}]
],
"plugins": [
["module-resolver", {
"root": ["./node_modules/#org/domain"],
"alias": {
"#org/constants": "./node_modules/#org/domain/src/constants",
"#org/contracts": "./node_modules/#org/domain/src/request-contracts"
}
}]
]
}
I do not know if the problem is due to how I am including my dependencies so I'm going to add the finer details of anything related to my import/export of these modules for the sake of clarity.
In the implementation files of org-services I am importing org-domain using npm scoped syntax like so: import ... from '#org/domain
Here are some observations I have:
In local development, when I try to reference click #org/domain, instead of being directed to org-services/node_modules/#org/domain I get redirected to the actual relative directory location which is root/org-services. I believe Jest ignores node_modules (correct me if I am wrong) but in my jest.config.js for org-services, I have:
collectCoverage: true,
coverageDirectory: 'coverage',
coveragePathIgnorePatterns: [
'/node_modules/'
],
moduleDirectories: [
'src',
'node_modules'
],
moduleFileExtensions: [
'js'
],
transform: {
'^.+\\.js$': 'babel-jest'
},
transformIgnorePatterns: [
'node_modules/(?!#org/domain)$'
]
To my understanding, everything should just work right now with all the configuration I have with respect to setting the plugin #babel/plugin-transform-modules-commonjs in test (within .babelrc) and including the '^.+\\.js$': 'babel-jest' instruction under the transform key in jest.config.js located under org-services -- but it does not.
I have tried every single thing I could find online with respect to this issue with no success. I have not gotten anywhere since and my patience is lost with this testing framework and the lack of support for ES6. It should not be this hard, so clearly I am doing something wrong here. Please advise.
Update 1
Found another SO post that is a mirror of this situation I am in.
Jest fails to transpile import from npm linked module
Unfortunately, the provided solution does not work for my case.
After upgrading from #babel/xyz: 7.0.0 to 7.1.2 I started getting an error regarding "import"
Jest encountered an unexpected token
<snip>
Details:
C:\....\SstcStrategy.test.js:2
import sequelizeFixtures from 'sequelize-fixtures';
^^^^^^
SyntaxError: Unexpected token import
at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)
To fix this I had to add #babel/plugin-transform-modules-commonjs as you mention in your question.
My babel.config.js now looks like this:
module.exports = {
presets: [
[
'#babel/preset-env',
{
targets: {
node: '8.10',
},
debug: false,
},
],
],
ignore: ['node_modules'],
plugins: [
'#babel/plugin-transform-runtime',
'#babel/plugin-transform-modules-commonjs',
// Stage 2
['#babel/plugin-proposal-decorators', { legacy: true }],
'#babel/plugin-proposal-function-sent',
'#babel/plugin-proposal-export-namespace-from',
'#babel/plugin-proposal-numeric-separator',
'#babel/plugin-proposal-throw-expressions',
// Stage 3
'#babel/plugin-syntax-dynamic-import',
'#babel/plugin-syntax-import-meta',
['#babel/plugin-proposal-class-properties', { loose: false }],
'#babel/plugin-proposal-json-strings',
],
};
Also BTW you don't need to define babel-jest transform in jest.config.js as this is the default setting.
Hope this helps
Receiving the following error when running Jest
Cannot find module 'src/views/app' from 'index.jsx'
at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:179:17)
at Object.<anonymous> (src/index.jsx:4:12)
index.jsx
import AppContainer from 'src/views/app';
package.json
"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": "node",
"testURL": "http://localhost",
"transform": {
"^.+\\.(js|jsx|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)$"
],
"moduleDirectories": [
"node_modules",
"src"
],
"moduleNameMapper": {
"^react-native$": "react-native-web"
},
"moduleFileExtensions": [
"web.js",
"js",
"json",
"web.jsx",
"jsx",
"node",
"mjs"
]
},
My tests that run files that only contain relative paths in the tree run correctly.
To Clarify, I'm looking for how to configure Jest to not fail on absolute paths.
I think you're looking for: roots or modulePaths and moduleDirectories
You can add both relative and absolute paths.
I would make sure to include <rootDir> in the roots array, <rootDir> in the modulePaths array, and node_modules in the moduleDirectories array, unless you've got a good reason to exclude them.
"jest": {
"roots": [
"<rootDir>",
"/home/some/path/"
],
"modulePaths": [
"<rootDir>",
"/home/some/other/path"
],
"moduleDirectories": [
"node_modules"
],
}
Since in package.json you have:
"moduleDirectories": [
"node_modules",
"src"
]
Which says that each module you import will be looked into node_modules first and if not found will be looked into src directory.
Since it's looking into src directory you should use:
import AppContainer from 'views/app';
Please note that this path is absolute to the src directory, you do not have to navigate to locate it as relative path.
OR you can configure your root directory in moduleDirectories inside your pakcage.json so that all your components could be imported as you want it.
Adding
"moduleDirectories": [
"node_modules",
"src"
]
should work if you have Jest's config in your package.json file.
If you have a jest.config.js file, you should add it there, otherwise package.json will be overriden (and ignored) by this config file. So in your jest.config.js file:
module.exports = {
// ... lots of props
moduleDirectories: ["node_modules", "src"],
// ...
}
That's because jest doesn't recognize relative imports like src/views/app
Add a rootDir and a modulePaths in package.json
"name": "my-app",
...
"jest": {
...
"rootDir": "./",
"modulePaths": [
"<rootDir>"
],
...
}
}
Make sure you have run npm i or npm install after update the package.json. My issue was that :0
For those who are building something from scratch with Webpack and Babbel.
Try the following steps:
Delete the node_modules folder and install again. (This was something that solved my issue).
Here is a link with the necessary documentation to set up Webpack which in some cases will not be necessary. Jest Docs Webpack
Here is a link to the docs that explains how to set up Jest with React (Without using Create-React-App). Jest React Docs
4. Here is an example with a simple setup with Jest. You can set this up in package.json or the Jest configuration file.
Disclaimer: This does not answer the OP question. But most people will end up here for the keywords used for this issue.
"jest": {
"moduleFileExtensions": ["js", "jsx"],
"moduleDirectories": ["node_modules"],
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js"
}
},
In my case, I was running integration tests and all tests were in the same file with the path src/int-test.spec.ts in order to read paths I had to write:
"jest": {
...,
"moduleNameMapper": {
"src/(.*)": "<rootDir>/$1"
}
}
Adding __esModule:true fixed this issue for me.
jest.mock('module',()=>({
__esModule: true, // this makes it work
default: jest.fn()
}));
Hope this helps somebody. Although this is not very specific to the question.
This can also be caused by absolute imports present in the globalSetup file (or any files it references).
It seems like moduleNameMappers do not get applied to globalSetup files. I fixed this by just switching to relative imports for those specific files.
This Workaround:
Using "moduleNameMapper" in your jest configuration will make test-resolve work as expected:
"jest": {
"moduleNameMapper": {
"#(.*)": "<rootDir>/node_modules/$1"
}
}
https://gist.github.com/lydell/d62ce96c95c035811133a5396195da14
One of the modules I wanted to use has a .cjs extension.
Adding .cjs to moduleFileExtensions in jest.config.js fixed this problem for me.
My jest.config.js as example:
module.exports = {
moduleNameMapper: {
// see: https://github.com/kulshekhar/ts-jest/issues/414#issuecomment-517944368
"^#/(.*)$": "<rootDir>/src/$1",
},
preset: "ts-jest/presets/default-esm",
globals: {
"ts-jest": {
useESM: true,
},
},
testEnvironment: 'jsdom',
transform: {
'^.+\\.vue$': 'vue3-jest',
},
moduleFileExtensions: ['json', 'js', 'jsx', 'ts', 'tsx', 'vue', "cjs"],
moduleDirectories: ["node_modules"],
};
Just add "modulePaths" to your package.json
"jest": {
...
"modulePaths": [
"<rootDir>"
],
...
}
}
I had jest-expo installed, but not jest. Probably related that I'm prebuild-ejected from Expo. I had to run yarn add jest-expo jest to install jest, and updated jest-expo. Now my tests run.
Depending on your setup it might be, npm i jest-expo jest or expo install jest-expo jest. ... Got the idea from their docs https://docs.expo.dev/guides/testing-with-jest/