I'm trying to test a function in a class-based entity and trying to spy on another function that is being called inside the one I'm testing. But even though the child function is being called once, Jest fails to spy on it and says it was called 0 times.
Let's say this is my class:
class Example {
function1() {
const data = this.function2();
return data;
}
function2() {
...some code
}
}
So to test function1, I'm doing this:
describe('ExampleComponent', () => {
beforeEach(() => {
client = new Example();
});
it('should call function2 once', async() => {
const callFunction1 = client.function1();
const function2Spy = jest.spyOn(client, 'function2');
expect(function2Spy).toHaveBeenCalledTimes(1);
});
});
What am I missing here?
You are calling function first then spying on another function.
Try spying before function call
describe('ExampleComponent', () => {
beforeEach(() => {
client = new Example();
});
it('should call function2 once', async() => {
const function2Spy = jest.spyOn(client, 'function2');
client.function1();
expect(function2Spy).toHaveBeenCalledTimes(1);
});
});
Related
I'm following this thread. Mock a function called by a tested function of the same file with jest
functions.js
export const a = (x) => { a very complicated function };
export const b = (x) => exports.a(x+1);
functions.test.js
import * as functions from './functions';
describe('b', () => {
test('calling b calls a with x+1', () => {
functions.a = jest.fn();
functions.b(1);
expect(functions.a).toHaveBeenCalledWith(2);
});
});
It works for the most part, except that if I have additional unit test after describe(b), that required the original implementation of a(), it will still be treated as mock function, like let's say I want to unit test a(), it won't work because it is an empty function now. e.g
describe('c', () => {
test('unit testing a will call something 3 times', () => {
functions.a()
expect(whatever.get).toHaveBeenCalledWith(3);
});
});
any way to fix this?
Note:
I have tried the following, but it does not work
beforeEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
});
afterEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
});
The only way I can make it work is this, but this seems like really hacky?
const originalA = functions.a.bind({});
afterEach(() => {
functions.a = originalA;
});
Have you tried using spyOn? It doesn't replace your implementation just chekcing what is happening with that function.
import * as functions from "../functions";
describe("b", () => {
test("calling b calls a with x+1", () => {
const functionASpy = jest.spyOn(functions, 'a');
functions.b(1);
expect(functionASpy).toHaveBeenCalledWith(2);
});
});
I am trying to test the loading of a player in my main js file. It just created a new instance of an IVSPlayer class and then calls init() on it.
MAIN.js
const ivsPlayer = new IVSPlayer({
id: VIDEO_PLAYER_ID,
config: VIDEO_JS_CONFIG,
ivsTech: win.registerIVSTech,
});
ivsPlayer.init();
player = ivsPlayer.player;
I am trying to mock the implementation below
MAIN.test.js
import IVSPlayer from './ivs-player';
it('should load the player', async () => {
const mockInit = () => jest.fn();
jest.mock('./ivs-player', () => {
return {
init: mockInit,
};
});
await createPlayers();
expect(?????).toHaveBeenCalled();
});
What do I put in for the expect to listen to since I mocked the ivs-player
I think your mocking is wrong. Try this (mock on the prototype)
it('should load the player', async () => {
IVSPlayer.prototype.init = jest.fn().mockImplementation(() => {
return {
init: jest.fn(),
};
});
// execute code that causes the init function to run
expect(IVSPlayer.prototype.init).toHaveBeenCalled();
});
Alternatively, you can try this
import { IVSPlayer } from './ivs-player';
jest.mock('./ivs-player'); // Automatic mock of the file
it('should load the player', async () => {
// execute code that causes the init function to run
const mockInit = IVSPlayer.mock.instances[0].init;
expect(mockInit).toHaveBeenCalled();
});
You can read more on class mocks here.
I'm trying to test whether an async function (fire and forget) gets called.
Content.js
export async function fireAndForgetFunction() {
...
}
export async function getData() {
...
fireAndForgetFunction()
return true;
}
I would like to test if fireAndForgetFunction has been called more than once.
Current test
import * as ContentFetch from '../Content';
const { getData } = ContentFetch;
const { fireAndForgetFunction } = ContentFetch;
it('test',async () => {
const spy = jest.spyOn(ContentFetch, 'fireAndForgetFunction');
await getData();
expect(spy).toHaveBeenCalled();
})
The test result to an error saying
Expected number of calls: >= 1
Received number of calls: 0
How could I do this test?
If you don't want to await for fireAndForgetFunction in getData(), which I assume is the case, then providing a mock implementation of fireAndForgetFunction when creating the spy is your best option:
it('test', (done) => {
const spy = jest.spyOn(ContentFetch, 'fireAndForgetFunction')
.mockImplementation(() => {
expect(spy).toHaveBeenCalled();
done();
})
getData();
})
I'm trying to mock one specific function when using module.exports. How could I test the inner function B?
In my worker.js
module.exports = function () {
this.funcA = funcA
this.funcB = funcB
}
funcA () {
funcB()
}
funcB() {...}
In my worker-test.js
const Worker = require('./worker')
test('test functionB', () => {...})
test('test functionA', () => {
const work = new Worker()
work.funcB = jest.fn() //mock funcB
work.funcA //run funcA
expect(work.funcB).toHaveBeenCalledTimes(1) //Error
})
I'm new to jest. Is there any good way to mock function in this case?
There isn't a way to mock funcB the way the code is currently written since funcA calls funcB directly.
The easiest way to fix it is to note that worker.js returns a constructor function and funcA and funcB are almost prototype methods...
...if you make them prototype methods then funcB can be mocked:
worker.js
class Worker {
funcA() {
this.funcB();
}
funcB() {
throw new Error('should not make it here');
}
}
module.exports = Worker;
worker.test.js
const Worker = require('./worker');
test('test functionB', () => { /* ... */ })
test('test functionA', () => {
const spy = jest.spyOn(Worker.prototype, 'funcB'); // <= spy on funcB
spy.mockImplementation(() => {}); // <= mock funcB
const work = new Worker();
work.funcA(); // <= call funcA
expect(spy).toHaveBeenCalledTimes(1); // Success!
spy.mockRestore(); // <= restore funcB
})
I know this is an old question but I thought I would chime in as I was searching for a way to do this as well and have discovered it is in fact possible.
Rather than calling the javascript function as above, you'll need to give it the scope of this to ensure that when you mock funcB, funcA calls the mocked version rather than just the function itself.
This means worker.js becomes
module.exports = function () {
this.funcA = funcA
this.funcB = funcB
}
funcA () {
this.funcB()
}
funcB() {/* Your impl */}
And worker.test.js can remain, as before:
const Worker = require('./worker')
test('test functionB', () => {...})
test('test functionA', () => {
// You could even just have: const work = require('./worker')
const work = new Worker()
work.funcB = jest.fn() //mock funcB
work.funcA() //run funcA
expect(work.funcB).toHaveBeenCalledTimes(1)
})
I have a function that calls another function
const getArtist = (id) => {
// builds params for other function
return otherFuntion(params);
}
I want to verify that when I call getArtist(someValue), otherFunction gets called with the right arguments.
How can I accomplish that with jest ?
describe('getArtist function', () => {
it('should call otherFunction with the right params', () => {
// how can I get a handle on the mock of otherFunction to see
// if it was called correctly ?
});
});
You could use proxyquire to mock out the imported function at compile time if it's a public function. If it's a private function then you definitely don't want to mock it out.
You should probably just test the return value of otherFuntion instead.
So you are really calling the function otherFuntion(params) so I would rather check if return of your getArtist functions gives the same results as otherFunction called with right params.
describe('getArtist function', () => {
it('should call otherFunction with the right params', () => {
expect(getArtist(id)).toBe(otherFunction(params));
});
});
Or create special function for generate params and test it separatly. Like prepareArtistParams and use it inside:
const getArtist = (id) => {
const params = prepareArtistParams(id);
return otherFuntion(params);
}
describe('otherFuntion function', () => {
it('should create right params', () => {
expect(prepareArtistParams(id)).toBe(params);
});
});