0

I want to write a unit test that covers the line in a constructor that calls super. How can I mock super so that I can verify it was called?

I found related content like mocking other functions on the super class and a solution that only works for ES6 code transpiled by Babel but nothing seems to address mocking the .super call in native ES6.

Here is a contrived example from https://jsfiddle.net/wuzkhfcx/16/ showing all my various attempts failing:

class Vehicle {
  constructor(make, model) {
    this.make = make;
    this.model = model;
  }
}

class Car extends Vehicle {
  constructor(make, model, doorCount) {
    super(make, model);
    this.doorCount = doorCount;
  }
}

function testCarConstructor() {
  console.log('Running test: testCarConstructor');
  let wereAnyMocksUsed = false;
  const mock = () => { wereAnyMocksUsed = true; }

  Vehicle.constructor = mock;
  Vehicle.prototype.constructor = mock;
  Car.prototype.super = mock;
  Car.super = mock;
  new Car('Nissan', 'Pulsar', 4);

  console.log('Finished test. Were any mocks used?', wereAnyMocksUsed);

}

testCarConstructor();

EDIT: This is only example code, not the actual code I am working on. I think that the shorter example can keep it simple without needing backstory on the names and inheritance structure of the code I'm actually working on.

Trindaz
  • 17,029
  • 21
  • 82
  • 111
  • You can't mock `super` or constructor function. `Vehicle.prototype.constructor = mock` won't work. This test is synthetic and thus leads to nowhere. Usually classes belong to different files. They should be mocked on module level. I see no real reason to mock parent class here. – Estus Flask Mar 18 '18 at 20:27
  • You can use any library that provides `spy` capability. You can intercept the call with a spy. – Randy Casburn Mar 18 '18 at 20:47
  • @RandyCasburn could you post some sample code? – Trindaz Mar 18 '18 at 22:13
  • @estus are you saying that the only way to mock `super` calls in ES6 is to use separate files for every class? I assumed that ES6 would not have a special constraint on file usage in order to be able to write testable code. – Trindaz Mar 18 '18 at 22:15
  • ES6 doesn't have this constraint. JS has, and this is not specific to ES6 classes. Modules are just boundaries where this becomes possible. And more importantly, the thing you're trying to do is likely totally unnecessary for writing testable code. What exactly is this mock for? At this point *keep it simple without needing backstory on the names* is not a good option because the answer depends on actual case. For the code you've posted, the answer would be "It's impossible and unneeded". – Estus Flask Mar 18 '18 at 23:08
  • 1
    @Trindaz - here is a repl to show using `sinon.stub()` to intercept the Car constructor. Validate the inputs, and call the actual constructor. Then validate the prototype is an instanceof Vehicle and validate the properties fall through the inheritance chain. This proves the `super()` function is excited. https://repl.it/@randycasburn/StubConstructorWithExtends – Randy Casburn Mar 19 '18 at 00:16
  • 1
    @Trindaz - one other note, in case you are unaware. The expects/asserts throw, so upon failure the terminal would show and exception. Make an assert fail and you'll see. – Randy Casburn Mar 19 '18 at 00:18
  • @RandyCasburn Thanks! `__proto__` assignment works great https://jsfiddle.net/up1rop3f/7/ – Trindaz Mar 19 '18 at 01:10
  • Awesome. Glad to help. You should know that they have deprecated __proto__. But by the time it is no longer usable we'll have better access to the inheritance chain to test. – Randy Casburn Mar 19 '18 at 01:17

0 Answers0