Spy on function and check that it has always been called with args - jestjs

I am migrating from Sinon and Mocha to Jest.
Following this link, you can see that there is the assert sinon.assert.alwaysCalledWith(spy, arg1, arg2, ...);, that doesn't check that a function was called at least one time with those args, but that it was called every time with those args.
How can I write an analogous thing in Jest?

Related

Mockito verify doesn't match multiple stub

It seems that, when I use thenReturn like this:
when(abc.call()).thenReturn(a).thenReturn(b),
I expect:
verify(abc, times(2)).call()
instead, the method seems only get called once, I am a little confused(my test work as expected, the mock seems return the value I expected), but for the invocation times, I don't know if I am getting the wrong result, or it's a expected behavior of the Mockito?
when() is mocking the abc.call() method which has to produce a certain return type. If the method is called once, it will return the value also once, so the stubbing for method invocation is done only once hence the verify only recognizes one call.
You need to customize your function so that the stub(abc.call()) gets called more than once.
You can follow this thread for implementing multiple stubs

Making assertions on Jest manual mocks

I'm having some trouble with manual Jest mocks and could use some help.
The file I am testing looks something like this:
import withTranslation from '../utils/withTranslation'
withTranslation('test')
I'm mocking a module in a test file like this.
import withTranslation from '../utils/withTranslation'
jest.mock('../utils/withTranslation')
// tests here
I have the manual mock at ../utils/__mocks__/withTranslation.js with the following code:
const impl = (...args) => {
console.log('in mock', args)
return args
}
export default impl
When the test runs, the mock is used and I can see the console log. So far so good.
However, I want to be able to make assertions on the usage of withTranslation when it is mocked. For example, expect(withTranslation).toHaveBeenCalledWith('test').
So, I change the manual mock to be a Jest mock function with the same implementation as before.
const impl = (...args) => {
console.log('in mock 1', args)
return args
}
// only difference is wrapping in jest.fn()
export default jest.fn(impl)
When the test runs now, a generic Jest mock function is used and I DO NOT see the console log, so my fake implementation is never called. Any ideas?
The code in my question is correct. The reason this was happening is because my test suite had a global beforeEach which was calling jest.resetMocks(). Hopefully this saves someone a few hours.
The function withTranslation in the actual module is already replaced with the mock before the test begins and this replacement is not done via reference. Hence when you assert the mock withTranslation the assertion fails because the mocked function is never called but rather the withTranslation method in the actual module is called.
Your console log still appears because as I said above the "real" module's function has already been replaced with the mock.
So import the actual withTranslation and assert it and it will resolve your problem.
Credit to this answer.

How does work Sinon.JS fake.yields?

I just started investigation of Sinon.JS and after some research I stuck with the following two methods and do not know how exactly they are working:
sinon.fake.yields(callback[, value1, ..., valueN]);
and
sinon.fake.yieldsAsync(callback[, value1, ..., valueN]);
It would be great if somebody explain (or even show some example) how they work and when should I use them. One more important question what is the difference between fake, stub and mock in common?
Thanks in advance!
The Sinon docs explain that yields() returns a fake that "expects the last argument to be a callback and will invoke it with the given arguments".
yieldsAsync() does the same thing but invokes the callback asynchronously.
Looking at the Sinon source code makes it clear exactly what this means:
Calling sinon.fake.yields(...) records the arguments passed and returns a function.
When the returned function is invoked it ignores all of its own arguments except the last one which it assumes is a callback. It then invokes that callback with the arguments it recorded from when it was created with yields():
import * as sinon from 'sinon';
const fake = sinon.fake.yields('arguments', 'passed', 'to', 'yields');
const callback = (...args) => {
console.log(args);
}
// logs the following to the console:
// [ 'arguments', 'passed', 'to', 'yields' ]
fake('every argument', 'except the last', 'is ignored', callback);
yieldsAsync() does exactly the same thing except that it invokes the callback asynchronously.
In Sinon, a spy "is a function that records arguments, return value, the value of this and exception thrown (if any) for all its calls". It just spies on the calls made to it. It can either wrap nothing or it can wrap and transparently pass through to an existing function.
A stub is a spy "with pre-programmed behavior". A stub lets you spy on the calls made to it and also lets you define how the function should behave (return value, exception thrown, etc.). If an existing function is wrapped in a stub the behavior defined by the stub is used instead of the function.
"fake was introduced with Sinon with v5. It simplifies and merges concepts from spies and stubs." It spies on the calls made to it like both spies and stubs, it can be created with or without behavior and it can also wrap an existing function.
A mock is a fake method "with pre-programmed behavior...as well as pre-programmed expectations". A mock lets you define how the function should behave and also how it is expected to be used. Calling verify() on a mock will fail if the mock was not used as expected.

