| name | react18-enzyme-to-rtl |
| description | Provides exact Enzyme → React Testing Library migration patterns for React 18 upgrades. Use this skill whenever Enzyme tests need to be rewritten - shallow, mount, wrapper.find(), wrapper.simulate(), wrapper.prop(), wrapper.state(), wrapper.instance(), Enzyme configure/Adapter calls, or any test file that imports from enzyme. This skill covers the full API mapping and the philosophy shift from implementation testing to behavior testing. Always read this skill before rewriting Enzyme tests - do not translate Enzyme APIs 1:1, that produces brittle RTL tests. |
React 18 Enzyme → RTL Migration
Enzyme has no React 18 adapter and no React 18 support path. All Enzyme tests must be rewritten using React Testing Library.
The Philosophy Shift (Read This First)
Enzyme tests implementation. RTL tests behavior.
expect(wrapper.state('count')).toBe(3);
expect(wrapper.instance().handleClick).toBeDefined();
expect(wrapper.find('Button').prop('disabled')).toBe(true);
expect(screen.getByText('Count: 3')).toBeInTheDocument();
expect(screen.getByRole('button', { name: /submit/i })).toBeDisabled();
This is not a 1:1 translation. Enzyme tests that verify internal state or instance methods don't have RTL equivalents - because RTL intentionally doesn't expose internals. Rewrite the test to assert the visible outcome instead.
API Map
For complete before/after code for each Enzyme API, read:
references/enzyme-api-map.md - full mapping: shallow, mount, find, simulate, prop, state, instance, configure
references/async-patterns.md - waitFor, findBy, act(), Apollo MockedProvider, loading states, error states
Core Rewrite Template
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MyComponent from './MyComponent';
describe('MyComponent', () => {
it('does the thing', async () => {
render(<MyComponent prop="value" />);
const button = screen.getByRole('button', { name: /submit/i });
await userEvent.setup().click(button);
expect(screen.getByText('Submitted!')).toBeInTheDocument();
});
});
RTL Query Priority (use in this order)
getByRole - matches accessible roles (button, textbox, heading, checkbox, etc.)
getByLabelText - form fields linked to labels
getByPlaceholderText - input placeholders
getByText - visible text content
getByDisplayValue - current value of input/select/textarea
getByAltText - image alt text
getByTitle - title attribute
getByTestId - data-testid attribute (last resort)
Prefer getByRole over getByTestId. It tests accessibility too.
Wrapping with Providers
const wrapper = mount(
<ApolloProvider client={client}>
<ThemeProvider theme={theme}>
<MyComponent />
</ThemeProvider>
</ApolloProvider>
);
import { render } from '@testing-library/react';
render(
<MockedProvider mocks={mocks} addTypename={false}>
<ThemeProvider theme={theme}>
<MyComponent />
</ThemeProvider>
</MockedProvider>
);