React Testing Library Cleanup Vs. Enzyme

I've been using React Testing Library (RTL) at work after years of testing React with Enzyme, and I am enjoying it immensely.

I ran into a pattern that will work in Enzyme but will not work in RTL, though, because of how RTL handles cleaning up after itself vs Enzyme. This isn't necessarily obvious if you're not familiar with how these two libraries handle cleaning up renders after each test.

RTL automatically runs a function called cleanup (assuming the testing framework you are using supports afterEach, and because we use Jest, this is done automatically.) Cleanup unmounts any React component trees that were rendered in the test. See the API doc for more details.

Why does this matter? Well, first, this is generally behavior you want. Kent C. Dodds has an entire article about test isolation with React that touches on rendering in every test.

It also means that you can't render a component and then run a bunch of tests against it without rendering it again per-test: you can't write a lot of it or test blocks referencing that first render, because it will clean itself up after every test. This is something I have seen done in Enzyme before with mount, though.

The fact that Enzyme doesn't cleanup automatically after every test isn't explicitly documented, but I did find an issue from 2017 that confirms that it does not.

This means you can do something like this in Enzyme:

import { mount } from 'enzyme';

describe("MyComponent", () => {
  const component = mount(<MyComponent />);

  // component persists between it blocks!
  it("does something", () => {
    expect(component...) // your assertions here
  })

  it("does something else", () => {
	expect(component...) // your assertions here
  })
})

But this will not work in RTL:

import { render } from "testing-library/react"

describe("MyComponent", () => {
  const component = render(<MyComponent />);

  it("does something", () => {
    expect(component...) // your assertions here
  })

  it("does something else", () => {
	expect(component...) // this will fail!
  })
})

Instead, you would move the render inside every it block:

import { render } from "testing-library/react"

describe("MyComponent", () => {

  it("does something", () => {
    const component = render(<MyComponent />);
    expect(component...) // your assertions here
  })

  it("does something else", () => {
  	const component = render(<MyComponent />);
	expect(component...) // this will fail!
  })
})

This isn't necessarily common, but I ran into it when refactoring older Enzyme tests to use RTL, so I thought I would post this snippet!

Previous

Thoughts On Interviewing For Developer Roles in 2021

 
 
comments powered by Disqus