React Testing LibraryによるIntegration Testing
テスト内でコンポーネントをrenderし、イベントを発生させ、実装ではなく表示結果を検証します。
「React Testing LibraryによるIntegration Testing」はCoddyKit上の無料React Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはReact Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 React Academyコースには全4レッスンが含まれています。
React Testing Libraryとは
React Testing Library(RTL)は、ユーザーの視点からテストすることを推奨します。コンポーネントを描画し、ユーザーと同じように操作して、実装の詳細ではなく表示される結果をアサートします。
セットアップ
RTLはCreate React AppとViteのReactテンプレートに含まれています。手動でセットアップする場合は、@testing-library/reactと@testing-library/jest-domをインストールします。
// package.json
// "@testing-library/react": "^14.0.0",
// "@testing-library/jest-dom": "^6.0.0"
// setupTests.ts
import '@testing-library/jest-dom';コンポーネントの描画
render()は仮想DOMにコンポーネントをマウントします。描画された出力を対象とするクエリ関数を返します。
import { render, screen } from '@testing-library/react';
import { Button } from './Button';
test('renders button label', () => {
render(<Button label="Submit" onClick={() => {}} />);
expect(screen.getByText('Submit')).toBeInTheDocument();
});要素の検索
クエリは次の順序で優先します:getByRole > getByLabelText > getByPlaceholderText > getByText。Roleクエリはアクセシビリティのセマンティクスに一致します。
// Best: query by role
const button = screen.getByRole('button', { name: /submit/i });
// Good: query by label (for form inputs)
const input = screen.getByLabelText('Email address');
// Acceptable: query by text
const heading = screen.getByText('Welcome');イベントの発火
@testing-library/user-eventのuserEvent(推奨)またはfireEvent(基本)を使用します。userEventは、フォーカスやぼかしを含む実際のブラウザー操作をシミュレートします。
import userEvent from '@testing-library/user-event';
test('types into input', async () => {
const user = userEvent.setup();
render(<SearchBar />);
const input = screen.getByRole('textbox');
await user.type(input, 'react');
expect(input).toHaveValue('react');
});フォーム送信のテスト
フォームを描画し、userEvent.typeで入力欄に値を入力し、送信ボタンをクリックして、結果(成功メッセージ、ページ遷移、またはコールバックの呼び出し)をアサートします。
test('submits the login form', async () => {
const onLogin = jest.fn();
const user = userEvent.setup();
render(<LoginForm onLogin={onLogin} />);
await user.type(screen.getByLabelText('Email'), 'test@example.com');
await user.type(screen.getByLabelText('Password'), 'password123');
await user.click(screen.getByRole('button', { name: /log in/i }));
expect(onLogin).toHaveBeenCalledWith({ email: 'test@example.com', password: 'password123' });
});表示状態のアサート
toBeInTheDocument()、toBeVisible()、toHaveValue()などのjest-domのmatcherを使うと、アサーションを読みやすく記述できます。
expect(screen.getByText('Error: required')).toBeInTheDocument();
expect(screen.getByRole('dialog')).toBeVisible();
expect(screen.getByRole('textbox')).toHaveValue('hello');
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();条件付き描画のテスト
要素が描画されていないことをアサートするには、存在しない場合にnullを返すqueryByを使用します。存在することを期待する場合はgetByを使用します。
test('shows error message when validation fails', async () => {
const user = userEvent.setup();
render(<SignUpForm />);
await user.click(screen.getByRole('button', { name: /submit/i }));
expect(screen.getByText('Email is required')).toBeInTheDocument();
});Providerでラップする
多くのコンポーネントにはContextまたはrouterが必要です。renderの呼び出し内でProviderを使ってラップするか、カスタムのrenderWithProvidersヘルパーを作成します。
function renderWithProviders(ui: React.ReactElement) {
return render(
<QueryClientProvider client={new QueryClient()}>
<MemoryRouter>
{ui}
</MemoryRouter>
</QueryClientProvider>
);
}
test('shows user data', () => {
renderWithProviders(<UserProfile />);
});状態変更のテスト
コンポーネントを操作した後、新しい状態がUIに反映されていることをアサートします。userEventを使用すると、RTLはほとんどの操作を自動的にactでラップします。
test('counter increments', async () => {
const user = userEvent.setup();
render(<Counter />);
expect(screen.getByText('Count: 0')).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: /increment/i }));
expect(screen.getByText('Count: 1')).toBeInTheDocument();
});Screenデバッグヘルパー
screen.debug()を呼び出すと、現在描画されているHTMLをコンソールに出力できます。クエリが失敗し、実際に何が描画されているか確認したい場合に便利です。
test('debugging a failing query', () => {
render(<MyComponent />);
screen.debug(); // prints rendered HTML
screen.getByRole('button', { name: /save/i }); // then inspect output
});クイックチェック
React Testing Libraryでボタンをテストするとき、どのクエリを優先すべきですか?
まとめ
RTLではコンポーネントを描画し、ロールベースのクエリとuserEventで操作します。必要なProviderでコンポーネントをラップし、読みやすいアサーションにはjest-domのmatcherを使用します。存在しないことをアサートする場合はqueryByを優先します。
よくある質問
「React Testing LibraryによるIntegration Testing」レッスンは無料ですか?
はい。「React Testing LibraryによるIntegration Testing」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、React Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 React Academyコースには全4レッスンが含まれています。
「React Testing LibraryによるIntegration Testing」で何を学びますか?
テスト内でコンポーネントをrenderし、イベントを発生させ、実装ではなく表示結果を検証します。 ブラウザで直接実行するハンズオンコードでReact Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
React Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのReact Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「React Testing LibraryによるIntegration Testing」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このReact Academyレッスンでコードを書いて実行できますか?
はい。すべてのReact Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- React Testing LibraryによるIntegration Testing
- MSWによる非同期UIとAPI呼び出しのテスト
- React向けPlaywright入門
- フォームとユーザーフローのE2Eテスト