How to preserve working manual mocks in Jest and the new resetMocks default in CRA?

Viewed 162

The resetMocks: true default in create-react-app (CRA) version 4.0.0 (see release notes) breaks manual mocks that have mocks inside them. In that situation, Jest will throw the error: mockConstructor(...): Nothing was returned from render.

This GitHub issue for CRA (dated Oct 2020) contains a discussion of the pros and cons of the new resetMocks default, but the only solution mentioned there is to override the new default.

I'm looking for a solution that preserves working manual mocks and has the benefits of the new default, such as cleaning mock state between tests.

Below are code snippets that reproduce the broken manual mock issue. I also put that same code this repo to make it easier to dive in and tweak things on your machine.

// src/App.js
import SomeComponent from './SomeComponent'

const App = () => (
  <div className="App">
    <SomeComponent />
  </div>
)

export default App
// src/SomeComponent.js
const SomeComponent = () => <p>original SomeComponent</p>

export default SomeComponent
// src/__mocks__/SomeComponent.js
const implementation = () => <p>mocked SomeComponent</p>
const SomeComponent = jest.fn().mockImplementation(implementation)
export default SomeComponent
// src/App.test.js
import { render, screen } from '@testing-library/react'

import App from './App'
import SomeComponent from './SomeComponent'

jest.mock('./SomeComponent')

beforeEach(() => {
  SomeComponent.mockClear() // Ensures that `calledTimes` is reset
})

it('should contain mocked mocked component', () => {
  render(<App />)
  screen.getByText(/mocked SomeComponent/i)
})

it('should have correct calledTimes', () => {
  render(<App />)
  screen.getByText(/mocked SomeComponent/i)
  expect(SomeComponent)
    .toHaveBeenCalledTimes(1)
})
0 Answers
Related