loading local modules in JEST with JSPM - reactjs

I'm trying to use jest in my JSPM project.
My jspm.config file looks like this:
SystemJS.config({
paths: {
"npm:": "jspm_packages/npm/",
"github:": "jspm_packages/github/",
"moment": "scripts/vendor/moment/moment.min.js"
}
});
In my package.json i have the follow JEST configurations:
"jest": {
"verbose": true,
"collectCoverage": true,
"moduleNameMapper": {
"^npm:(.*)": "<rootDir>/jspm_packages/npm/$1",
"^github:(.*)": "<rootDir>/jspm_packages/github/$1",
"moment": "<rootDir>/public/scripts/vendor/moment"
},
"moduleDirectories": [
"jspm_packages/npm",
"jspm_packages/github",
"public/scripts/vendor",
"node_modules"
],
"rootDir": "",
"modulePathIgnorePatterns": [
"jspm_packages/npm/js-tokens#1.0.3/"
]
},
I try the aproach of the poeticGeek answer in jest testing with es6 + jspm + systemjs + reactJS
but in my test.js whenever i import moment from 'moment'; the tests never completes, seems to enter in an infinite loop.
If i remove the moment inside the moduleNameMapper appears the following error: Cannot find module 'moment' from 'date.test.js'
Any ideas?

The problem was:"rootDir": "" in the configuration file.

Related

Why isn't ts-jest loading my custom tsconfig file?

For some reason, my custom tsconfig file isn't being picked up in jest.config.ts. Here is my jest.config.ts:
module.exports = {
setupFilesAfterEnv: [`./jest.setup.ts`],
testEnvironment: `jsdom`,
roots: [
`<rootDir>/test`
],
testMatch: [
`**/__tests__/**/*.+(ts|tsx|js)`,
`**/?(*.)+(spec|test).+(ts|tsx|js)`
],
transform: {
"^.+\\.(ts|tsx)$": `ts-jest`
},
globals: {
"ts-jest": {
tsConfig: `tsconfig.jest.json`
}
}
}
I know that other parts of this config ARE being applied. For example, if I remove the keys above globals my tests don't run. Also, I know that the change specified in my tsconfig.jest.json file is the necessary change to fix my tests because if I make the same change in my main tsconfig.json file my tests run fine.
I've also tried putting to desired tsconfig compiler options directly into the jest.config.ts file, but that doesn't seem to work either:
module.exports = {
setupFilesAfterEnv: [`./jest.setup.ts`],
testEnvironment: `jsdom`,
roots: [
`<rootDir>/test`
],
testMatch: [
`**/__tests__/**/*.+(ts|tsx|js)`,
`**/?(*.)+(spec|test).+(ts|tsx|js)`
],
transform: {
"^.+\\.(ts|tsx)$": `ts-jest`
},
globals: {
"ts-jest": {
tsConfig: {
jsx: `react`
}
}
}
}
Updated answer for jest#29 (released August 2022) and ts-jest#29 (released September 2022)
All of my React component *.tsx-related tests were broken after upgrading Jest-and-friends to version 29. I also received error messages that jestConfig.globals['ts-jest'] is now deprecated.
As per the ts-jest "Options" doc you need to use the lowercased tsconfig and not the camel-cased tsConfig.
As per the ts-jest "TypeScript Config option" doc you should modify your Jest config to jestConfig.transform['regex_match_files'].
The relevant parts of my project's configuration are below. (Caveat: note that I'm using a custom location for my config files, i.e. a dedicated ./config/ directory in the project root, but the principle of specifying the relative-path-to-config-file remains the same).
// ./package.json
// (trimmed to just the relevant parts)
"scripts": {
"test": "jest --config=./config/.jestrc.js --rootDir=./src/"
},
"devDependencies": {
"#types/jest": "^29.0.1",
"jest": "^29.0.3",
"jest-environment-jsdom": "^29.0.3",
"ts-jest": "^29.0.0",
"typescript": "^4.8.3"
}
// ./config/.jestrc.js
// (trimmed to just the relevant parts)
transform: {
'^.+\\.tsx?$': [
'ts-jest',
// required due to custom location of tsconfig.json configuration file
// https://kulshekhar.github.io/ts-jest/docs/getting-started/options/tsconfig
{tsconfig: './config/tsconfig.json'},
],
},
the correct key is tsconfig not tsConfig.

How to resolve "Cannot use import statement outside a module" in jest

