Syntax Error when test component with SASS file imported - javascript

I'm trying test my React component with Jest + Enzyme, but when my component has SASS file (scss), is occurring SyntaxError.
This is my SASS file content:
.user-box {
width: 50px;
height: 50px;
}
And I just import that in my component:
import React from 'react';
import './userBox.scss';
class MyComponent extends React.Component {
render() {
const style = {
borderRadius: '99px'
};
return (
<div>Hello World</div>
);
}
}
export default MyComponent;
Following error message of my test:
If I comment the import './userBox.scss';, test will be okey.
How to can I test React component with Jest + ‵Enzyme` when has style imported

If you have Babel in your stack, you can fix this in the right way using babel-jest
Just do npm i --save-dev babel-jest and in your jest settings file add:
"moduleNameMapper": {
"^.+\\.(css|less|scss)$": "babel-jest"
}

You have do define a mock for this kind of file by define moduleNameMapper in your jest settings.
We are using identity-obj-proxy. So install it with
npm install identity-obj-proxy --save-dev
and add it your jest setting:
"moduleNameMapper": {
"^.+\\.(css|less|scss)$": "identity-obj-proxy"
}

The following information wasn't available before, so I made a pull request on facebook/jest and it was merged.
I wanted to stub style imported in modules, something like:
// module.js
import Style from '#/path/to/style.scss';
import App from './App';
So I created a style stub file:
// test/unit/stubs/style.js
module.exports = '.style-stub{color:red;}';
After messing around with the following jest.conf.js:
moduleNameMapper: {
'^#/(.*)$': '<rootDir>/src/$1', // '#' alias
'^.*\\.scss$': '<rootDir>/test/unit/stubs/style.js',
}
I found that the moduleNameMapper ordering is important. The # alias rule was resolving before my .scss rule, so the style file was loaded as a normal module and would crash the test.
The solution is to put specific rules first.
moduleNameMapper: {
'^.*\\.scss$': '<rootDir>/test/unit/stubs/style.js',
'^#/(.*)$': '<rootDir>/src/$1',
}

I have been searching for a while for a solution to a similar problem and I kept coming across the solution above.
I didn't seem to work for me at first but I realised that Jest was simply ignoring anything I added to "jest" in package.json. My setup includes a jest.config.js file. I found that if I added "moduleNameMapper" there, it worked. So now my jest.test.config.js looks something like this:
module.exports = {
setupFiles: ["<rootDir>/testSetup.js"],
moduleNameMapper: {
"^.+\\.(css|scss)$": "identity-obj-proxy",
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
"<rootDir>/fileMocks.js"
}
};

Related

react helper import fails in production but works in development

I've got a file called "globalHelper.js" like this:
exports.myMethod = (data) => {
// method here
}
exports.myOtherMethod = () => { ... }
and so on...
I import my Helper in other files like this:
import helper from "../Helper/globalHelper";
Now there is the problem:
In the past, everything worked with that when running my build-script:
"build": "GENERATE_SOURCEMAP=false react-scripts build"
but for some reason, when I run "npm run build", I get the error:
Attempted import error: '../Helper/globalHelper' does not contain a default export (imported as 'helper')
However, when I simply start my development server (npm start), everything works just fine.
I already tried to import like import { helper } from "../Helper/globalHelper";, but that did not work either.
Does someone know how to solve that?
try exporting like this with ES6 syntax
export const myOtherMethod = () => { ... }
then
import { myOtherMethod } from '...your file'
The method you are using exports.functionName is CJS. you need to use require to get the methods.
The CommonJS (CJS) format is used in Node.js and uses require and
module.exports to define dependencies and modules. The npm ecosystem
is built upon this format.
If you want to use module method you can do this.
export { myOtherMethod1, myOtherMethod2 }
then you import like this.
import * as Module from '....file name'
Since you've not export default you should import the function with {} like :
import {helper} from "../Helper/globalHelper";

Can i use Enzyme's .hasClass feature with react components importing css files?

i am currently setting up a test environment and come across a problem, that all my calls to .hasClass return false.
Current Setup: My react components import scss files with an import statement. For example:
import styles from "./text.scss";
To test the components i had to define the moduleNameMapper in the jest.config.js file like so:
moduleNameMapper: { "\\.(scss|less)$": "<rootDir>/__mocks__/styleMock.js" },
I think that the moduleNameMapper is kind of responsible for the problems, since it replaces via default all scss definitions with an empty module. (styleMock.js content is just module.exports = {};)
But i need it to test my components, otherwise it would result in an error, when jest tries to load the scss imports.
When i now try this:
it("is Title", () => {
const wrapper = shallow(<Text textType={TextType.Title} />);
expect(wrapper.find("div").hasClass("Title")).toEqual(true);
});
It always returns false.
Is there any solultion on how to test the scss classes (with .hasClass from enzyme?), when you have scss import statements in your component?
Found a solution finally that works!
For me i had to install the identity-obj-proxy via
npm install --save-dev identity-obj-proxy
and then add it to the jest config file like that:
moduleNameMapper: {
"^.+\\.(css|less|scss)$": "identity-obj-proxy"
}
After that my class name's are now in the snapshots correctly and no more undefined classnames!
In addition to that i can now finally use the .hasClass feature of enzyme and check if new css class had been added to a div and so on. (Finally i can go into testing those conditional rendering parts!)

Auto-completion in Webstorm for my custom npm module (ES6/Babel)

When I use material-ui package I get nice auto-completion in Webstorm (ctrl+space):
I thought it might have something to do with the fact the package includes an index.es.js file:
import _AppBar from './AppBar';
export { _AppBar as AppBar };
import _AutoComplete from './AutoComplete';
export { _AutoComplete as AutoComplete };
import _Avatar from './Avatar';
export { _Avatar as Avatar };
import _Badge from './Badge';
export { _Badge as Badge };
import _BottomNavigation from './BottomNavigation';
...
So I generated my own index.es.js in my custom npm module and put it next to the transpiled index.js:
import {ActionTypes as _ActionTypesElements} from './reducers/elements/elements';
export { _ActionTypesElements as ActionTypes };
import {ActionTypes as _ActionTypesAppState} from './reducers/appState/appState';
export { _ActionTypesAppState as ActionTypesAppState };
import _appStateActions from './reducers/appState/appState_actions';
export { _appStateActions as appStateActions };
...
And yet I get no auto-complete:
Any idea why?
Found the answer:
Had to add a jsnext:main field to the package.json of the npm module:
package.json:
...
"module": "./index.js",
"jsnext:main": "./index.es.js",
...
Webstorm recognizes the package's inner exports.
In WebStorm 2019.3, here are the steps I follow to force Code Completion (including auto-import) to work for a custom, self-published NPM package:
Ensure that the project, itself, has a package.json file at the root of the project, and that package.json includes the desire package in the "dependency" object. For example:
{
"name": "testproject",
"version": "1.0.0",
"dependencies": {
"#yourname/yourpackage": "latest"
}
}
In WebStorm, select File > Invalidate Caches / Restart...
To enable auto-import for package contents, ensure that the JavaScript file in which the package is being used has AT LEAST ONE export statement. For example, in the following code, an export is present, so Code Completion auto-imports the package function isNil():
export function init () {
isNil
}
By comparison, the following code does not contain an export statement, so isNil() is not automatically imported:
function init () {
isNil
}
For me, all three of the preceding steps are necessary for Code Completion to work for my own NPM packages in WebStorm.

Mocha keeps bombing due to absolute paths

I'm having a great deal of trouble using Enzyme and Mocha to test my React project. I have a test like this:
import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import { ChipInput} from '../client/components/Chips';
describe('<ChipInput />', _ => {
it('rocks', done => {
done();
});
});
And when ChipInput gets imported, that file imports something with an absolute path, e.g. /lib/collections/tags, and then Mocha errors out because it apparently only does relative paths. How do I get this working?
EDIT:
The actual error:
Error: Cannot find module '/lib/collections/tags'
This happens because /tests/ChipInput-test.js imports the ChipInput component from /client/components/Chips/index.js, which has the following lines:
import React from 'react';
import {
MapsLocalOffer as TagIcon,
ImageRemoveRedEye as InsightIcon,
EditorInsertChart as TestIcon,
SocialPerson as UserIcon,
} from 'material-ui/svg-icons';
import { Tag } from '/lib/collections/tags'; // error thrown here
import { Insight } from '/lib/collections/insights';
// import { Test } from '/lib/collections/tests';
import Chip from './Chip';
import ChipDisplay from './ChipDisplay';
import ChipInput from './ChipInput';
import * as chipTypes from './chip-types';
To anyone hitting here from google, while ffxsam's answer will work, there are many ways to accomplish this. Node's require allows for a base to be set either via environment variable or programmatically, allowing for simple absolute paths that don't require the leading slash (require("my/module"); vs require("/my/module");).
I use gulp as a taskrunner, so my preferred technique is to use app-module-path to do the following at the top of my gulpfile (this will work anywhere, so long as you haven't encountered any absolute requires yet):
require('babel-core/register'); //for mocha to use es6
require('app-module-path').addPath(__dirname + '/src'); //set root path
//I also use webpack to pull in other extensions, so I
//want mocha to noop out on them
require.extensions['.css'] = _.noop;
require.extensions['.scss'] = _.noop;
require.extensions['.png'] = _.noop;
require.extensions['.jpg'] = _.noop;
require.extensions['.jpeg'] = _.noop;
require.extensions['.gif'] = _.noop;
For a more complete rundown, check out this gist by github user branneman: https://gist.github.com/branneman/8048520
This has been awhile, but I want to share my solution here, just in case, all solutions above don't work in your specific situation. I was looking for a solution to fix our unit test, which failed "Error: Cannot find module 'components/shared/xyz', our 'components' folder is under 'client/src' folder, so I came up with the following solution which works for us.
npm install babel-plugin-module-resolver --save-dev
{
'plugins': [
'babel-plugin-module-resolver',
{ 'root': ['client/src'] }
]
}
Here's the solution, nice and simple!
https://github.com/mantrajs/babel-root-slash-import
Basically, install said package:
npm install babel-root-slash-import --save-dev
Add the plugin to .babelrc:
{
"plugins": [
"babel-root-slash-import"
]
}
And it's good to go.

Jest: cannot find module required inside module to be tested (relative path)

I have this component:
import React from 'react';
import VideoTag from './VideoTag';
import JWPlayer from './JWPlayer';
class VideoWrapper extends React.Component {
//... component code
}
That based on some logic renders another component inside ( VideoTag or JWPlayer) but when I try to test it in a jest file i get the error:
Cannot find module './VideoTag'
The three coponents are in the same directory that's why it actually works when I transpile it and see it in action in a browser but looks like Jest is having problems resolving those relative paths, this is the jest file:
jest.dontMock('../src/shared/components/Video/VideoWrapper.jsx');
import React from 'react';
import ReactDOM from 'react-dom';
TestUtils from 'react-addons-test-utils';
import VideoWrapper from '../src/shared/components/Video/VideoWrapper.jsx';
describe('VideoWrapper tests', () => {
it('Render JWPlayer', () => {
let vWrapper = TestUtils.renderIntoDocument(
< VideoWrapper model={model} />
);
});
});
The error is at line:
import VideoWrapper from '../src/shared/components/Video/VideoWrapper.jsx';
How do I tell jest how to handle relative paths?
I also had to add the moduleNameMapper to my jest configuration for my tsconfig path maps in order to get my tests to recognize the path maps I had setup. Something like this:
"moduleNameMapper": {
"^yourPath/(.*)": "<rootDir>\\yourPath\\$1"
}
Hopefully this will help someone down the line!
The problem were not the paths, It was looking for modules only with .js extension, it worked after adding the .jsx in the jest configuration:
"moduleFileExtensions": [
"js",
"jsx"
]
You don't need to add moduleFileExtensions in the configuration for these two options since jest uses ['js', 'jsx', 'json', 'node'] as default file extensions. (Unless you want to specifically skip any option that is)
In my case the issue was the import is also case sensitive. Check your import statement and ensure that it matches the filename exactly!
For others ending up here trying to use Jest with TypeScript: you need to include ts in the moduleFileExtensions, e.g.:
"moduleFileExtensions": [
"js",
"jsx",
"json",
"node",
"ts"
]
You also need a transform for *.ts files:
transform: {
"^.+\\.vue$": "vue-jest",
"^.+\\.js$": "babel-jest",
"^.+\\.(ts|tsx)$": "ts-jest"
},

Categories

Resources