user578895
user578895

Reputation:

Expect a jest test to resolve, but don't care about the value

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

Answers (4)

JHH
JHH

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

axiac
axiac

Reputation: 72226

Update, by a two years wiser version of me

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();
});

What is wrong with your code

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.

Older answer

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

user3637541
user3637541

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

geg
geg

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

Related Questions