I want to test a function which just return a function with some values and an anonymous function as parameters. How to test the match for the anonymous function using toHaveBeenCalledWith in jest?
function toBeTested( id, values) {
return xyz(id, values, () => {
return {
type: 'foo',
payload: {
text: values.text
}
}
})
}
In my test
describe('test for toBeTested', () => {
it('should call xyz with params', () => {
const id = 123;
const values = {
text: 'Hello world',
};
xyz = jest.fn();
toBeTested(id, values);
expect(xyz).toHaveBeenCalledWith(id, values, () => {
return {
type: 'foo',
payload: {
text: values.text,
}
}
});
})
})
Test error report
expect(jest.fn()).toHaveBeenCalledWith(expected)
Expected mock function to have been called with:
[123, {text: 'Hello world'}, [Function anonymous]]
But it was called with:
[123, {text: 'Hello world'}, [Function anonymous]]
at Object.it.only (src/actions/tests/xyz.test.js:30:43)
at new Promise (<anonymous>)
at Promise.resolve.then.el (node_modules/p-map/index.js:46:16)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
I had the same problem and I found this question which the selected answer didn't help me. So I decided to write an answer with what solved my problem hoping it can help other people.
TL;DR: use expect.any(Function) as below:
expect(xyz).toHaveBeenCalledWith(
id,
values,
expect.any(Function)
);
Full answer:
The selected answer is indeed an alternative for situations in which you can receive a callback, however there are other scenarios in which the anonymous function shouldn't be exposed or even provided by the caller function.
Example:
import { exec } from 'child_process';
export const runScript = (data: string): Promise<string> => {
return new Promise((resolve, reject) => {
exec(`a script to be called with this data ${data}`, (error) => {
if (error) {
// handle error
// ...
reject();
} else {
// do something
// ...
resolve('result');
}
});
});
};
in the example above I don't want to receive the error handling function as an callback since that logic is really intrinsic to the runScript function and it shouldn't be implemented or provided by an external caller function. The real function would have more logic in it, but I believe sharing its structure already gives an idea that those scenarios exist.
NOTE: the // ... parts in my code have more logic, calling external functions which I'm able to mock and assert what's being passed to them, so I can test it properly. I just removed it for the sake of simplifying it
Anyway, here's how I managed to test it:
expect(execMock).toHaveBeenCalledWith(
'...',
expect.any(Function),
);
In the your case @manikandan-j, it would be:
it('should call xyz with params', () => {
const id = 123;
const values = {
text: 'Hello world',
};
xyz = jest.fn();
toBeTested(id, values);
expect(xyz).toHaveBeenCalledWith(
id,
values,
expect.any(Function)
);
});
});
Also, if you use expect.any(Function) (as I'm using) and you want to test the content of your anonymous function
() => {
return {
type: 'foo',
payload: {
text: values.text
}
}
you would test the result of toBeTested that would be impacted by those values. Something like the below:
const result = toBeTested(id, values);
expect(xyz).toHaveBeenCalledWith(
id,
values,
expect.any(Function)
);
expect(result).toBe(...);
Anyway, I hope it helps people testing functions that one of its arguments is an anonymous function that cannot be received as an argument.
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