This guide is part of The Complete Guide to ES6 with Babel 6 series. If you’re having trouble upgrading to Babel 6, start with Six Things You Need To Know About Babel 6.
So you’ve written a useful little app with ES6, and being the excellent developer that you are, you want to test it. You’ve got some experience testing with Mocha, so you write a few tests and run them. And bam, nothing works. Why? Because by default, Mocha only knows ES5. But luckily, teaching Mocha ES6 only takes about a minute and 30 seconds!
Dependencies
Skip this section if you’ve already installed Babel 6 and any required presets/plugins.
Babel 6 doesn’t play well with its younger self, so start by removing any older Babel packages from package.json
— babel
, babel-core
, etc. Make sure you npm uninstall <package-name>
each one to remove them from node_modules
too.
We’ll need to install the babel-core
package to get access to its require hook:
npm install babel-core --save-dev
Once complete, you’ll need to install the presets and plugins you want to use to transform your code. Start with babel-preset-es2015
– Babel’s collection of ES6 transforms. If you want to use JSX in your tests, you’ll also want babel-preset-react
. You can also use experimental ES7 features by adding babel-preset-stage-0
, but please take a long, hard think about your life before you do.
# For ES6/ES2015 support
npm install babel-preset-es2015 --save-dev
# If you want to use JSX
npm install babel-preset-react --save-dev
# If you *must* use experimental ES7 features
npm install babel-preset-stage-0 --save-dev
Configuring Babel
Of course, just having Babel’s packages installed isn’t enough. We still need to tell Babel to use them!
For the Webpack and Babel CLI episodes, we were able to do this with configuration specific to each tool. But while Mocha let’s us run our tests through Babel, it provides no way to configure it. This means we’ll need to configure Babel with a .babelrc
file in the project’s root directory:
{
"presets": ["es2015"]
}
If you want to use the react
or stage-0
presets, just add them to the presets
array.
Unfortunately, .babelrc
is shared between all tools which can’t set their own configuration. For example, Gulp also reads .babelrc
when used with a gulpfile.babel.js
. Plan accordingly, and try not to put anything in there which is going to surprise you later on.
Running ES6 tests
Once Babel is installed and configured, all that is left is to tell Mocha to use it!
mocha --compilers js:babel-core/register
Assuming you haven’t used any of ES6’S new built-in’s, your tests should pass with flying colours. But what if you have?
Now my tests compile, but fail?!
While the babel-core/register
script transforms your tests into ES5 JavaScript, it takes care not to change the global environment. That means that if Promise
, Map
, Set
or Object.assign
are missing from your JavaScript environment, they’ll stay missing.
For testing, this has a definite upside: your tests see what the consumer sees. But maybe you’re package isn’t meant to be published, or maybe you’re testing an app instead of a library. In this case, you don’t care about the global environment. And in all likelihood, you want to use ES6 — not a confusing subset of it. So install the built-ins with babel-polyfill
:
npm install babel-polyfill --save
And then require them by adding it to the top of your tests:
import 'babel-polyfill'
But keep in mind that if you’re publishing a library, this will eventually cause you to publish code which will not run on the majority of JavaScript runtimes. Loading babel-polyfill
in your tests won’t load it for your consumers too. Be careful.
Tests vs Source
Talking about published code, let’s say you’re writing a library which you’d like to publish to NPM. Because you’ve done your research, you know that your published source should be ES5. And to make this happen, you’ve set up your project to compile your src
directory’s files to a lib
directory before publishing.
Naturally, your tests import the lib
code which you’re actually publishing, not the original src
files. And while this may go without saying, make sure you compile your code before testing!
Assuming you’ve followed part 1 and configured npm run compile
to compile your source, that means running your tests after the compilation step:
npm run compile && mocha --compilers js:babel-core/register
Of course, even though you know you should run your tests like this, you may well forget. And that’s why you should…
Configure your tests in package.json
By adding a test
entry to the scripts
object in package.json
, NPM will know to run the above test command whenever we call npm test
from the terminal:
"scripts": {
"test": "npm run compile && mocha --compilers js:babel-core/register"
},
Babel 5’s register
script was located in the babel
package, not the babel-core
package. So if you’re upgrading, make sure to update the package name in the test
script in package.json
!
Examples
For an example of a package with tests run with Mocha and Babel 6, see react-pacomo.
OK, it works! But for how long?
Here’s a little story: while writing these guides, I learned that the require hook in babel-core
used by Mocha is already set to be deprecated (it will now be placed in a new package called babel-require
). This is despite the fact that Babel 6 only introduced the current way of doing things a few weeks ago.
Staying up to date in our JavaScript-driven world can be tough — and that’s why I provide my Newsletter! Subscribe to receive my latest guides to writing small apps with React. And in return for your e-mail, you’ll immediately receive three bonus print-optimised PDF cheatsheets – on React (see preview), ES6 and JavaScript promises. All for free!
I will send you useful articles, cheatsheets and code.
One more thing – I love hearing your questions, offers and opinions. If you have something to say, leave a comment or send me an e-mail at james@jamesknelson.com. I’m looking forward to hearing from you!
Read More
- Babel Documentation: Require Hook
- Compiling ES6 NPM packages with the Babel 6 CLI
- Using ES6 and ES7 in the Browser, with Babel 6 and Webpack
- Webpack Made Simple: Building ES6/LESS with Autorefresh
- Learn Raw React
According to babel-core’s source, babel-register will be the new standard for the require hook :
`npm install babel-register –save-dev`
`mocha –compilers js:babel-register`
Works fine for me !
With babel 5.x. I was able to use require hook via mocha –require option.
I used to have a js file where I do require(‘babel-core/register’, options).
Is that approach changed with babel 6.x ? I was relying on babel option “resolveModuleSource” to make by tests play nice with System.js plugins I was using.
Yes, `mocha –require babel-register` will works as well.
Can you make `mocha –watch` works with babel?
yes you can. Just add the watch option:
$ mocha –compilers js:babel-core/register –require ./test/test_helper.js –recursive –watch”
From what I gather, babel recommends using babel-runtime for libraries rather than babel-polypill. I understand the argument that tests are not going to be shared with the consumers though is there a way to leverage babel-runtime with Mocha instead of needing the polyfills in the tests ?
Thanks much for the article
I was also seeing errors during mocha tests saying “Unexpected token export”, which were pointing to when external modules that contained es6 code. I fixed this error by adding this to the top of my mocha test script
require(“babel-register”)({
ignore: false
});
Source: See note about node_modules being ignored by babel-register here https://babeljs.io/docs/usage/require/
Not sure how ideal this setup is but it worked for me!
you have a demo code for this. I tried this but keep getting error. I made a demo of code on github see if people can help debug. https://github.com/craigcosmo/react-redux-test
My tests fail because babel changes certain variables to be prefixed with an underscore.
So ‘myVar’ will become ‘_myVar’.
My problem is that when I transpile my tests with babel, the same rules don’t always apply.
So in a test that injects a variable called myVar into an angular controller that has been changed to _myVar, everything breaks.
I can’t figure out how to fix this.
Is there any way to tell Babel not to parse certain files: eg:
SyntaxError: /Users/larry/Projects/Dynamic-Traveler-2/app/assets/base/interface/move-folder.png: Unexpected character ‘�’ (1:0)
�PNG
The component I am testing imports images