Adam Tuttle

My Jest Mock Calls Are Missing Data. Now What?

Yesterday I had an altogether too familiar experience. I spent several hours debugging, and once I believed that the answer was beyond me, I started drafting an explanation and code samples that would eventually become a Stack Overflow question. After 20 minutes of explaining the problem to my hypothetical Stack Overflow helpers, the answer came to me.

I've said it before, I'll say it again. @StackOverflow is the worlds best rubber duck.

Spent 2+ hours debugging. Another 20 minutes drafting my question (6 paragraphs of explanation, a bunch of code examples) before I realized I was missing an "await" 😎😭

— 0xADAM (@AdamTuttle) June 2, 2021

I've already spoiled the solution above, but what was the problem, and how can I share that knowledge in a way to help others who might run into the same situation?

Wait, what? How can I know that the calls were made and also not see them in the fetch.mock.calls array?

Well, my mock looks like this:

fetch.mockResponse(async (req) => {
console.log(req.url);
if (req.url === '...') {
return JSON.stringify( /* ... */ );
}
});

As my test ran, I could see about half a dozen HTTP requests logged by the console.log statement. Ok, great, but...

const thingDoer = require('./thingDoer');
it('does the thing', () => {
thingDoer();
console.log(fetch.mock.calls);
expect(fetch).toHaveBeenCalledWith( /* ... */ );
});

How is it, then, that the console.log in the test shows only 1 call in the array?!

Well, maybe you've already guessed it from the spoiler in the tweet, but the answer was as simple as a missing await. Specifically, the thingDoer method is async and returns a promise.

Since I wasn't awaiting that promise, thingDoer returned early and I was running my console.log and expectations while it was still running. That explains why the log of fetch.mock.calls had less data than I could see in the individual logs for each request... they hadn't been made yet.

Making my test async and awaiting thingDoer solved it.

const thingDoer = require('./thingDoer');
it('does the thing', async () => {
await thingDoer();
expect(fetch).toHaveBeenCalledWith( /* ... */ );
});

Hopefully this helps someone else out there going nuts because things that they can see happening aren't in the list of things that happened. But let's be realistic. It'll be me referring to this article again in 9 months. 🤷‍♂️