ES2016 Class, Sinon Stub Constructor

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.

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);
  });
});

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;
    });
 });

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); 

It doesn’t work for me either. I managed a workaround that works for me, i use spy as well:

class FakeSchema {
  constructor(newCar) {
    this.constructorCallTest();
    this.name = newCar.name;
  }

  constructorCallTest() {
    mochaloggger.log('constructor was called');
  }

}

// spy that tracks the contsructor call
var fakeSchemaConstrSpy = sinon.spy(FakeCarSchema.prototype,'constructorCallTest');

Hope that was helpful

Read More:   Failed to load resource: net::ERR_CONTENT_LENGTH_MISMATCH

If you are in a browser environment, the following works too:

let constructorSpy = sinon.spy(window, 'ClassName');

For example this would work with Jasmine.

Mocha instead runs in Node environment, there is no window. The variable you’d be looking for is global


The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Similar Posts