I have a React application (not using Create React App) built using TypeScript, Jest, Webpack, and Babel. When trying to run yarn jest, I get the following error:
I have tried removing all packages and re-adding them. It does not resolve this. I have looked at similar questions and documentation and I am still misunderstanding something. I went so far as to follow another guide for setting up this environment from scratch and still received this issue with my code.
Dependencies include...
"dependencies": {
"#babel/plugin-transform-runtime": "^7.6.2",
"#babel/polyfill": "^7.6.0",
"babel-jest": "^24.9.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-test-renderer": "^16.11.0",
"source-map-loader": "^0.2.4"
},
"devDependencies": {
"#babel/core": "^7.6.0",
"#babel/preset-env": "^7.6.0",
"#babel/preset-react": "^7.0.0",
"#types/enzyme": "^3.9.2",
"#types/enzyme-adapter-react-16": "^1.0.5",
"#types/jest": "^24.0.13",
The component's import lines...
import * as React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import HomePage from "./components/pages";
import {
Footer,
Header,
Navigation,
} from "./components/shared";
The test file....
import * as React from "react";
import * as renderer from "react-test-renderer";
import App from "../App";
it("Renders the Footer correctly", () => {
const tree = renderer
.create(<App />)
.toJSON();
expect(tree).toMatchSnapshot();
});
I expected to be able to use named imports in my components without my tests blowing up. It appears to fix the issue if I only use default imports through my solution, but I would prefer to not go that route.
Also using Babel, Typescript and Jest. Had the same failure, driving me crazy for hours.
Ended up creating a new babel.config.js file specifically for the tests. Had a large .babelrc that wasn't getting picked up by jest no matter what i did to it. Main app still uses the .babelrc as this overrides babel.config.js files.
Install jest, ts-jest and babel-jest:
npm i jest ts-jest babel-jest
babel.config.js (only used by jest)
module.exports = {presets: ['#babel/preset-env']}
jest.config.js
module.exports = {
preset: 'ts-jest',
transform: {
'^.+\\.(ts|tsx)?$': 'ts-jest',
"^.+\\.(js|jsx)$": "babel-jest",
}
};
package.json
"scripts": {
"test": "jest"
Use Babel to transpile those JS Modules and you'll be able to write your tests with es6.
Install Babel/preset-env
npm i -D #babel/preset-env
Create a babel configuration file with the preset
//babel.config.js
module.exports = {presets: ['#babel/preset-env']}
I solved this by migrating the .babelrc file to babel.config.js! Shocker.
For future references,
I solved the problem by using below jest config, after reading Logan Shoemaker's answer.
module.exports = {
verbose: true,
setupFilesAfterEnv: ["<rootDir>src/setupTests.ts"],
moduleFileExtensions: ["js", "jsx", "ts", "tsx"],
moduleDirectories: ["node_modules", "src"],
moduleNameMapper: {
"\\.(css|less|scss)$": "identity-obj-proxy"
},
transform: {
'^.+\\.(ts|tsx)?$': 'ts-jest',
"^.+\\.(js|jsx)$": "babel-jest",
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/file.js",
}
};
try this thing if you are using babel 6
Adding #babel/plugin-transform-modules-commonjs in the plugin section of babel.config.js
or
For my case import issue was due to the react file drop by adding that to transformIgnorePatterns
"transformIgnorePatterns": ["/node_modules/(?!react-file-drop)"]
I fixed it by simply appending the pattern after the run statement in package.json runner
{
"scripts": {
...
"test": "react-scripts test --transformIgnorePatterns 'node_modules/(?!my-library-dir)/'"
...
Then, just run npm test
Solution: my named imports were coming from index.js files and I believe ts-jest needed them as index.ts files (I'm using Typescript). If anyone else runs into this error, couldn't hurt to check if you derped your file extensions.
I wasted a lot of time on this, unfortunately, but I learned a lot about webpack configurations and Babel.
Add your test script in package.json with Node experimental feature: --experimental-vm-modules
In this way you won't require babel or other dependencies.
Examples:
"test": "NODE_OPTIONS='--experimental-vm-modules --experimental-specifier-resolution=node' jest"
If you get this error: zsh: command not found: jest, try with node passing jest.js like this:
"test": "NODE_OPTIONS='--experimental-vm-modules --experimental-specifier-resolution=node --trace-warnings' node node_modules/jest/bin/jest.js --detectOpenHandles"
I'm surprised that none of the answers does not give an elegant solution:
jest.config.js
module.exports = {
...,
globals: {
"ts-jest": {
isolatedModules: true,
},
},
};
This compiles each file separately therefore avoiding the no exports issue.
Create .babelrc on the main directory and add this code and install these packages
#babel/core, #babel/preset-env and #babel/preset-react
{
"presets": [
[
"#babel/preset-env",
{
"modules": "commonjs"
}
],
"#babel/preset-react"
]
}
Matching file extensions:
I importing a file named Todo.jsx in the root as ./src/Todo/. Whenever I changed it to Todo.js the problem went away.
Disclaimer: I'm not sure what the requirement is for having your file extension as jsx vs js for your components. It did not effect me at all, but I could imagine it could mess with intellisense or snippets.
For me renaming file to babel.config.js worked.
Here is my config file an NX project using next with Typescript along with Twin-macro
// .babelrc.js >> babel.config.js
module.exports = {
presets: [
[
"#nrwl/react/babel",
{
"runtime": "automatic",
"targets": {
"browsers": [">0.25%", "not dead"]
},
"preset-react": {
runtime: "automatic",
importSource: "#emotion/react",
},
}
],
'#babel/preset-env',
'#emotion/babel-preset-css-prop',
'#babel/preset-typescript'
],
plugins: ['#emotion', 'macros', '#babel/plugin-transform-runtime', 'react-docgen'],
}
Also, please note even updating package.json works,
https://kulshekhar.github.io/ts-jest/docs/getting-started/presets/#basic-usage
// package.json
"jest": {
// Replace `ts-jest` with the preset you want to use
// from the above list
"preset": "ts-jest"
}
I encountered the same problem with Typescript, Jest, and VueJS/VueCli 3. The normal build has no problem. only happens for Jest. I struggled for hours by searching. But no answer actually works. In my case, I have a dependency on my own typescript package which I specific "target": "es6" in the tsconfig.json. That's the root cause. So the solution is simply to change the dependent's (Not the same project) back to es5 tsconfig.json:
{
"compilerOptions": {
"target": "es5",
...
},
...
}
Personnaly I followed #ajwl setup but discovered that jsdom-worker inside setupFiles: section of jest.config.js was triggering that same error. Once removed, my tests were passing.
P.S. my babel.config.js is a bit different, since I have a Vuejs (v2) SPA (bundled with Vitejs):
module.exports = {
plugins: ['#babel/plugin-transform-modules-commonjs'],
presets: [['#babel/preset-env', { targets: { node: 'current' } }]]
}
The problem is likely that jest doesn't support esmodules natively. Which can cause problems if youre typescript target is es6 or greater.
If you are testing the built typescript output, you could simply add a module=commonjs flag while transpiling. That way, your code can run with es6 or greater and still work with Jest.
"scripts": {
"test": tsc --module commonjs && jest {your-output-folder}/
}
What's great about this is that I didn't have to add any additional babel dependencies or special jest runners :)
I solved it by changing my tsconfig.json to a compatible native output
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
It is not ideal in every scenario but you might be okay with this.
All I had to do, was simply updating the package #babel/preset-env in the dev dependencies to the latest version
// package.json
"#babel/preset-env": "^7.18.6"
None of the answers helped me, what did help me was making sure my NODE_ENV was set to test, since babel config is per NODE_ENV using the wrong NODE_ENV by accident that is not configured in babel config will mean you wont be using babel and the typescript files will not be transformed.
It took me couple of hours to figure this one out so i hope it will save someone else the time it took me.
Don't know why and how but how I solved the problem was really interesting.
Just add __mocks__ folder in your src folder and create an empty file inside __mocks__ named axios.js
I discovered that this error might be triggered when you try to load a dependency that is made for the browser and, thus, cannot work with jest (node).
I had a lot of trouble solving this issue for #zip.js/zip.js lib. But I could do it like that:
Here is my jest.config.js. Adapt it to your need. The trick here is the moduleNameMapper that will make all imports to zip.js point to the file __mocks__/#zip.js/zip.js I created in my root folder.
export default {
preset: 'ts-jest',
testEnvironment: 'node',
moduleNameMapper: {
'#zip.js/zip.js': '<rootDir>/__mocks__/#zip.js/zip.js',
},
}
And here is what I have in <rootDir>/__mocks__/#zip.js/zip.js file:
module.exports = {}
Too late for this answer :)
After trying all the possible solutions, this worked for me:
The solution, that works for me:
create a file named jest/mocks/#react-native-firebase/crashlytics.js
export default () => ({ log: jest.fn(), recordError: jest.fn(), });
create a file named jest/jestSetupFile.js
import mockFirebaseCrashlytics from './mocks/#react-native-firebase/crashlytics';
jest.mock('#react-native-firebase/crashlytics', () => mockFirebaseCrashlytics);
in package.json add
"jest": { "setupFiles": ["./jest/jestSetupFile.js"] },
I needed to do a couple things to get this to work for me
Rename my .babelrc to babel.config.js and make a little change:
// .babelrc
{
"presets": [
[
"#babel/preset-env",
{
"corejs": "3.26",
"useBuiltIns": "usage"
}
],
"#babel/preset-react"
],
...
}
// babel.config.js - This still works fine with webpack
module.exports = {
"presets": [
[
"#babel/preset-env",
{
"corejs": "3.26",
"useBuiltIns": "usage"
}
],
"#babel/preset-react"
],
...
}
Add the following to my jest config file:
{
...
"transformIgnorePatterns": [
"node_modules/(?!(react-leaflet-custom-control)/)"
],
...
}
Where react-leaflet-custom-control was the package causing issues for me.
If you're using TypeScript, and you have a tsconfig.json file, try removing "module": "esnext" if you're using it
Running npm ci fixed this problem for me.

Error when testing react components with jest and css-modules

I'm trying to test my components with jest, react, redux but I keep getting the following error:
● Test suite failed to run
stream-react-redux/src/containers/App/App.css:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){.app {
SyntaxError: Unexpected token .
I have followed the instructions on how to add the identity-obj-proxy and configuring my .jestrc file, but I keep getting the same error. The problem came when I started using css-modules and importing them in my components
Here is my .jestrc:
{
"moduleFileExtensions": [ "js", "jsx"],
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"^.+\\.(css)$": "identity-obj-proxy"
},
"transform": {
"^.+\\.(js|jsx)$": "babel-jest"
},
"verbose": true
}
I have also added the ["es2015", { "modules": false } ] inside my .babelrc file.
So after trying everything, I was still getting the same error.
What I just noticed is that when I specify my config inside a .jestrc file my tests brake because of the .css, but when I do it from the package.json everything works.
EDIT
#package.json
"jest": {
"moduleNameMapper": {
"\\.css$": "identity-obj-proxy"
},
"transform": {
"\\.js$": "babel-jest"
}
I took a look at the Jest docs and, just to be clear, did you install identity-obj-proxy?
npm install --save-dev identity-obj-proxy
Also, I see that the recommended file regex in the Jest docs is
"\\.(css|less)$": "identity-obj-proxy"
may try switching yours to match.
Finally, you could try a jest plugin like jest-css-modules
https://github.com/justinsisley/Jest-CSS-Modules

Migrating to preactjs

I have a universal react app where server side is built in babel and the client bundle is built in webpack. I have read preact-compact docs and it suggests to adding this in .babelrc for building using babel:
{
"plugins": [
[
"transform-react-jsx",
{
"pragma": "h"
}
],
[
"module-resolver",
{
"root": [
"."
],
"alias": {
"react": "preact-compat",
"react-dom": "preact-compat"
}
}
]
],
"presets": [
"react"
]
}
And for webpack:
{
"resolve": {
"alias": {
"react": "preact-compat",
"react-dom": "preact-compat"
}
}
}
But after building I get an error h is not defined
How to migrate to preact for a universal react app
But after building i get an error "h is not defined"
You added the transform-react-jsx plugin to your babel config.
["transform-react-jsx", { "pragma":"h" }]
This tells babel how to transpile your JSX code. For that to work, the function h needs to be in scope, that means you need to import it in every file you use JSX.
import { h } from 'preact';
Instead of having to change all your code that uses React, you can use preact-compat and alias both react and react-dom to preact-compat, as you did correctly, either with babel-plugin-module-resolver or with webpack. With that you can use react and react-dom in your code and preact-compat does the rest for you.
In order to make it work you have to remove ["transform-react-jsx", { "pragma":"h" }] from your babel config.

SyntaxError with Jest and React and importing CSS files

I am trying to get my first Jest Test to pass with React and Babel.
I am getting the following error:
SyntaxError: /Users/manueldupont/test/avid-sibelius-publishing-viewer/src/components/TransportButton/TransportButton.less: Unexpected token
> 7 | #import '../variables.css';
| ^
My package.json config for jest look like this:
"babel": {
"presets": [
"es2015",
"react"
],
"plugins": [
"syntax-class-properties",
"transform-class-properties"
]
},
"jest": {
"moduleNameMapper": {
"^image![a-zA-Z0-9$_-]+$": "GlobalImageStub",
"^[./a-zA-Z0-9$_-]+\\.png$": "RelativeImageStub"
},
"testPathIgnorePatterns": [
"/node_modules/"
],
"collectCoverage": true,
"verbose": true,
"modulePathIgnorePatterns": [
"rpmbuild"
],
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/react/",
"<rootDir>/node_modules/react-dom/",
"<rootDir>/node_modules/react-addons-test-utils/",
"<rootDir>/node_modules/fbjs",
"<rootDir>/node_modules/core-js"
]
},
So what am I missing?
moduleNameMapper is the setting that tells Jest how to interpret files with different extension. You need to tell it how to handle Less files.
Create a file like this in your project (you can use a different name or path if you’d like):
config/CSSStub.js
module.exports = {};
This stub is the module we will tell Jest to use instead of CSS or Less files. Then change moduleNameMapper setting and add this line to its object to use it:
'^.+\\.(css|less)$': '<rootDir>/config/CSSStub.js'
Now Jest will treat any CSS or Less file as a module exporting an empty object. You can do something else too—for example, if you use CSS Modules, you can use a Proxy so every import returns the imported property name.
Read more in this guide.
I solved this by using the moduleNameMapper key in the jest configurations in the package.json file
{
"jest":{
"moduleNameMapper":{
"\\.(css|less|sass|scss)$": "<rootDir>/__mocks__/styleMock.js",
"\\.(gif|ttf|eot|svg)$": "<rootDir>/__mocks__/fileMock.js"
}
}
}
After this you will need to create the two files as described below
__mocks__/styleMock.js
module.exports = {};
__mocks__/fileMock.js
module.exports = 'test-file-stub';
If you are using CSS Modules then it's better to mock a proxy to enable className lookups.
hence your configurations will change to:
{
"jest":{
"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|scss|sass)$": "identity-obj-proxy"
},
}
}
But you will need to install identity-obj-proxy package as a dev dependancy i.e.
yarn add identity-obj-proxy -D
For more information. You can refer to the jest docs
UPDATE who use create-react-app from feb 2018.
You cannot override the moduleNameMapper in package.json but in jest.config.js it works, unfortunately i havent found any docs about this why it does.
So my jest.config.js look like this:
module.exports = {
...,
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(scss|sass|css)$": "identity-obj-proxy"
}
}
and it skips scss files and #import quite well.
Backing my answer i followed jest webpack
Similar situation, installing identity-object-proxy and adding it to my jest config for CSS is what worked for me.
//jest.config.js
module.exports = {
moduleNameMapper: {
"\\.(css|sass)$": "identity-obj-proxy",
},
};
The specific error I was seeing:
Jest encountered an unexpected token
/Users/foo/projects/crepl/components/atoms/button/styles.css:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){.button { }
^
SyntaxError: Unexpected token .
1 | import React from 'react';
> 2 | import styles from './styles.css';
If you're using ts-jest, none of the solutions above will work! You'll need to mock transform.
jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
roots: [
"<rootDir>/src"
],
transform: {
".(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/jest-config/file-mock.js",
'.(css|less)$': '<rootDir>/jest-config/style-mock.js'
},
};
file-mock.js
module.exports = {
process() {
return `module.exports = 'test-file-stub'`;
},
};
style-mock.js
module.exports = {
process() {
return 'module.exports = {};';
}
};
I found this working example if you want more details.
Solution of #import Unexpected token=:)
Install package:
npm i --save-dev identity-obj-proxy
Add in jest.config.js
module.exports = {
"moduleNameMapper": {
"\\.(css|less|scss)$": "identity-obj-proxy"
}
}
Update: Aug 2021
If you are using Next JS with TypeScript. Simply follow the examples repo.
Else you will be wasting days configuring the environment.
https://github.com/vercel/next.js/tree/canary/examples/with-jest
I added moduleNameMapper at the bottom of my package.json where I configured my jest just like this:
"jest": {
"verbose": true,
"moduleNameMapper": {
"\\.(scss|less)$": "<rootDir>/config/CSSStub.js"
}
}

Resources