Why does Jest's toStrictEqual fail to match JSON responses made using the fetch API?

2 min read 05-10-2024
Why does Jest's toStrictEqual fail to match JSON responses made using the fetch API?


Why Jest's toStrictEqual Fails to Match JSON Responses from fetch

Testing your application's interactions with external APIs is crucial. Jest's toStrictEqual matcher is often the go-to for verifying data equality, but a common pitfall arises when comparing JSON responses from the fetch API.

Let's illustrate this problem with a simple example.

Scenario:

You have a function that retrieves data from an API using fetch and expects a JSON response:

async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return data;
}

Now, you want to write a Jest test to ensure the function returns the expected JSON data:

test('fetches data successfully', async () => {
  const expectedData = {
    name: 'John Doe',
    age: 30,
  };

  const data = await fetchData();
  expect(data).toStrictEqual(expectedData);
});

You might find that this test fails despite data seeming to hold the correct data.

The Issue:

The problem stems from the fact that fetch returns a Response object, and response.json() returns a Promise that resolves to the parsed JSON object. While your test is expecting an object, what it actually receives is a Promise that will eventually resolve to the object. This leads to the comparison between the Promise and the expected object, which always fails because they are not strictly equal.

Solution:

The key to resolving this is to await the response.json() Promise before comparing the data:

test('fetches data successfully', async () => {
  const expectedData = {
    name: 'John Doe',
    age: 30,
  };

  const data = await fetchData();
  expect(data).toStrictEqual(expectedData);
});

Explanation:

By adding await before response.json(), we are explicitly waiting for the Promise to resolve and retrieve the actual JSON object before making the comparison. This allows toStrictEqual to perform the deep equality check correctly, ensuring that the received data matches the expected structure.

Additional Notes:

  • For situations where you want to test the entire Response object (status code, headers, etc.), you can directly compare the Response object itself instead of just the parsed JSON data.

  • While toStrictEqual offers a deep comparison, remember that you can also use other Jest matchers like toEqual or toMatchObject depending on your specific needs and the level of detail required in your test.

Key Takeaway:

Always ensure that your test is comparing the actual value you are expecting, not a Promise that resolves to that value. By understanding the nuances of fetch and response.json(), you can write accurate and reliable tests for your API interactions.