classnames_1.default is not a function when testing with Jest - reactjs

I am facing issue with running test cases on Jest when classnames ( https://www.npmjs.com/package/classnames ) library is being used :
It throws error : classnames_1.default is not a function
It is working with webpack on website itself.. so i don't want to change import.
I have an option to mock classnames for test to provide similar behaviour. Is there any other way to solve this issue ?
Has anyone faced this issue ?
Here is my jest configuration in package.json :
"jest": {
"globals": {
"API_HOST": "",
"DEV": false
},
"transform": {
".(ts|tsx)": "<rootDir>/node_modules/XXX-framework/jestTypeScriptPreProcessor.js"
},
"testRegex": "(/tests/.*|\.(test|spec))\.(js|jsx|ts|tsx)$",
"transformIgnorePatterns": [],
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"json"
],
"automock": false,
"clearMocks": true,
"resetMocks": true,
"coverageThreshold": {
"global": {
"branches": 50,
"functions": 50,
"lines": 50,
"statements": 50
}
},
"modulePaths": [
"<rootDir>/src",
"<rootDir>/node_modules/XXX-framework/src"
],
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/react/",
"<rootDir>/node_modules/react-dom/",
"<rootDir>/node_modules/react-addons-test-utils/",
"<rootDir>/node_modules/enzyme/",
"<rootDir>/node_modules/XXX-framework/"
]
}
Thanks

You are probably using css-loader, so it works with Webpack. The problem is that Jest doesn't load your CSS files with css-loader and it's your responsibility to tell Jest how to load CSS files. One way to do that is using identity-obj-proxy.
Do npm i -D identity-obj-proxy (or use yarn to install if you like)
and add this config to your Jest config file
"moduleNameMapper": {
"^.+\\.css$": "identity-obj-proxy"
}
You can find more detail in this document.

Related

SyntaxError: Unexpected token export while running tests in Jest with components having amcharts4