Jest how to assert that function is not called

In Jest there are functions like tobeCalled or toBeCalledWith to check if a particular function is called.
Is there any way to check that a function is not called?
Just use not.
expect(mockFn).not.toHaveBeenCalled()
See the jest documentation
not did not work for me, throwing a Invalid Chai property: toHaveBeenCalled
But using toHaveBeenCalledTimes with zero does the trick:
expect(mock).toHaveBeenCalledTimes(0)
Recent versions of Jest (22.x and onwards) collect quite decent statistics of mock functions calls, just check out their docs.
The calls property shows you the number of calls, the arguments passed to the mock, the result returned out of it and whatnot. You can access it directly, as a property of mock (e.g. in a way how #Christian Bonzelet suggested in his answer):
// The function was called exactly once
expect(someMockFunction.mock.calls.length).toBe(1);
// The first arg of the first call to the function was 'first arg'
expect(someMockFunction.mock.calls[0][0]).toBe('first arg');
// The second arg of the first call to the function was 'second arg'
expect(someMockFunction.mock.calls[0][1]).toBe('second arg');
I personally prefer this way as it gives you more flexibility and keeps code cleaner in case if you test for different inputs that produce a different number of calls.
However, you can also use shorthand aliases for Jest's expect since recently (spy matchers aliases PR). I guess .toHaveBeenCalledTimes would suit fine here:
test('drinkEach drinks each drink', () => {
const drink = jest.fn();
drinkEach(drink, ['lemon', 'octopus']);
expect(drink).toHaveBeenCalledTimes(2); // or check for 0 if needed
});
In rare cases, you might even want to consider writing your own fixture that'd do the counting. It could be useful if you're heavy on conditioning or working with state, for example.
Hope this helps!
Please follow the documentation from jest:
https://jestjs.io/docs/en/mock-functions#mock-property
All mock functions have this special .mock property, which is where data about how the function has been called and what the function returned is kept. The .mock property also tracks the value of this for each call, so it is possible to inspect this as well: [...]
These mock members are very useful in tests to assert how these functions get called, instantiated, or what they returned:
// The function was called exactly once
expect(someMockFunction.mock.calls.length).toBe(1);
Or...
// The function was not called
expect(someMockFunction.mock.calls.length).toBe(0);

How to return Array of Objects using Powermock and mockito

I have a method which return array of object.
public IConfigurationElement[] getConfigurationElementsFor(String extensionPointId);
I am not sure how can I mock this call using mockito and powermock.
I have tried
mockConfigurationElements = (IConfigurationElement[]) Mockito.anyListOf( IConfigurationElement.class ).toArray();
but this is ending in ClassCastException.
Mocking (stubbing) calls with Mockito is done in a following way (for example):
Mockito.when(mockObject.getConfigurationElementsFor(Mockito.anyString()).thenReturn(new IConfigurationElement[]{})
or
Mockito.doReturn(new IConfigurationElement[]{}).when(mockObject).getConfigurationElementsFor(Mockito.anyString());
Mockito.anyListOf() is a use of a matcher. Matchers are passed instead of real arguments when stubbing meaning that the behavior is to be applied if the method is called with arguments satisfying those matchers.

Resources