I have a class Qux
that inherits from class Baa
and I would like to mock Baa
while testing Qux
. That works in principle if I don't try to spy on the mock BaaMock
.
If I would like to spy on the mocked class, the doc says that I should use a jest.fn() instead of the class. However, that does not seem to work correctly: some of the methods of the inheriting class Qux
are lost.
Some example code (also available at https://github.com/stefaneidelloth/testDemoES6Jest) :
Super class Baa (/src/baa.js):
import Foo from './foo.js';
export default class Baa extends Foo {
constructor(name){
super(name);
}
baaMethod(){
return 'baaMethod';
}
overridableMethod() {
return 'baa';
}
}
Inheriting class Qux (/src/qux.js):
import Baa from './baa.js';
export default class Qux extends Baa {
constructor(name){
super(name);
}
quxMethod(){
return 'quxMethod';
}
overridableMethod() {
return 'qux';
}
}
A. Test for inheriting class Qux without a possibility to spy (/test/qux.test.js):
jest.mock('./../src/baa.js', () => {
return class BaaMock {
constructor(name){
this.name = name;
}
baaMethod(){
return 'baaMockedMethod';
}
}
});
import Qux from './../src/qux.js';
describe('Qux', function(){
var sut;
beforeEach(function(){
sut = new Qux('qux');
});
it('quxMethod', function(){
expect(sut.quxMethod()).toEqual('quxMethod');
});
it('baaMethod', function(){
expect(sut.baaMethod()).toEqual('baaMockedMethod');
});
it('overridableMethod', function(){
expect(sut.overridableMethod()).toEqual('qux');
});
});
B. In order to be able to spy on the mocked class, I tried to replace the class with a mock function (also see https://jestjs.io/docs/en/es6-class-mocks):
import Baa from './../src/baa.js';
jest.mock('./../src/baa.js',
function(){
return jest.fn().mockImplementation(
function(name){
return {
name:name,
baaMethod: () =>{ return 'baaMockedMethod';}
};
}
);
}
);
import Qux from './../src/qux.js';
describe('Qux', function(){
var sut;
beforeEach(function(){
//Baa.mockClear();
sut = new Qux('qux');
//expect(Baa).toHaveBeenCalledTimes(1);
});
it('quxMethod', function(){
expect(sut.quxMethod()).toEqual('quxMethod');
});
it('baaMethod', function(){
expect(sut.baaMethod()).toEqual('baaMockedMethod');
});
it('overridableMethod', function(){
expect(sut.overridableMethod()).toEqual('qux');
});
});
As a result, the test fails with following errors:
FAIL test/qux.test.js
Qux
× quxMethod (7ms)
√ baaMethod (4ms)
× overridableMethod (2ms)
● Qux › quxMethod
TypeError: sut.quxMethod is not a function
28 |
29 | it('quxMethod', function(){
> 30 | expect(sut.quxMethod()).toEqual('quxMethod');
| ^
31 | });
32 |
33 | it('baaMethod', function(){
at Object.quxMethod (test/qux.test.js:30:14)
● Qux › overridableMethod
TypeError: sut.overridableMethod is not a function
36 |
37 | it('overridableMethod', function(){
> 38 | expect(sut.overridableMethod()).toEqual('qux');
| ^
39 | });
40 |
41 | });
at Object.overridableMethod (test/qux.test.js:38:14)
I would expect my instance sut
of Qux
to still contain the methods quxMethod
and overridableMethod
that are defined by the class Qux.
=> Is this a bug of jest?
=> If not, why should do I need to implement all methods of Qux in the mock for Baa !!???
=> How do I need to adapt my example code B do successfully mock the class Baa, so that Qux is still able to inherit from it?
Jest can be used to mock ES6 classes that are imported into files you want to test. ES6 classes are constructor functions with some syntactic sugar. Therefore, any mock for an ES6 class must be a function or an actual ES6 class (which is, again, another function). So you can mock them using mock functions.
To spy on an exported function in jest, you need to import all named exports and provide that object to the jest. spyOn function. That would look like this: import * as moduleApi from '@module/api'; // Somewhere in your test case or test suite jest.
To mock a TypeScript interface with Jest, we just need to create objects that match the shape of the interface. The mocked function takes 2 numbers as arguments and returns a number, and we have the same signature and return type in the mocked function. So no error will be raised.
I believe you should not do that way. I see few strong reasons avoiding such an approach:
Summarizing all above I propose you avoid mocking super class at any cost.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With