Geeting error: Unexpected token export while running tests in Jest with components having amcharts4
export { System, system } from "./.internal/core/System";
^^^^^^
SyntaxError: Unexpected token export
> 1 | import * as am4core from "#amcharts/amcharts4/core";
| ^
2 | import * as am4charts from "#amcharts/amcharts4/charts";
3 | import * as am4maps from "#amcharts/amcharts4/maps";
4 | import am4geodata_worldLow from "#amcharts/amcharts4-geodata/worldLow";
"jest": "24.9.0"
"#amcharts/amcharts4": "^4.10.19"
"typescript": "^3.9.5"
Following is jest config in the package.json file :(Using create-react-app for the project & ejected it)
"jest": {
"roots": [
"<rootDir>/src"
],
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}",
"!src/**/*.d.ts"
],
"setupFiles": [
"react-app-polyfill/jsdom",
"<rootDir>\\src\\__mocks__\\dom.js",
"<rootDir>\\src\\__mocks__\\reactrouter.js"
],
"setupFilesAfterEnv": [
"#testing-library/jest-dom/extend-expect"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
],
"testEnvironment": "jest-environment-jsdom-fourteen",
"transform": {
"^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"node_modules/(?!#amcharts/amcharts4/)",
"^.+\\.module\\.(css|sass|scss)$"
],
"modulePaths": [
"<rootDir>/src/",
"<rootDir>/node_modules/"
],
"moduleNameMapper": {
"\\.(css|scss)$": "<rootDir>/src/__mocks__/styleMock.js"
},
"moduleFileExtensions": [
"web.js",
"js",
"web.ts",
"ts",
"web.tsx",
"tsx",
"json",
"web.jsx",
"jsx",
"node"
],
"watchPlugins": [
"jest-watch-typeahead/filename",
"jest-watch-typeahead/testname"
]
}
Cause: babel-jest uses babel configuration that is loaded based on the location of the file that is going to be transformed. After ejecting create-react-app your package.json probably contains:
"babel": {
"presets": [
"react-app"
]
}
which makes import/export statements work for your files, but #amcharts/amcharts4 does not have that setting in its package.json nor does it have .babelrc and so no import/export transformation takes place.
Solution: You can update your Jest config to transform #amcharts in a more specific way:
Add relevant babel plugin: npm install -D #babel/plugin-transform-modules-commonjs
Update jest config in your package.json - redirect #amcharts transformation to custom transformer. (I also changed transformIgnorePatterns so that they work for Windows.)
"transform": {
"#amcharts[/\\\\].+\\.(js|jsx|ts|tsx)$": "<rootDir>/config/jest/babelTransformImportExport.js",
"^.+\\.(js|jsx|ts|tsx)$": "babel-jest",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"node_modules[/\\\\](?!#amcharts[/\\\\]amcharts4[/\\\\])",
"^.+\\.module\\.(css|sass|scss)$"
],
Create config/jest/babelTransformImportExport.js:
const babelJest = require("babel-jest");
module.exports = babelJest.createTransformer({
plugins: [require.resolve("#babel/plugin-transform-modules-commonjs")],
babelrc: false,
configFile: false,
});
Tests should be running now.
Edit: As Subrato Patnaik mentioned (using amcharts with jest), amcharts use APIs such as SVGPathElement which aren't yet available in Jest test environment (JSDOM - issue #2128). In other words, your tests won't probably work, if you're using standard mounting. But they might work if you are using e.g. enzyme and its shallow rendering.
If you don't use enzyme or it doesn't work, then as the last resort, you can try to simply define missing APIs in a minimalistic way and see whether it is sufficient:
Change setupFiles in jest config to:
"setupFiles": [
"react-app-polyfill/jsdom",
"<rootDir>/config/jest/setup.js"
],
Create config/jest/setup.js:
class SVGGraphicsElement extends SVGElement {}
class SVGGeometryElement extends SVGGraphicsElement {}
class SVGPathElement extends SVGGeometryElement {}
Object.assign(global, {
SVGGraphicsElement,
SVGGeometryElement,
SVGPathElement,
});
PS: If you are using pnpm instead of npm/yarn, then you will need to update transformIgnorePatterns to:
"node_modules[/\\\\](?!(|\\.pnpm[/\\\\]#amcharts.*node_modules[/\\\\])#amcharts[/\\\\]amcharts4[/\\\\])",
otherwise the old regexp would match (and therefore ignore) paths such as node_modules/.pnpm/#amcharts+amcharts4#4.10.21/node_modules/#amcharts/amcharts4/core.js

Setting up test coverage and thresholds with create react app and typescript

Following the example here https://create-react-app.dev/docs/running-tests/
my package.json now has...
Package.json
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}",
"!<rootDir>/node_modules/"
],
"coverageThreshold": {
"global": {
"branches": 90,
"functions": 90,
"lines": 90,
"statements": 90
}
},
"coverageReporters": [
"text"
],
"snapshotSerializers": [
"my-serializer-module"
]
},
I run CI=true npm test
And I get the error
● Validation Error:
Module my-serializer-module in the snapshotSerializers option was not found.
<rootDir> is: /Users/me/Documents/Proj/React/my-app
Configuration Documentation:
https://jestjs.io/docs/configuration.html
Maybe you should try to watch what is a testing library and how setup yours!
You don't have to compile your TS for run test on it but you should try to get a look at jest.io and testing-library.com is not complicated to setup testing library at all.

Jest is using the wrong version of core-js when testing react-beautiful-dnd

