2012.10.29

Node.js Protip: Avoid Global Test Runners

Some of the most popular Node.js test frameworks advertise that they should be installed globally: Jasmine, Mocha, Buster.js, etc… I consider this an anti-pattern.

On this post I will try to explain why it’s an anti-pattern and show how to avoid global installs by using npm test instead.

Globals are evil!

Everybody knows that global variables are evil, but somehow nobody been talking about global installs of tools that doesn’t need to be installed globally to work. Very few Node.js modules should be installed globally, probably only tools like jshint (which can be used by text editors/IDEs) or anything that you expect to use together with other shell commands (ie. file system related tools). If your project depends on some third party code to work (including your tests) always favor local installs.

Local dependencies can be listed on the package.json file, so you keep track of the version, you can also commit them together with the project source code (making it easier for other devs to clone your project). It will reduce version conflicts and surely save you some headaches like “why do the tests work on my machine but not in others?”, which might be caused by a version conflict on the test framework.

If every single tool is installed globally the chance of name collisions will get extremely high. Please don’t do it unless you really need it.

npm test is your savior

Besides the fact of NPM being an awesome package manager it also has the very neat feature called scripts. It allows custom hooks to be executed before/after/during a certain action and comes with some good default behavior.

You probably want to run the tests multiple times and probably with the same arguments, so it’s way better to keep the test information inside the package.json file and reference the local bin file:

{
    "name" : "example",
    "version" : "1.0.0",
    "devDependencies" : {
        "jasmine-node" : "~1.0.26"
    },
    "scripts" : {
        "test" : "jasmine-node spec"
    }
}

Now you can run npm install on the project folder to install the devDependencies and every time you run npm test, it will execute the node node_modules/jasmine-node/bin/jasmine-node spec command, simple like that. (node add all the binaries inside node_modules/.bin to the PATH)

Another good trick is to use npm install --save and npm install --save-dev to automatically add the dependencies to the package.json file.

Automate ALL the things and avoid globals for a saner life.

Further Reading


Comments

Since npm test uses npm run-script, it executes with node_modules/.bin in the PATH so you can shorten the command to jasmine-node spec. :)

I've actually solved this in a different way in my testing library, suite.js. I simply make my tests executable and run them. No need to deal with globals.

I can see this doesn't quite scale if you have a big library and like to split up tests to numerous files. I guess it might be cool to apply your advice and expand suite.js to support this. It's not a particularly difficult thing to implement even.

Leave a Comment

Please post only comments that will add value to the content of this page. Please read the about page to understand the objective of this blog and the way I think about it. Thanks.

Comments are parsed as Markdown and you can use basic HTML tags (a, blockquote, cite, code, del, em, strong) but some code may be striped if not escaped (specially PHP and HTML tags that aren't on the list). Line and paragraph breaks automatic. Code blocks should be indented with 4 spaces.