Since the end of 2015, the Envato Front End team has been working on bringing a modern development workflow to our stack. Our main project repo powers sites like themeforest.net and serves around 150 million Page Views a month, so it is quite a challenge to re-architect our front end while maintaining a stable site. In addition, the codebase in 9 years old, so it contains the code from many developers and multiple approaches.
As I mentioned above, it’s a 9 year old code base and nobody can guarantee that introducing something new won’t break the code, so we began all the work with tests in mind. This post documents our experiences developing the framework for testing the React based autosuggestion component.
One issue I had while writing unit test code is that some of the code depends on a browser based environment because they need to access to some browser only object or APIs.
The first solution
Most of the unit tests nowadays are running with Nodejs, so in order to emulate a browser environment, jsdom showed up.
Here’s a handy snippet that you could use before your testing code to prepare a DOM environment:
1 2 3 4 5 6 7 8 9 10 11 12 13
And in your test code, you could just import it and use it by calling the function.
1 2 3
If your code depends on some DOM helper function like jQuery, you may also need to include the source code of jQuery into the prepared environment, you could do:
1 2 3 4 5 6 7 8 9 10 11 12
Notes: in the official jsdom github repo, they give an example of loading jQuery from the CDN which needs an additional network request and can be unreliable and not work if without network. They also have an example loading jQuery source code with nodejs
fs module but it’s not clean as you have to tell the path to jQuery.
Everthing looks OK so far, but why do we bother to having a real browser environment?
The reason is that once things get compliated, your code may depend on more browser based APIs. Of course you could fix your code but what if you are using 3rd party moudles from npm, and one of them happen to depends on
XMLHttpRequest, it’s nearly impossible to “mock” everything, and to be honest, I feel uncomfortable doing it this way as it’s really tricky and kinda dirty.
Let’s run it in a browser
Why not Phantomjs
From the problem we saw above, it’s pretty straight forward to think about just running all the tests in a real browser. If you search “headless browser testing” on Google, the first result will be PhantomJS.
I haven’t used phantomjs a lot and I’m not familar with how it works, but I’ve been heard bad things about it, “lagging behind more and more from what actual web browser do today”, “have 1500+ opened issues on Github”, “unicode encode issue for different language”.
The last concern is actually from my own experince and I mentioned it in my another blog post PDF generation on the web.
Last but not least, I’m not quite confident about how Phantomjs deals with Nodejs code. As my testing code is actually not browser only code, it needs to access to nodjes
fs module as well.
Let’s talk about Electron
What is Electron?
Build cross platform desktop apps with web technologies. Formerly known as Atom Shell. Made with <3 by GitHub.
Let’s run our code in browser
Please read the quick start guide and make sure you know how to write your first Electron App.
You can install it with
npm install browser-run and use it like this:
Run test in Electron
And if you are writting your test with
tape, you could even pipe your testing result to a test reporter like
There are also a tool specific designed for tape named tape-run
A tape test runner that runs your tests in a (headless) browser and returns 0/1 as exit code, so you can use it as your npm test script.
With this tool, it is even easier to run your test.
Tip: There’s also one module to run mocha test named electron-mocha.
As the title indicate, this post is about running tests on any CI server. The reason is that most of the CI servers are neither Mac or Windows, and there’s a known issue with running Electron on Linux, you need a few setup steps to get it running.
Here’s a few notes copied from the repo and thanks to juliangruber for including my section on running it on gnu/linux there.
To use the default electron browser on travis, add this to your travis.yml:
1 2 3 4 5 6 7 8
For Gnu/Linux installations without a graphical environment:
1 2 3 4
There is also an example docker machine here.
Once we have all setups ready, our test will be much simpler without the need to “hack” a browser like environment:
1 2 3 4 5 6 7 8 9 10 11 12 13
And you can put the test code in npm script and call it on your CI
1 2 3 4 5 6 7
As front-end development is changing rapidly recently with things like single page application,
isomorphic universal apps, also front-end tooling system like npm, Browserify, Babel, Webpack, testing will become more complex. I hope this setup will make your life suck less and be significantly eaiser.
Last but not least, if you have any questions or better way for testing setups, let us know!