Jest is using the wrong version of core-js when building components that import from react-beautiful-dnd. However, at runtime, there is no problem and our pages build successfully.
We are building a kanban board using react-beautiful-dnd. At runtime, everything is fine and the library works really well: pages load, components are draggable where they should be draggable, etc etc.
However, it is causing problems in our tests (we are using jest and enzyme). When we try to test components that import from the react-beautiful-dnd library, we hit errors like the following:
FAIL app/javascript/spec/Kanban/KanbanColumn.spec.js
● Test suite failed to run
Cannot find module 'core-js/library/fn/object/assign' from 'assign.js'
However, Jest was able to find:
'../core-js/object/assign.js'
The issue appears to be that react-beautiful-dnd depends on #babel/runtime-corejs2, which depends on core-js2. Our app is running #babel/core 7.5.5 and core-js 3.2.1. The folder structure of core-js3 is completely different, and so when jest tries to access its files, the paths are wrong.
Because these errors are not replicated at runtime, it seems that the issue must be with our jest/testing configuration.
We have managed to work around this problem by mocking the react-beautiful-dnd library in all tests of components that depend on it, but this is a bit frustrating and I was wondering if there is a better solution that simply configures jest to use the correct version of core-js in the same way as the runtime.
Our babel config:
module.exports = {
presets: [
[
'#babel/preset-env',
{
modules: false,
targets: {
browsers: '> 1%',
},
useBuiltIns: 'usage',
corejs: 3,
forceAllTransforms: true,
},
],
'#babel/preset-react',
],
plugins: [
'#babel/plugin-syntax-dynamic-import',
'#babel/plugin-proposal-object-rest-spread',
'#babel/plugin-transform-object-assign',
[
'#babel/plugin-proposal-class-properties',
{
spec: true,
},
],
'react-hot-loader/babel',
],
env: {
test: {
presets: ['#babel/preset-env', 'jest', '#babel/preset-react'],
plugins: ['#babel/plugin-proposal-class-properties'],
},
},
};
Our jest config:
"jest": {
"setupFiles": [
"jest-date-mock",
"./app/javascript/spec/setupTests.js"
],
"roots": [
"app/javascript/spec"
],
"moduleFileExtensions": [
"js",
"jsx",
"css",
"scss"
],
"moduleDirectories": [
"<rootDir>/node_modules"
],
"moduleNameMapper": {
"\\.(css|scss)$": "identity-obj-proxy",
"^.+\\.(jpg|jpeg|png|gif|svg)$": "<rootDir>/app/javascript/spec/__mocks__/fileMock.js",
"\\.(gif|svg|png)$": "<rootDir>/app/javascript/spec/__mocks__/fileMock.js",
"\\.worker.entry.js": "<rootDir>/app/javascript/spec/__mocks__/workerMock.js"
},
"collectCoverageFrom": [
"**/app/javascript/components/**"
],
"coverageThreshold": {
"global": {
"statements": 49,
"branches": 5,
"functions": 15,
"lines": 48
}
},
"snapshotSerializers": [
"enzyme-to-json/serializer"
]
},
Jest setup:
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import 'core-js/stable';
import 'regenerator-runtime/runtime';
configure({ adapter: new Adapter() });

Babel will not compile .test.js files while running Jest

