This is a quick article to share a little tip on spies and requires
Our test stack uses mocha, karma, sinon. Our code is bundled using webpack
Front-end testin is hard: there are lots of libraries but only a few practical examples. When you start testing your project, you quickly run into problems and you think : “I’m pretty sure someone has been in this position before, why can’t I find any documentation ?”.
Since I was getting frustrated I decided to make my own documentation.
I recently spent some time to understand how I could spy on a module required by the module we were testing… Get it?
If not, just read on ;)
Let’s say you have a main js module, that requires some other module:
var yeah = require('yeah');
var great = function () {
// Do great stuff
// Use the required module
yeah();
}
module.exports = great
yeah
was calledgreat
module (it’s great already)You would like to write something similar to this
// In your test file
var sinon = require('sinon');
var great = require('great');
describe('Great', function() {
var yeahSpy;
beforeEach(function(){
yeahSpy = sinon.spy(great, 'yeah');
});
it('should call yeah', function(){
great();
yeahSpy.should.have.been.called;
});
afterEach(function(){
yeahSpy.restore();
});
});
But this doesn’t work.
It will throw a TypeError: Attempted to wrap undefined property yeah as function
.
Note that I don’t recommend this solution, but I am putting it here for the sake of completeness.
You could modify your great
module so that yeah
is a property.
var yeah = require('yeah');
var great = function () {
// Do great stuff
// Here you need to use the yeah which is a property of great for this to work
great.yeah();
};
great.yeah = yeah;
module.exports = great;
I don’t like this method mainly because these changes don’t really make sense: if not for testing, I would not have done it.
Luckily, there is a better way !
Rewire let’s you require modules and adds getters and setters that help you in your tests.
The trick here is to get the yeah
module with rewire, create a spy on it, and inject the spy back into great
.
var sinon = require('sinon');
// Here use rewire instead of require
var great = rewire('great');
// Here get the `yeah` module
var yeah = great.__get__('yeah');
describe('Great', function() {
var yeahSpy;
beforeEach(function(){
// Create a spy on the correct yeah module
yeahSpy = sinon.spy(yeah);
// Inject the spy in the module, otherwise it doesn't work
great.__set__('yeah', yeahSpy);
});
it('should call yeah', function(){
great();
yeahSpy.should.have.been.called;
});
afterEach(function(){
yeahSpy.restore();
});
});
And you’re good to go !
Note: you might be able to achieve similar results with Proxyquire. We tried very briefly but rewire seemed simpler so we went with it.
For rewire to work with webpack, use … rewire-webpack
. The configuration is easy (shamelessly copy-pasted from rewire webpack’s doc)
// In your webpack config file
var RewirePlugin = require("rewire-webpack");
var webpackConfig = {
plugins: [
new RewirePlugin()
]
};
If you’re interested in other front-end testing stuff, check out David’s article on visual TDD