react18-enzyme-to-rtl について
React チームが Enzyme テストを React Testing Library(RTL)で書き換えるための移行スキルです。コンポーネント内部ではなく画面上の動作を検証し、API と非同期パターンの対応を示します。
主な機能
- 01Enzyme テストを RTL に書き換え
- 02内部ではなく表示動作をテスト
- 03一般的な Enzyme API と RTL の対応
- 04非同期クエリと状態のテスト
- 05アクセシブルな RTL クエリを優先
活用シーン
- 01React 18 のコードベースで Enzyme テストを置換
- 02状態やインスタンスのアサーションを画面結果に変更
- 03ローディング状態とエラー状態を非同期でテスト
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ github/ awesome-copilot --skill react18-enzyme-to-rtlインストール後、Claude Code で/react18-enzyme-to-rtlを入力して読み込まれたか確認します。
同梱ファイルreferences/async-patterns.mdreferences/enzyme-api-map.md
詳細
React 18 Enzyme → RTL への移行
Enzyme には React 18 アダプターがなく、React 18 をサポートする方法もありません。すべての Enzyme テストを React Testing Library を使って書き直す必要があります。
考え方の転換(まずお読みください)
Enzyme のテストは実装をテストします。RTL のテストは動作をテストします。
// Enzyme: tests that the component has the right internal state
expect(wrapper.state('count')).toBe(3);
expect(wrapper.instance().handleClick).toBeDefined();
expect(wrapper.find('Button').prop('disabled')).toBe(true);
// RTL: tests what the user actually sees and can do
expect(screen.getByText('Count: 3')).toBeInTheDocument();
expect(screen.getByRole('button', { name: /submit/i })).toBeDisabled();
これは 1 対 1 の置き換えではありません。内部状態やインスタンスメソッドを検証する Enzyme テストには、RTL での同等の方法はありません。RTL は意図的に内部を公開しないためです。代わりに、目に見える結果を検証するテストに書き直してください。
API マップ
各 Enzyme API の変更前後のコード全体については、以下をお読みください。
references/enzyme-api-map.md- 完全なマッピング:shallow、mount、find、simulate、prop、state、instance、configurereferences/async-patterns.md- waitFor、findBy、act()、Apollo MockedProvider、ローディング状態、エラー状態
基本的な書き換えテンプレート
// Every Enzyme test rewrites to this shape:
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 () => {
// 1. Render (replaces shallow/mount)
render(<MyComponent prop="value" />);
// 2. Query (replaces wrapper.find())
const button = screen.getByRole('button', { name: /submit/i });
// 3. Interact (replaces simulate())
await userEvent.setup().click(button);
// 4. Assert on visible output (replaces wrapper.state() / wrapper.prop())
expect(screen.getByText('Submitted!')).toBeInTheDocument();
});
});
RTL のクエリ優先順位(この順に使用)
getByRole- アクセシブルなロール(button、textbox、heading、checkbox など)で検索しますgetByLabelText- ラベルと関連付けられたフォームフィールドを検索しますgetByPlaceholderText- 入力欄のプレースホルダーで検索しますgetByText- 表示されているテキストの内容で検索しますgetByDisplayValue- input/select/textarea の現在の値で検索しますgetByAltText- 画像の代替テキストで検索しますgetByTitle- title 属性で検索しますgetByTestId-data-testid属性で検索します(最終手段)
getByTestId よりも getByRole を優先してください。アクセシビリティもテストできます。
プロバイダーでラップする
// Enzyme with context:
const wrapper = mount(
<ApolloProvider client={client}>
<ThemeProvider theme={theme}>
<MyComponent />
</ThemeProvider>
</ApolloProvider>
);
// RTL equivalent (use your project's customRender or wrap inline):
import { render } from '@testing-library/react';
render(
<MockedProvider mocks={mocks} addTypename={false}>
<ThemeProvider theme={theme}>
<MyComponent />
</ThemeProvider>
</MockedProvider>
);
// Or use the project's customRender helper if it wraps providers
コメント
Markdown 対応