Unexpected Token Errors Related to CSS with Mocha tests
Another fun one. You might get something like this error when you're not even testing css (which is pointless and..don't do that!), but mocha might at times depending on what libs you're using for css, if you're using webpack, etc. It might complain due to conflicts with webpack
loading postcss
or other css generated code, and so fourth:
SyntaxError: Header.css: Unexpected token (1:0)
> 1 | :global(.smartbanner) {
| ^
2 | max-width: 100vw;
3 | width: 100%;
4 | position: relative;
In the error above, it's bitching about some css syntax. Wha!? The tests I am running have nothing to do with testing styles! I don't test css you're thinking, WTF! Ugh, I was going so great and now this?
Well it's because the code I'm testing is React code, and it's loading styles, and mocha is not sure what to do with some style generation I guess. A lot of it relates to postcss and other fancy style generation going on these days in the JS world...it gets complicated.
(mini rant) Keep in mind this isn't just a mocha
thing so don't go and think "oh shit, I should just use Jest, mocha sucks and everyone including FB is saying Jest is the motha fing shit!!". Calm down, get off the Jest Snowflake Bandwagon, and chill yourself..enough Koolaid. Wrong, it's total BS and you know it. Mocha works wonderfully and Jest doesn't give you anything mocha doesn't and worse gives you crap you really don't need to be using such as snapshots which I hate. It's just one of cases things where certain libs aren't aware of things and simply need some work arounds. It happens sometimes when you're working with many libs like we all do with node...nothing new. As long as it's not too painful to get around these things that happen in lib, it's all good. If it's really painful, and you just can't handle it , then I digress.
Thankfully as with most conflicts in node modules, many have already come across this and have come up with quick fixes for it.
I've gone with Corey House's nice little script to fix this and it's been working great. I took his and modified it:
mocha-webpack-compiler.js
(you can of course name this whatever you want)
/*
Tests are placed alongside files under test.
This file does the following:
1. Sets the environment to 'production' so that
dev-specific babel config in .babelrc doesn't run.
2. Disables Webpack-specific features that Mocha doesn't understand.
3. Registers babel for transpiling our code for testing.
This assures the .babelrc dev config (which includes
hot module reloading code) doesn't apply for tests.
*/
process.env.NODE_ENV = 'production';
/*
Disable webpack-specific features for tests since
Mocha doesn't know what to do with them.
*/
require.extensions['.css'] = function () {
return null;
};
require.extensions['.png'] = function () {
return null;
};
require.extensions['.jpg'] = function () {
return null;
};
/* Register babel so that it will transpile ES6 to ES5 before our tests run. */
require('babel-register')();
Then just pop that file where you feel a good place is in your app, and then reference it from your mocha scripts by poping in the relative path to it. For example I added ./src/test/mocha-webpack-compiler.js
to my existing mocha script.
What's also nice is that in that file at the end it includes require('babel-register')();
So that means you don't have to add --compilers js:babel-core/register
to every test script in your app, it'll just pick it up from the script above. Just makes your test scripts a little cleaner:
Now the WebStorm test runner no longer needs that flag now:
Nor do your scripts if you're running them that way.
Example in package.json:
"test-isolated-unit": "NODE_ENV=development BABEL_DISABLE_CACHE=1 mocha --require ./src/test/jsdom --compilers js:babel-core/register --recursive ./src/test/unit/**/*.spec.js"
can now just be
"test-isolated-unit": "NODE_ENV=development BABEL_DISABLE_CACHE=1 mocha ./src/test/mocha-webpack-compiler.js --require ./src/test/jsdom ./src/test/unit/**/*.spec.js"