ES2016 Class, Sinon Stub Constructor
Solution 1
You'll need to setPrototypeOf the subClass due to the way JavaScript implements inheritance.
const sinon = require("sinon");
class Foo {
constructor(message) {
console.log(message);
}
}
class Bar extends Foo {
constructor() {
super('test');
}
}
describe('Example', () => {
it('should stub super.constructor call', () => {
const stub = sinon.stub().callsFake();
Object.setPrototypeOf(Bar, stub);
new Bar();
sinon.assert.calledOnce(stub);
});
});
Solution 2
You need to spy
instead of stub
,
sinon.spy(Foo.prototype, 'constructor');
describe('Example', () => {
it('should stub super.constructor call', () => {
const costructorSpy = sinon.spy(Foo.prototype, 'constructor');
new Bar();
expect(costructorSpy.callCount).to.equal(1);
});
});
*****Update****** Above was not working as expected, I added this way and is working now.
describe('Example', () => {
it('should stub super.constructor call', () => {
const FooStub = spy(() => sinon.createStubInstance(Foo));
expect(FooStub).to.have.been.calledWithNew;
});
});
Solution 3
Adding to the accepted answer of Wenshan, there is one step that may be overlooked when stubbing the parent class and replacing the original parent class with setPrototypeOf
.
💡 Additionally, to avoid it breaking the succeeding tests it is a good idea to set back the original parent class at the end, like:
const sinon = require("sinon");
class Foo {
constructor(message) {
console.log(message);
}
}
class Bar extends Foo {
constructor() {
super('test');
}
}
describe('Bar constructor', () => {
it('should call super', () => {
const stub = sinon.stub().callsFake();
const original = Object.getPrototypeOf(Bar); // Bar.__proto__ === Foo
Object.setPrototypeOf(Bar, stub); // Bar.__proto__ === stub
new Bar();
sinon.assert.calledOnce(stub);
Object.setPrototypeOf(Bar, original); // Bar.__proto__ === Foo
});
});
The addition is
// saving the reference to the original parent class:
const original = Object.getPrototypeOf(Bar);
// setting back the original parent class after stubbing and the assertion:
Object.setPrototypeOf(Bar, original);
klyd
Updated on May 10, 2021Comments
-
klyd almost 3 years
I'm trying to stub out a super call with sinon, and es2016 but I'm not having much luck. Any ideas why this isn't working?
Running Node 6.2.2, this might be an issue with its implementation of classes/constructors.
.babelrc file:
{ "presets": [ "es2016" ], "plugins": [ "transform-es2015-modules-commonjs", "transform-async-to-generator" ] }
Test:
import sinon from 'sinon'; class Foo { constructor(message) { console.log(message) } } class Bar extends Foo { constructor() { super('test'); } } describe('Example', () => { it('should stub super.constructor call', () => { sinon.stub(Foo.prototype, 'constructor'); new Bar(); sinon.assert.calledOnce(Foo.prototype.constructor); }); });
Result:
test AssertError: expected constructor to be called once but was called 0 times at Object.fail (node_modules\sinon\lib\sinon\assert.js:110:29) at failAssertion (node_modules\sinon\lib\sinon\assert.js:69:24) at Object.assert.(anonymous function) [as calledOnce] (node_modules\sinon\lib\sinon\assert.js:94:21) at Context.it (/test/classtest.spec.js:21:18)
Note: this issue seems to only happen for constructors. I can spy on methods inherited from the parent class without any issues.