You need to understand the mechanics behind Typescript and spying.
Typescript first ...
I ignore extra partners in class Parent() .
Typescript uses prototype inheritance behind the curtain. Thus, the prototype will copy the reference properties from the "base class" into the new class. This is what the for loop does in __extends() .
This is ES5 code, your Typescript is translated into:
var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var Parent = (function () { function Parent() { } Parent.prototype.buyFood = function () {
You can translate Typescript using the Typescript playground .
Your super expression calls the buyFood() method of the parent class, not the "inherited" Husband method.
See line
_super.prototype.buyFood.call(this);
and follow the instructions of _super .
Now Jasmine spies ...
The spy will replace the named function of the passed object with the spy function, which will act as a proxy. This proxy server can now track calls and, depending on the programmed behavior, control whether to call the original function, fake, return a value or do nothing (by default).
A very simplified spyOn() might look like this:
function spyOn(obj, fn) { var origFn = obj[fn], spy = function() { spy.calls.push(arguments); }; spy.calls = []; obj[fn] = spy; }
the actual spy method is much more complicated.
Your line
spyOn(husband, 'buyFood');
will actually replace the method in the Husband instance with a spy. But since the code calls the base class reference (the parent prototype), this is not the same function that you just replaced.
Decision
You must either call this method
class Husband extends Parent { makeDinner() {
... or spy on the original prototype ( super ):
it('Should make a good dinner', () => { spyOn(Parent.prototype, 'buyFood'); husband.makeDinner(); expect(Parent.prototype.buyFood).toHaveBeenCalled(); }