Yesterday I had a bit of a bad time trying to code some tests for a web application (written in js
). The main problem was that using requirejs
needed some further configuration within tests. It didn’t take too long to find what I was doing wrong but it may be confusing at the beginning. During this post I’ll be talking about:
In order to run tasks you need to install grunt
with npm install -g grunt-cli
.
In order to learn some modular JavaScript and how nodejs
works, I decided to code a card game called Dominion. There are already multiple web versions of this game, there is even an official one. Yet this is a good way of practicing modularity, testing and server/client behaviour with nodejs
.
Let’s show how the work tree is organized:
Let’s look at the package.json
file as it includes all the dependencies needed:
The Gruntfile.js
file has been simplified to match the testing part:
We are using requirejs
to load modules. Therefore we can share some the configuration with a file: require-config.js
In this project I load this file only once, in the main.js
. However when having more complex configuration you should load it every time you need it.
We first start by using requirejs
and selfish
to create some classes that will be used in the application:
We can ignore src/app.js
and main.js
as they are used for the requirejs
entry point and have nothing to deal with testing.
Here comes the important part which is accessing modules from the test and being able to use them. First let’s take a look at the test file:
First we require the different modules needed by node
We are going to use requirejs
to load modules. This is actually different from the nodejs
method require()
. Then we add the configuration. The baseUrl
specifies from which point modules must be found. This path is relative to the runtime, thus when running grunt
at project root (cf tree
) we must specify files as card
or subdir/file
.
When loading modules within tests there’s one important thing: creating a test before calling requirejs()
. This is because Mocha
need to know tests exists. After that we can load any modules needed by the tests:
We declare a variable Card
to store the Card
class and use it later in the tests. By using the before(done)
function we ensure that classes will be available before any test. Calling done()
callback is necessary because we’re dealing with asynchronous module loading, thus we have to notify Mocha
that modules are available. If we don’t call done()
, tests will fail because they will be called before requirejs()
call ends.
Note: The describre()
, before(done)
and it()
methods are BDD
assertions style (as shouldjs
). The TDD
equivalents are suite()
, setup(done)
and test()
Once the setup is done we can do the tests as usual:
Remember to use the done()
callback when dealing with asynchronous code!
You can find the boilerplate here:
https://github.com/posva/mocha-requirejs-boilerplate
The Gruntfile
contains more targets that help development, such as:
serve
: simple HTTP serverdeploy
: Compress and unify every js
file using requirejs
jshint
: run jshint
on project files.default
: will run test
, jshint
and deploy
There’s also a Victory
class to show that everything works just fine with more that one module loading.