Reputation:
Let's say I have the following fn that I want to test:
const foo = async () => {}
This resolves of course, but how do I test that with Jest?
it('resolves', async () => {
expect(await foo()).???
});
All of the examples I can find require values, e.g. expect(await foo()).resolves.toBe(42)
Upvotes: 24
Views: 18092
Reputation: 9295
I had this problem as well, and the ugly workaround I found was to assert negatively on a value I know wasn't ever going to be resolved, such as
await expect(somePromise).resolves.not.toBe({});
This works since toBe
uses strict equality, and a newly created empty object is not strictly equal to any other object, meaning this assertion will pass as long as somePromise
resolves with anything.
At first I intended to use a unique symbol, but {}
works just as well.
Upvotes: 0
Reputation: 72226
The property .resolves
of an expectation object created by expect()
is also an expectation object that has the same properties (the matchers) as a regular expectation object. The only difference is that it expects the actual value to be a Promise
and the matchers apply to the resolved value, not to the promise.
If the promise returned by the function resolves it means that it does not throw (if it throws then it is rejected, not resolved).
Let's express this expectation in Jest code:
it('resolves', async () => {
await expect(foo()).resolves.not.toThrow();
});
You have tried:
expect(await foo()).resolves.toBe(42)
It doesn't work this way because the result of await foo()
is not a Promise
but the resolved value of the Promise
returned by foo()
(assuming it resolves).
.resolves.toBe()
expects a Promise
, Jest complains and the test fails.
When await
is in front of the expect()
, foo()
returns a Promise
, expect()
wraps it into a object whose .resolves.toBe...()
returns another Promise
and await
awaits for it.
The general rule is: if you put await
inside the call to expect()
then you cannot use .resolves
or .rejects
because the value that expect()
receives is not a Promise
.
In order to use .resolves
or .rejects
, the await
keyword should stay in front of the expect()
call.
Alternatively you can return
the Promise
instead of await
-ing for it.
Read more about .resolves
and .rejects
.
If you know that foo()
always resolves to a value then you can use .toBeDefined()
:
it('resolves', async () => {
await expect(foo()).resolves.toBeDefined();
});
This doesn't work if foo()
completes using return undefined
or return
(without a value) or it doesn't use return
at all.
In this case you cannot use .resolves
but you can simply return the Promise
returned by foo()
and Jest takes care of the rest:
it('resolves', () => {
return foo();
});
Upvotes: 46
Reputation: 693
You can also just not use expect here:
it('resolves', async () => {
await foo();
});
Should foo throw, it makes the test fail anyways. The output is a little bit different on failure, but very readable and understandable, too.
I prefer this way, as imo it is short and clear.
Upvotes: 0
Reputation: 4785
I don't think jest natively supports this. However, the jest-extended library (community managed extensions) does with #toResolve()
await expect(foo()).toResolve()
Jest devs discuss the request here and refer us to jest-extended
Upvotes: 4