I'm having an issue with stubbing a particular function with sinon after having used proxyquire.
Example:
// a.js
const api = require('api');
module.exports = (function () {
return {
run,
doStuff
};
function run() {
return api()
.then((data) => {
return doStuff(data);
})
}
function doStuff(data) {
return `Got data: ${data}`;
}
})()
// a.spec.js - in the test
a = proxyquire('./a', {
'api': () => Promise.resolve('data')
})
sinon.stub(a, 'doStuff');
// RUN TEST - call a.run()
I know it isn't working because it calls the original doStuff instead of a mocked/stubbed doStuff.
I know it isn't working because it calls the original doStuff instead of a mocked/stubbed doStuff.
That is because function run()
in a.js invokes function doStuff(data)
inside the closure function run()
is holding over the content of a.js and not function doStuff(data)
in a_spec.js.
Lets re-write a.js to:
var a = 'I am exported';
var b = 'I am not exported';
function foo () {
console.log(a);
console.log(this.b)
}
module.exports.a=a;
module.exports.foo=foo;
and a.spec.js to:
var one = require('./one');
console.log(one); // { a: 'I am exported', foo: [Function: foo] }
one.a = 'Charles';
one.b = 'Diana';
console.log(one); // { a: 'Charles', foo: [Function: foo], b: 'Diana' }
Now if we invoke one.foo()
it will result in:
I am exported
Diana
The I am exported
is logged to the console because console.log(a)
inside foo
points to var a
inside the closure foo
is holding over the contents of a.js.
The Diana
is logged to the console because console.log(this.b)
inside foo
points to one.b
in a.spec.js.
You need to change:
module.exports = (function () {
return {
run,
doStuff
};
function run() {
return api()
.then((data) => {
return doStuff(data);
})
}
function doStuff(data) {
return `Got data: ${data}`;
}
})()
to:
module.exports = (function () {
return {
run,
doStuff
};
function run() {
return api()
.then((data) => {
return this.doStuff(data); // ´this.doStuff´ points to ´doStuff´ in the exported object
}.bind(this)) // to ensure that ´this´ does not point to the global object
}
function doStuff(data) {
return `Got data: ${data}`;
}
})()