As you might be aware, our stack runs unit tests using mocha directly on Node.js. Those tests do not run in the browser, which makes the setup much simpler (no bundling, no karma) and most importantly it makes it much faster. The down side of this of course is that any browser API is not available in Node.js environment. Enzyme, which is a very commnly used testing utility for React, is using document
, window
and DOM API, which is obviously a problem if we run tests in Node.js and not in the browser, but luckily we can use a library called jsdom, which implements the whole DOM API in Node.js.
This guide explains how to add jsdom to an existing project in order to enable testing using mocha and enzyme on Node.js without a browser. Projects generated by the wix-js-stack generator already includes jsdom, so this guide should be used by people who are adding jsdom to an old project that was generated before jsdom support was baked in and obviously also for people who would like to understand how this works.
If you try to use enzyme in a tests without setting up jsdom properly you will probably see this error:
Cannot render markup in a worker thread. Make sure `window` and `document` are available globally before requiring React when unit testing or use ReactDOMServer.renderToString() for server rendering.
Since enzyme doesn't only need DOM API jsdom provides (it actually needs also the document
and window
global variables) we use a library called jsdom-global which uses jsdom in order to setup the global variables as enzyme requires. So actually in order to setup jsdom for enzyme all you have to do is install jsdom-global
as dev dependency:
$ npm install --save-dev jsdom-global
And then import it in your test file:
import 'jsdom-global/register';
Notice that you must do the import BEFORE you import enzyme, otherwise you will still see the error above.
As hopefully you already noticed yourself, jsdom-global
is manipulating the global namespace, which might cause many kinds of problems of state leaking between tests and it has to be cleand up after every test. In addition, it creates window
and document
global variables, which might be confusing for some third party tools since those variables generally indicate that you are running in a browser.
In order to make sure that the window
and document
global variables only exist in tests that use enzyme and in order to make sure we do not leak state between tests it is very important that you group enzyme tests into separate describe
clauses and in those describe
clauses add the following code:
let cleanup;
beforeEach(() => cleanup = require('jsdom-global')());
afterEach(() => cleanup());