How I Fixed: TypeError: Invalid attempt to destructure non-iterable instance

This morning I hit upon a really annoying problem whilst trying to write a basic test for a React component.

The internals of the component are not important to the issue I was facing.

Here’s the outcome:

What frustrated me was that the first it block was working. And then the second block would not work.

I could xit the first it, and then the second it would work / pass. But together, they would not play nicely.

The reason for this is something that’s caught me out several times previously, but something I keep forgetting about. Here we go:

The issue is the use of jest.resetAllMocks();.

Here’s what it should be:

In case you missed it, switch resetAllMocks for clearAllMocks.

The reasoning, in my case is that I had declared a .mockImplementation elsewhere in my test, and a call to resetAllMocks wipes out that mock implementation.

At least, that’s my understanding of it.

For more details see the docs for the difference between resetAllMocks and clearAllMocks.

Testing React withRouter

One area I’ve always found tricky when writing tests for React is where Higher Order Components are involved. I’ve found this complicates the test setup process. There are ways around this, which may or may not be possible depending on many factors. Sometimes you work on third party code that won’t accept ‘dramatic’ refactors just to scratch your own testing itches.

One example of where this problem might occur (particularly if you don’t read the docs!!) is with React Router, specifically when using withRouter.

In this example I have MyComponent which wants to history.push('/some/location') when the user completes some action.

I’d like to test that this process takes place as expected.

Here was my first attempt. This way works, but there are some drawbacks:

This works.

There are a couple of drawbacks to this:

  • It involves a couple of extra imports.
  • Behind the scenes, withRouter is still used (afaik) but by wrapping in another Router, we can override the history prop.

As this particular approach is so common, React Router gives us an alternative / preferable way to test this workflowWrappedComponent.

The necessary actions to ‘run’ this test are unchanged. However, there are fewer lines as we can make use of the existing constructs provided by React Router to aid our testing workflow.

This may have been extremely obvious to you.

I can’t remember if WrappedComponent has always been available and I have overlooked it, or it is something new since I last had to do testing with a project using React Router.

Either way, it’s time I refreshed my knowledge of the documentation. And hopefully this helps someone else when testing withRouter at some point in the future.