We're using CSS modules in our React components, which are importing .scss
files, like this:
import styles from './ReviewFeedItem.scss';
To ignore them when running jest, I've excluded /scss/
from the module loader (or so I think):
// package.json
"preprocessorIgnorePatterns": [
"/scss/"
],
However, when running the tests, the module loader still tries (and fails) to parse the .scss file as javascript and yields this error:
Runtime Error
SyntaxError: Unexpected token ILLEGAL in file 'src/components/navigation/Navigation.scss'.
Make sure your preprocessor is set up correctly and ensure your 'preprocessorIgnorePatterns' configuration is correct: http://facebook.github.io/jest/docs/api.html#config-preprocessorignorepatterns-array-string
If you are currently setting up Jest or modifying your preprocessor, try `jest --no-cache`.
Preprocessor: jest-preprocessor.js.
Jest tried to the execute the following preprocessed code:
body { height: 0; }
Any variation of the exclude Pattern, such as \\.scss
, scss
and so forth has no effect.
We're using babel-jest
as the scriptPreprocessor
(so no specific entry for that in package.json)
Any updates on this?
This doesn't work because ignoring scss from the preprocessor just means that it will not be run through babel-jest. Jest will then try to require the scss file directly and then fail because it isn't valid JavaScript.
There are two solutions:
moduleNameMapper
option and a stub file:Jest config:
"moduleNameMapper": {
"\.scss$": "path/to/SCSSStub.js"
}
SCSSStub.js:
module.exports = {}; // Or other stub data for all SCSS modules.
node-sass
.I'm not entirely sure what webpack does to export scss files as JavaScript, but basically you'll want to wrap babel-jest
and do something like this:
module.exports = function(src, filename) {
if (fileName.endsWith('.scss')) {
return processSass(src);
}
return babelJest.process(src, filename);
}
where the processSass would use node-sass
and whatever the webpack loaders do :)
I hope one of these is a satisfying solution. If you do build a preprocessor that wraps babel-jest, I'd be happy to add it to Jest as an officially supported package.
The moduleNameMapper
solution worked great for me. Here's what I used (took me a while to figure out the magic that would make all imports for SCSS files load the same stub):
"moduleNameMapper": {
"^.*\\.scss$": "./src/shared/test/SCSSStub.js"
}
Now requiring SCSS in Jest works exactly like requiring CSS.
that's great!
preprocessorIgnorePatterns does not need slashes around the entries. It should work with .scss$
, although to @cpojer 's point that won't fix your problem.
I worked around that by having my preprocessor return an empty string if the filename ends in css|less|etc
@cpojer I just tried upgrading to v16.0.1 (from v14.1.0) and all our tests now fail because it complains about syntax errors related scss
files. We have moduleNameMapper
set up and the setup worked fine with v14.1.0. Wondering if you have any thoughts on what might be the issue?
jest setup:
"jest": {
"moduleFileExtensions": [
"",
"js",
"json"
],
"modulePaths": [
"./src"
],
"moduleDirectories": [
"node_modules"
],
"testRegex": "/.*\\-snapshot\\.js$",
"moduleNameMapper": {
"^testUtils": "./src/utils/tests.js",
"^.+\\.(s?css|less)$": "./src/utils/styleMock.js",
"^.+\\.(gif|ttf|eot|svg)$": "./src/utils/fileMock.js"
},
"setupFiles": [
"./src/utils/setupJest.js"
]
},
styleMock.js
// Return an object to emulate css modules
import idObj from 'identity-obj-proxy';
export default idObj;
Example of an error:
@iam-peekay I was getting the same error due to sass imports. Following the instructions in the Jest webpack tutorial resolved the issue for me - specifically adding the moduleNameMapper for files and styles, and the mocks they reference.
I also had to add md
to the mapped file extensions as I'm importing markdown content in the project.
Edit - looked at your setup and I see you have a styleMock - maybe try just using an empty object instead of the idObj
.
Took me a while to get this to work for me because I thought the path was relative to the project.
Below works for me:
"jest": {
"modulePaths": [
"v2/app"
],
"moduleNameMapper": {
".scss$": "SassStub.js" // <-- lives in v2/app
},
"testPathIgnorePatterns": [
"/node_modules/",
"/build/"
]
}
__SassStub.js__
module.exports = {}
Hi guys, I'm running into this problem too. What is a SassStub.js file? What goes inside it? Can't find anything about it.
@leongaban Try this solution: https://stackoverflow.com/questions/41040269/syntax-error-when-test-component-with-sass-file-imported
@leongaban See https://github.com/facebook/jest/issues/870#issuecomment-286575674:
SassStub.js
module.exports = {}
Just a note for future readers, the moduleNameMapper
ordering is important.
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',
}
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 was to put specific rules first.
moduleNameMapper: {
'^.*\\.scss$': '<rootDir>/test/unit/stubs/style.js',
'^@/(.*)$': '<rootDir>/src/$1',
}
@emileber it's generally advised to have as moduleNameMapper
regexes as specific as possible, to avoid such problems and confusion to consumers.
@thymikee Regexes are a maintenance nightmare, so keeping them as simple as possible is best in my opinion.
I feel like it's much more likely that any confusion in this regard comes from the missing documentation rather than under-specific regexes.
@emileber interested in contributing to docs? 馃檪 Patterns are indeed checked one-by-one until they fit and then bailout.
Struggling to get this to work, I have:
"jest": {
"transform": {
"^.+\\.jsx?$": "babel-jest"
},
"collectCoverageFrom": [
"src/**/*.{js,jsx}"
],
"moduleNameMapper": {
"^.*[.](jpe?g|gif|png|less|css)$": "./emptyTestModule.js"
},
"setupFiles": [
"<rootDir>/setupTests.js"
]
}
And I'm not exactly sure where to put the emptyTestModule, I've tried both the root and src/
but I get:
Test suite failed to run
Configuration error:
Could not locate module ag-grid/dist/styles/ag-grid.css (mapped as emptyTestModule.js)
Please check:
"moduleNameMapper": {
"/^.*[.](jpe?g|gif|png|less|css)$/": "./emptyTestModule.js"
},
"resolver": undefined
Edit: I fixed this by using rootDir: "^.*[.](jpe?g|gif|png|less|css)$": "<rootDir>/emptyTestModule.js"
Most helpful comment
This doesn't work because ignoring scss from the preprocessor just means that it will not be run through babel-jest. Jest will then try to require the scss file directly and then fail because it isn't valid JavaScript.
There are two solutions:
Use the
moduleNameMapper
option and a stub file:Jest config:
SCSSStub.js:
Build your own preprocessor using
node-sass
.I'm not entirely sure what webpack does to export scss files as JavaScript, but basically you'll want to wrap
babel-jest
and do something like this:where the processSass would use
node-sass
and whatever the webpack loaders do :)I hope one of these is a satisfying solution. If you do build a preprocessor that wraps babel-jest, I'd be happy to add it to Jest as an officially supported package.