0Pricing
React Academy · レッスン

MSWによる非同期UIとAPI呼び出しのテスト

Mock Service WorkerでHTTPリクエストをモックし、データを取得するコンポーネントをテストします。

「MSWによる非同期UIとAPI呼び出しのテスト」はCoddyKit上の無料React Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはReact Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 React Academyコースには全4レッスンが含まれています。

Mock Service Workerを使う理由

MSWは、Service Worker(ブラウザー)またはhttpインターセプター(Node)を使ってネットワークレベルでHTTPリクエストをインターセプトします。これにより、アプリケーションコードに手を加えずにAPIをモックできます。

MSWのインストール

MSWをインストールし、Jest/Vitestのテスト用にNodeインターセプターをセットアップします。

// npm install msw --save-dev

// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw';

export const handlers = [
  http.get('/api/users', () => {
    return HttpResponse.json([{ id: 1, name: 'Alice' }]);
  }),
];

モックサーバーのセットアップ

ハンドラーを使ってsetupServerインスタンスを作成し、テスト前にserver.listen()を、各テストの後にserver.resetHandlers()を、すべてのテストの後にserver.close()を呼び出します。

import { setupServer } from 'msw/node';
import { handlers } from './handlers';

const server = setupServer(...handlers);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

データを取得するコンポーネントのテスト

fetchを実行するコンポーネントを描画します。MSWがリクエストをインターセプトし、モックデータを返します。データの読み込み後にユーザーに表示される内容をアサートします。

test('shows user list after fetch', async () => {
  render(<UserList />);
  expect(screen.getByText('Loading...')).toBeInTheDocument();
  expect(await screen.findByText('Alice')).toBeInTheDocument();
});

非同期UIのfindByクエリ

findByクエリは、要素が表示されると解決するPromiseを返します(デフォルトのタイムアウトは最大1秒です)。非同期処理の後に表示されるコンテンツに使用します。

// findByText waits for the element to appear
const username = await screen.findByText('Alice');
expect(username).toBeInTheDocument();

// waitFor wraps assertions that need to wait
await waitFor(() => {
  expect(screen.getByText('3 users')).toBeInTheDocument();
});

テストごとのハンドラーの上書き

テスト内でserver.use()を使用すると、そのテストに限ってデフォルト設定を上書きする一時的なハンドラーを追加できます。

test('shows error on API failure', async () => {
  server.use(
    http.get('/api/users', () => {
      return HttpResponse.json({ message: 'Server error' }, { status: 500 });
    })
  );

  render(<UserList />);
  expect(await screen.findByText('Failed to load users')).toBeInTheDocument();
});

ローディング状態のテスト

非同期データが到着する前に、描画直後のローディングインジケーターを同期的にアサートします。

test('shows loading state initially', () => {
  render(<UserList />);
  expect(screen.getByRole('progressbar')).toBeInTheDocument();
  // or
  expect(screen.getByText('Loading...')).toBeInTheDocument();
});

POSTリクエストのテスト

リクエストボディを検証し、作成されたリソースを返すPOSTハンドラーを定義します。コンポーネントが成功状態を反映していることをアサートします。

server.use(
  http.post('/api/users', async ({ request }) => {
    const body = await request.json();
    return HttpResponse.json({ id: 2, ...body }, { status: 201 });
  })
);

test('creates a user', async () => {
  const user = userEvent.setup();
  render(<NewUserForm />);
  await user.type(screen.getByLabelText('Name'), 'Bob');
  await user.click(screen.getByRole('button', { name: /create/i }));
  expect(await screen.findByText('User created!')).toBeInTheDocument();
});

現実的なテストのためのネットワーク遅延

ハンドラーに人工的な遅延を追加して、ローディングUIをより詳しくテストします。MSWのdelayユーティリティを使用してください。

import { delay } from 'msw';

http.get('/api/users', async () => {
  await delay(200);
  return HttpResponse.json([{ id: 1, name: 'Alice' }]);
})

React Queryを使ったテスト

テスト間で状態が漏れないように、各テストで新しいQueryClientProviderにコンポーネントをラップします。

function renderWithQuery(ui: React.ReactElement) {
  const queryClient = new QueryClient({
    defaultOptions: { queries: { retry: false } },
  });
  return render(
    <QueryClientProvider client={queryClient}>{ui}</QueryClientProvider>
  );
}

リクエストデータのアサーション

ハンドラー内でリクエストスパイを使用し、アプリケーションが正しいリクエストボディやヘッダーを送信したことを検証します。

let capturedBody: unknown;

server.use(
  http.post('/api/login', async ({ request }) => {
    capturedBody = await request.json();
    return HttpResponse.json({ token: 'abc' });
  })
);

test('sends credentials to API', async () => {
  // ... submit form ...
  expect(capturedBody).toEqual({ email: 'a@b.com', password: 'pass' });
});

開発時のブラウザでのMSW

MSWは開発中のブラウザでも動作します。npx msw init public/を実行してサービスワーカーをインストールし、main.tsxでハンドラーをインポートすると、ローカル開発でモックAPIを使用できます。

クイックチェック

API呼び出しが解決した後に表示されるコンテンツをアサートするには、どの種類のRTLクエリを使用すべきでしょうか。

振り返り

MSWは実際のHTTPリクエストをインターセプトするため、ライブサーバーに接続しなくても現実的なテストを実行できます。テストごとにハンドラーを上書きするにはserver.use()を、非同期アサーションにはfindByを使用します。また、React Queryのテストでは新しいQueryClientProviderでラップしてください。

よくある質問

「MSWによる非同期UIとAPI呼び出しのテスト」レッスンは無料ですか?

はい。「MSWによる非同期UIとAPI呼び出しのテスト」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、React Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 React Academyコースには全4レッスンが含まれています。

「MSWによる非同期UIとAPI呼び出しのテスト」で何を学びますか?

Mock Service WorkerでHTTPリクエストをモックし、データを取得するコンポーネントをテストします。 ブラウザで直接実行するハンズオンコードでReact Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

React Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのReact Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「MSWによる非同期UIとAPI呼び出しのテスト」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このReact Academyレッスンでコードを書いて実行できますか?

はい。すべてのReact Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. React Testing LibraryによるIntegration Testing
  2. MSWによる非同期UIとAPI呼び出しのテスト
  3. React向けPlaywright入門
  4. フォームとユーザーフローのE2Eテスト
← React Academyに戻る