Migration guide

    Enzyme → React Testing Library, step by step.

    Enzyme doesn't work on React 18 and hasn't been maintained in years. React Testing Library is where the ecosystem went. This isn't a search-and-replace: RTL tests what a user sees, not your component internals, so most tests get rewritten rather than renamed.

    Refactyl doesn't migrate Enzyme to React Testing Library yet. This guide covers the manual path; the waitlist notifies you when the verified engine ships.

    Why this migration is hard to get right

    shallow() has no RTL equivalent

    Enzyme's shallow() renders a component one level deep, isolating it from children. RTL always full-renders with render(). Tests that relied on shallow to avoid child component side effects (network calls, context requirements, complex renders) must be refactored with mocked children or proper test context providers.

    wrapper.find('.my-class') tests implementation details

    Enzyme's selector API encourages finding elements by CSS class, component name, or prop value, all internal details a user never sees. RTL's query API (getByRole, getByText, getByLabelText) finds elements by what a user perceives. Every Enzyme query needs rewriting to a semantics-first query, which often means updating the component's markup to have proper ARIA roles or accessible labels.

    .simulate() doesn't fire real events

    Enzyme's .simulate('click') calls the onClick prop directly. It doesn't fire a real DOM event. RTL's fireEvent.click() and userEvent.click() fire real bubbling DOM events. Tests that relied on Enzyme's shortcut simulation may produce different results when real event propagation is involved.

    How to migrate manually

      1

      Install RTL, remove Enzyme

      Install @testing-library/react, @testing-library/jest-dom, @testing-library/user-event. Remove enzyme, enzyme-adapter-react-16/17/18, @types/enzyme. Remove enzyme setup from jest.config.js / setupFiles.

      2

      Add jest-dom matchers

      Add `import '@testing-library/jest-dom'` to your test setup file. This gives you .toBeInTheDocument(), .toHaveValue(), .toBeVisible(), the idiomatic RTL assertion set.

      3

      Replace shallow() and mount() with render()

      The RTL equivalent of both is render(). For tests that used shallow to isolate from children, add jest.mock() calls for the child components you want to stub. For tests that used mount().instance() to call methods directly, rewrite to trigger the behavior through user interaction.

      4

      Rewrite Enzyme queries to RTL queries

      Replace wrapper.find('button').first() → screen.getByRole('button'). Replace wrapper.find('[data-testid="x"]') → screen.getByTestId('x'). Replace wrapper.find(MyComponent) → consider what the user sees; if nothing, the test is testing implementation. Priority: getByRole > getByLabelText > getByText > getByTestId.

      5

      Replace simulate() with userEvent or fireEvent

      Replace wrapper.simulate('click') → await userEvent.click(element). Replace wrapper.simulate('change', { target: { value: 'x' } }) → await userEvent.type(element, 'x'). Use userEvent (async) for all user interactions; use fireEvent only when you need exact synthetic event control.

    What Refactyl's verified version will do

    Roadmap

    Refactyl doesn't run this migration yet. When it ships, the bar will be the same as every other Refactyl path: every file gated by a real jest / vitest (RTL is a testing helper, not a runner) run, repaired until clean, or clearly flagged with the reason. No unverified files ship.

    The public benchmark methodology is at refactyl.com/benchmark . The same dual-metric approach will apply here.

    Manual / DIY vs Refactyl (roadmap)

    This table describes what Refactyl's EnzymeReact Testing Library engine will do. It isn't live yet.

    ConcernManual / DIYRefactyl (roadmap)
    React 18+ compatibilityEnzyme: no official React 18 adapterRTL supports React 18 natively. Migration is required, not optional
    Query rewrite scopeEvery wrapper.find() needs manual rethinking, not just renamingPattern detection will identify automatable vs judgment-call rewrites, flagging the latter
    Event simulationManual .simulate() → userEvent audit across the test suiteWill convert each event type to the async userEvent pattern
    Test setup filesRemove enzyme-adapter config, add jest-dom setup manuallySetup migration will be handled as part of the batch

    FAQ

    Enzyme → React Testing Library migration: common questions

    Real questions engineers ask before migrating Enzyme to React Testing Library, answered honestly.

    On the roadmap

    Want Refactyl to do this for you?

    Join the waitlist and we'll notify you when the EnzymeReact Testing Library engine ships. The bar is the same as every other Refactyl path: every file gated by a real jest / vitest (RTL is a testing helper, not a runner) run before handoff.

    Join the waitlist →

    Refactyl doesn't migrate Enzyme to React Testing Library yet. No misleading trial, no fake demo.