DEV Community

Cover image for Why you should cleanup after render
Nicolas Amabile
Nicolas Amabile

Posted on

6 1

Why you should cleanup after render

I spent some time today debugging a simple jest test with react-testing-library. I run into some issues and I couldn't easily figure out what was going on.

The problem

For a very simple component I had:

  • Snapshot test
  • Some basic interaction tests that work correctly only if I run them separately πŸ˜’

I created this example to illustrate the idea:



const Google = ({ onSubmit }) => {
  const [text, setText] = useState('')
  return (
    <Fragment>
      <input
        data-testid='textbox'
        type='text'
        value={text}
        onChange={({ target: { value }}) => setText(value)} />

        <button
          data-testid='btn'
          onClick={() => {
            if (text) {
              onSubmit(text)
              setText('')
            }
        }}>
          Search
        </button>
    </Fragment>
  )
}


Enter fullscreen mode Exit fullscreen mode

And the tests:



import { render, fireEvent } from 'react-testing-library'

describe('Google tests', () => {
  test('It renders corectly', () => {
    const { container } = render(<Google />)
    expect(container.firstChild).toMatchSnapshot()
  })

  test('Search with empty value', () => {
    const onSubmit = jest.fn()
    const { container, getByTestId } = render(<Google onSubmit={onSubmit}/>)
    const button = getByTestId('btn')
    fireEvent.click(button)
    expect(onSubmit).not.toBeCalled()
  })

  test('Seach with valid value', () => {
    const onSubmit = jest.fn()
    const text = 'Example'
    const { container, getByTestId } = render(<Google onSubmit={onSubmit}/>)
    const textbox = getByTestId('textbox')
    fireEvent.change(textbox, { target: { value: text }})
    const button = getByTestId('btn')
    fireEvent.click(button)
    expect(onSubmit).toBeCalledWith(text)
  })
})



Enter fullscreen mode Exit fullscreen mode

If I run this, I get this error:

Clearly, I was sending a function for that particular test ('Search with valid value'). Typo maybe? πŸ€”
My first reaction was to add .only to the test and focus on that particular problem. Guess what, it worked πŸ˜’

I spent some time debugging it until I realize that the failing test was using the component instance I created for the first snapshot test (the one that doesn't have the click handler) 🀯
How the hell did that happen?

From the official documentation:
"Failing to call cleanup when you've called render could result in a memory leak and tests which are not "idempotent" (which can lead to difficult to debug errors in your tests)."

The solution

It was as simple as using cleanup from 'react-testing-library'.



import { render, fireEvent, cleanup } from 'react-testing-library'

describe('Google tests', () => {
  beforeEach(cleanup)
  ...
})


Enter fullscreen mode Exit fullscreen mode

Here you have a repl.it with the example.

Hopefully, this will save you some debugging time πŸ‘

Photo by karatara from Pexels

Top comments (1)

Collapse
 
cubiclebuddha profile image
Cubicle Buddha β€’

Thank you for sharing your example. This reminds me of when I realized the need of putting someMock.mockReset() in the beforeEach when you’re spying on something with Jest. Because if you don’t you might have false positives when calling expect(someMock).toHaveBeenCalled()

πŸ‘‹ Kindness is contagious

Please leave a ❀️ or a friendly comment on this post if you found it helpful!

Okay