I'm trying to test an application but jest.spyOn is make me crazy.
I'm working on node v8.9.4 and jest v22.2.2
I have extracted this code:
// my-module.js
class MySingletonModule {
constructor() {
this.foo = 'bar';
}
myPromise() {
return new Promise((resolve, reject) => resolve(this.foo));
}
}
module.exports = new MySingletonModule();
// promise.test.js
const singleton = require('./my-module');
describe('Module test-suite', () => {
let spy;
beforeAll(async () => {
spy = jest.fn();
spy = jest.spyOn(singleton, 'myPromise');
});
beforeEach(() => spy.mockReset());
test('Check bar', () => {
return singleton.myPromise().then((bar) => {
expect(bar).toEqual('bar');
});
});
test('Check called times', () => {
singleton.myPromise();
expect(spy).toHaveBeenCalledTimes(1);
});
afterAll(() => {
jest.restoreAllMocks();
});
});
The Check bar
test is failing because the myPromise
method doesn't return a promise:
If I comment the spy = jest.spyOn(singleton, 'myPromise');
the test works.. but obviously the other test doesn't works..
I would expect that all the tests work with spyOn
, because reading the docs is wrote:
Note: By default, jest.spyOn also calls the spied method.
I'm missing something?
Thanks for the help
Here is working snippet without Jasmine:
describe('Module test-suite', () => {
let spy;
beforeAll(() => { // get rid of async
spy = jest.fn();
spy = jest.spyOn(singleton, 'myPromise');
});
afterEach(() => spy.mockRestore()); // main difference is here
test('Check bar', () => {
return singleton.myPromise().then((bar) => {
expect(bar).toEqual('bar');
});
});
test('Check called times', () => {
singleton.myPromise();
expect(spy).toHaveBeenCalledTimes(1);
});
afterAll(() => {
jest.restoreAllMocks();
});
});
I think it's better to use mockRestore
instead of mockReset
, because as I understand from jest docs mockReset
hardly clears all information about spy and spying object. And mockRestore
just clears some temp data such as number of called times.
Why is using afterEach
instead of beforeEach
important - I have no clue :(
Also I removed async
because tests failed with it.
I can't see any mention of this in the documentation but it seems like jest allows you to use a lot of Jasmine's functionality / syntax, including .and.callThrough
:
beforeEach(() => {
spyOn(singleton, 'myPromise').and.callThrough();
};
test('Check bar', async () => {
const bar = await singleton.myPromise();
expect(bar).toEqual('bar');
});
test('Check called times', () => {
singleton.myPromise();
expect(singleton.myPromise.calls.count()).toBe(1);
});
Here are the jasmine spy docs: https://jasmine.github.io/2.0/introduction.html#section-Spies
If you want to stick to the documented jest.spyOn
API then you can instead set the spy inside of the test that uses it, so that it doesn't affect the other:
test('Check bar', async () => {
const bar = await singleton.myPromise();
expect(bar).toEqual('bar');
});
test('Check called times', () => {
const spy = jest.spyOn(singleton, 'myPromise');
singleton.myPromise();
expect(spy).toHaveBeenCalledTimes(1);
});
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