While running yarn run jest --no-cache, An error is being thrown that says:
SyntaxError: Unexpected token import
My best guess is that babel is not reaching this this test file. Is their something special I need to include in .babelrc?
path:
/src/tests/LandingPage.test.js
test file:
import React from 'react';
import ReactShallowRenderer from 'react-test-renderer/shallow';
import LandingPage from '../../components/LandingPage';
test('Should render LandingPage correctly', () => {
const renderer = new ReactShallowRenderer();
renderer.render(<LandingPage />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
.babelrc :
{
"presets": [
"env",
"react"
],
"plugins": [
"transform-class-properties",
"transform-object-rest-spread"
]
}
Thanks #hannad rehmann for the nudge in the right direction here is the solution that worked for me.
Install babel-jest
yarn add babel-jest --dev
Configure .babelrc for test env
Jest automatically sets your Env to test, so duplicate whatever config you want to the test env.
{
"presets": [
"env",
"react"
],
"plugins": [
"transform-class-properties",
"transform-object-rest-spread"
],
"env": {
"test": {
"presets": [
"env",
"react"
],
"plugins": [
"transform-class-properties",
"transform-object-rest-spread"
]
}
}
}
Add jest.config.json to project root
{
"transform": {
"^.+\\.jsx?$": "babel-jest"
}
}
Finally, let your test script know where to find config file
I just added it to my test script in package.json, but you can also just run this in the command line.
"scripts": {
"test": "jest --config=jest.config.json --watch"
},
oh. this issue had me waste so many days. here is what you need to do.
before that check these files.
1) .babelrc install corresponding modules and add them to package.json
define different env support as your jest always changes NODE_ENV to "test"
{
"presets": [
[
"env",
{ "modules": false }],
"react"
],
"plugins": [
"react-hot-loader/babel",
"transform-object-rest-spread",
"transform-class-properties",
"dynamic-import-webpack"
],
"env":{
"test":{
"presets": [
"env",
"react"
],
"plugins": [
"transform-object-rest-spread",
"transform-class-properties",
"dynamic-import-webpack"
]}
}
}
2) add this to your package.json
"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|scss)$": "<rootDir>/__mocks__/styleMock.js"
},
"automock": false,
"transform": {
"^.+\\.jsx?$": "<rootDir>/node_modules/babel-jest",
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js"
},
"moduleFileExtensions": [
"js",
"jsx"
],
"moduleDirectories": [
"node_modules"
],
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/react/",
"<rootDir>/node_modules/react-dom/"
],
"transformIgnorePatterns": [
"/node_modules/"
],
"coveragePathIgnorePatterns": [
"/node_modules/"
],
"modulePathIgnorePatterns": [
"/node_modules/"
],
"collectCoverage": true,
"coverageReporters": [
"json",
"lcov",
"text"
]
}
What I understood about this problem is that Jest will change your NODE_ENV to "test" and Babel doesn't have any configuration for this env, we normally define Babel config for development and production env. When there is no babel transpilation, import keyword actually becomes undefined as it actually doesn't exist in JS context.
For anyone looking for solutions, in my case the problem turned out that I had my NODE_ENV environment variable configured to development for some reason.
Now JEST only sets the env to test if NODE_ENV is not defined yet, otherwise it'll use the value of NODE_ENV. This means if you have added in your .babelrc or babel.config file a dedicated part for the test (something like below), it will be ignored,and defaults (or the one matching your NODE_ENV) will be used instead!
{
...
"env": {
"test": { presets: [ "#babel/preset-env" ] }
}
...
}
So if it looks like JEST does not transform your test files (which one of a sign can be a SyntaxError: Cannot use import statement outside a module when running tests reated to your test.js or spec.js file) I'd recommend to check if you have NODE_ENV defined.
Use the env command (on MacOS and Linux or the appropriate command for your environment) to check the configured environment variables. If you have it already configured to something (other than test) you need to either remove that or prepend your jest commands with appropriate override: env NODE_ENV=test jest.
I hope it'll help others. Took me good few hours to figure out what was going on...

react storybook jest snapshots leads to an error Cannot find module '../../package' from 'node.js'

I want to combine storybooks and jest snapshot testing, but I don't get it working.
As soon as I follow the doc and add the Snapshot.test.js, it leads to following error, when I run npm test.
FAIL ./Storyshots.test.js Test suite failed to run
Cannot find module '../../package' from 'node.js'
at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:169:17)
at Object.<anonymous> (node_modules/babel-core/lib/api/node.js:60:16)
anyone has a clue / hint if this is a failure of implementation or a bug?
thnx a lot!
this is my jest configuration, it my gives a hint?
"jest": {
"rootDir": "",
"transform": {
".*": "<rootDir>/node_modules/babel-jest"
},
"moduleFileExtensions": [
"js",
"jsx"
],
"collectCoverage": false,
"collectCoverageFrom": [
"**/*.{js,jsx}",
"!**/node_modules/**",
"!**/vendor/**"
],
"coverageDirectory": "<rootDir>/coverage",
"setupTestFrameworkScriptFile": "<rootDir>/jestSetup.js",
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/react",
"<rootDir>/node_modules/react-dom",
"<rootDir>/node_modules/react-addons-test-utils",
"moment",
"jasmine-expect-jsx",
"fbjs",
"enzyme",
"expect",
"cheerio",
"htmlparser2",
"lodash",
"domhandler",
"object.assign",
"define-properties",
"function-bind",
"object-keys",
"object.values",
"es-abstract"
]
},
I had this same problem and my solution was add "json" into "moduleFileExtensions", just like this:
...
"moduleFileExtensions": [
"js",
"jsx",
"json"
],
...
Seems like the file 'package' was not a js[x] file, but a json one, and jest refused to load it.

Resources