0Pricing
React Academy · Lekcja

Testowanie asynchronicznego interfejsu i wywołań API za pomocą MSW

Mockowanie żądań HTTP za pomocą Mock Service Worker w celu testowania komponentów pobierających dane.

Testowanie asynchronicznego interfejsu i wywołań API za pomocą MSW to bezpłatna lekcja React Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej React Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs React Academy zawiera 4 lekcji w sumie.

Dlaczego Mock Service Worker?

MSW przechwytuje żądania HTTP na poziomie sieci za pomocą Service Worker (w przeglądarce) lub interceptora http (w Node), umożliwiając mockowanie API bez modyfikowania kodu aplikacji.

Instalowanie MSW

Należy zainstalować MSW i skonfigurować interceptor Node na potrzeby testów Jest/Vitest.

// 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' }]);
  }),
];

Konfiguracja serwera mocków

Należy utworzyć instancję setupServer z handlerami oraz wywołać server.listen() przed testami, server.resetHandlers() po każdym teście i server.close() po zakończeniu wszystkich testów.

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

const server = setupServer(...handlers);

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

Testowanie komponentu pobierającego dane

Należy wyrenderować komponent, który uruchamia żądanie fetch. MSW przechwytuje żądanie i zwraca dane testowe. Należy sprawdzić to, co użytkownik widzi po załadowaniu danych.

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

Zapytania findBy dla asynchronicznego interfejsu

Zapytania findBy zwracają obietnicę, która zostaje rozstrzygnięta, gdy pojawi się element, z domyślnym limitem czasu wynoszącym 1 sekundę. Należy używać ich w przypadku treści pojawiających się po operacjach asynchronicznych.

// 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();
});

Nadpisywanie handlerów dla pojedynczego testu

Należy użyć server.use() wewnątrz testu, aby dodać jednorazowy handler, który nadpisze domyślny handler tylko na potrzeby tego testu.

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();
});

Testowanie stanów ładowania

Należy sprawdzić wskaźnik ładowania bezpośrednio po renderowaniu, synchronicznie i przed nadejściem asynchronicznych danych.

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

Testowanie żądań POST

Należy zdefiniować handler POST, który zweryfikuje treść żądania i zwróci utworzony zasób. Należy sprawdzić, czy komponent odzwierciedla stan powodzenia.

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();
});

Opóźnienia sieciowe na potrzeby realistycznych testów

Należy dodać sztuczne opóźnienia do handlerów, aby dokładniej testować interfejs ładowania, korzystając z utility delay biblioteki MSW.

import { delay } from 'msw';

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

Testowanie z React Query

Należy opakować komponent w nowy QueryClientProvider dla każdego testu, aby zapobiec przenikaniu stanu między testami.

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

Sprawdzanie danych żądania

Należy użyć spy dla żądania wewnątrz handlera, aby zweryfikować, czy aplikacja wysłała prawidłową treść żądania lub nagłówki.

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 w przeglądarce podczas tworzenia aplikacji

MSW działa również w przeglądarce podczas tworzenia aplikacji. Należy uruchomić npx msw init public/, aby zainstalować service workera, a następnie zaimportować handlery do main.tsx, by podczas lokalnej pracy korzystać z mockowanego API.

Szybkie sprawdzenie

Jakiego typu zapytania RTL należy użyć, aby sprawdzić treść pojawiającą się po zakończeniu żądania API?

Podsumowanie

MSW przechwytuje rzeczywiste żądania HTTP, dzięki czemu testy są realistyczne i nie wymagają kontaktu z działającym serwerem. Należy używać server.use() do zastępowania handlerów w poszczególnych testach, findBy do asynchronicznych asercji oraz opakowywać testy React Query w nowy QueryClientProvider.

Często zadawane pytania

Czy lekcja „Testowanie asynchronicznego interfejsu i wywołań API za pomocą MSW” jest bezpłatna?

Tak — pełny tekst „Testowanie asynchronicznego interfejsu i wywołań API za pomocą MSW” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu React Academy, przejdź na CoddyKit PRO. Kurs React Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Testowanie asynchronicznego interfejsu i wywołań API za pomocą MSW”?

Mockowanie żądań HTTP za pomocą Mock Service Worker w celu testowania komponentów pobierających dane. Ćwiczysz React Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć React Academy?

Nie wymagamy żadnego doświadczenia. React Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Testowanie asynchronicznego interfejsu i wywołań API za pomocą MSW”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji React Academy?

Tak. Każda lekcja React Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Testy integracyjne z React Testing Library
  2. Testowanie asynchronicznego interfejsu i wywołań API za pomocą MSW
  3. Pierwsze kroki z Playwright dla React
  4. Testowanie formularzy i przepływów użytkownika end-to-end
← Powrót do React Academy