4

I have the following function that uses fetch() to make an API call:

export async function fetchCars(dealershipId) {
  return request('path/to/endpoint/' + dealershipId)
    .then((response) => {
      if (response.ok === false) {
        return Promise.reject();
      }
      return response.json();
    })
    .then((cars) => {
      return parseMyCars(cars);
    });
}

I want to test when the call fails (specifically when return Promise.reject() is returned). I have the following Jest test right now:

(fetch as jest.Mock).mockImplementation(() =>
    Promise.resolve({ ok: false })
);
const result = await fetchCars(1);
expect(request).toHaveBeenCalledWith('/path/to/endpoint/1');
expect(result).toEqual(Promise.reject());

but I get a Failed: undefined message when running the test. I've tried using:

(fetch as jest.Mock).mockRejectedValue(() =>
  Promise.resolve({ ok: false })
);

but get a similar Failed: [Function anonymous] message.

What's the proper way to test for the rejected promise here?

Lloyd Banks
  • 35,740
  • 58
  • 156
  • 248
  • `const result = await fetchCars(1);` throws an error, because the promise rejects, so the test fails, the function call ends and the assertions aren't reached. `expect(result).toEqual(Promise.reject());` doesn't make sense anyway - the result of awaiting a rejected promise isn't a rejected promise, an error gets thrown. Also note testing errors is always tricky because you can accidently write code where the non-error path is a false positive. Per https://jestjs.io/docs/asynchronous you probably want to use `.rejects`. – jonrsharpe Dec 22 '21 at 00:08

2 Answers2

1

Your test is failing because it's throwing an exception. You need to catch that exception, there are many ways to do it, and using rejects helper is one of them:

it("should fail", async () => {
    (window.fetch as jest.Mock).mockResolvedValueOnce({
      ok: false,
    });
    await expect(fetchCars(1)).rejects.toEqual(/* error you are expecting*/);
});
lissettdm
  • 12,267
  • 1
  • 18
  • 39
-1

There is a couple of ways to deal with this correctly. I think the issue is that you are awaiting your promise.

If you plan to use await then you must await the expect:

const result = fetchCars(1);
await expect(result).toEqual(Promise.reject());
// ✅ Correct setup

or you can just return the un-awaited promise:

const result = fetchCars(1);
return expect(result).toEqual(Promise.reject());
// ✅ Correct setup

If you don't return or await the expect, then you might notice you get a false positive:

const result = fetchCars(1);
expect(result).toEqual(Promise.reject());
// ❌ False positive!

I've created a codesandbox example showing you how to mock the fetch function and how to correctly set up the test including the incorrect ways. Have a play around with the Tests tab at the top right.

Steve
  • 4,372
  • 26
  • 37