Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

React Testing Library -- Panel Kontroli Misji

React Testing Library (RTL) to biblioteka, która zmienia sposób, w jaki testujemy komponenty React. Zamiast testować wewnętrzną implementację, RTL skupia się na tym, co użytkownik widzi i robi -- dokładnie jak panel kontroli misji, który pokazuje pilotowi tylko to, co istotne.

Główna zasada RTL

"Im bardziej Twoje testy przypominają sposób, w jaki oprogramowanie jest używane, tym więcej pewności Ci dają." -- Kent C. Dodds

Renderowanie komponentów

Funkcja

render
to podstawa RTL -- odpala komponent w wirtualnym DOM:

1import { render, screen } from '@testing-library/react';
2import SpaceshipDashboard from './SpaceshipDashboard';
3
4test('renders spaceship dashboard', () => {
5  render(<SpaceshipDashboard pilotName="Nova" />);
6  // Komponent jest teraz dostępny do testowania
7  expect(screen.getByText('Welcome, Nova!')).toBeInTheDocument();
8});

Queries -- Wyszukiwanie Elementów

RTL oferuje trzy rodziny zapytań, każda do innego celu:

getBy -- Szuka i wymaga znalezienia

1// Rzuca błąd, jeśli element NIE istnieje
2const heading = screen.getByText('Mission Control');
3const input = screen.getByRole('textbox');
4const img = screen.getByAltText('spaceship');

queryBy -- Szuka, ale nie wymaga

1// Zwraca null, jeśli element NIE istnieje (nie rzuca błędu)
2const error = screen.queryByText('Error occurred');
3expect(error).not.toBeInTheDocument();

findBy -- Szuka asynchronicznie

1// Czeka na pojawienie się elementu (zwraca Promise)
2const data = await screen.findByText('Data loaded');
3expect(data).toBeInTheDocument();

Rodzaje selektorów

Każda rodzina zapytań ma warianty:

ByRole -- Najlepsza praktyka!

1// Szuka po roli ARIA -- najlepszy sposób!
2screen.getByRole('button', { name: 'Launch' });
3screen.getByRole('heading', { level: 1 });
4screen.getByRole('textbox', { name: /pilot name/i });
5screen.getByRole('checkbox', { checked: true });
6screen.getByRole('link', { name: 'Dashboard' });

ByText -- Szuka po tekście

1screen.getByText('Mission Status: Active');
2screen.getByText(/mission/i); // regex, case-insensitive

ByLabelText -- Szuka po etykiecie formularza

1// <label htmlFor="speed">Speed</label>
2// <input id="speed" />
3screen.getByLabelText('Speed');

ByPlaceholderText -- Szuka po placeholder

1screen.getByPlaceholderText('Enter coordinates');

ByTestId -- Ostateczność

1// <div data-testid="fuel-gauge">...</div>
2screen.getByTestId('fuel-gauge');

Priorytet selektorów

RTL zaleca następujący priorytet (od najlepszego):

  1. getByRole -- dostępność, jak użytkownik widzi element
  2. getByLabelText -- formularze
  3. getByPlaceholderText -- gdy brak labela
  4. getByText -- elementy nieinteraktywne
  5. getByDisplayValue -- aktualna wartość inputa
  6. getByAltText -- obrazy
  7. getByTitle -- atrybut title
  8. getByTestId -- ostateczność, gdy nic innego nie pasuje

Matchery jest-dom

Biblioteka

@testing-library/jest-dom
dodaje specjalne matchery:

1// Widoczność
2expect(element).toBeVisible();
3expect(element).toBeInTheDocument();
4
5// Atrybuty
6expect(button).toBeDisabled();
7expect(input).toBeRequired();
8expect(input).toHaveValue('Apollo');
9
10// Klasy CSS
11expect(element).toHaveClass('active');
12
13// Tekst
14expect(element).toHaveTextContent('Mission');
15
16// Style
17expect(element).toHaveStyle({ color: 'green' });

Renderowanie z kontekstem

Często komponenty potrzebują providerów (Router, Theme, Store):

1function renderWithProviders(ui, options = {}) {
2  function Wrapper({ children }) {
3    return (
4      <ThemeProvider theme="dark">
5        <MissionProvider>
6          {children}
7        </MissionProvider>
8      </ThemeProvider>
9    );
10  }
11  return render(ui, { wrapper: Wrapper, ...options });
12}
13
14// Użycie
15test('renders themed dashboard', () => {
16  renderWithProviders(<Dashboard />);
17  expect(screen.getByText('Dark Mode')).toBeInTheDocument();
18});

Debug -- kiedy testy nie przechodza

Gdy test nie przechodzi i nie wiesz dlaczego, uzyj

screen.debug()
do podejrzenia aktualnego stanu DOM:

1test('shows mission status', () => {
2  render(<MissionPanel />);
3
4  // Wyswietla aktualny stan DOM w konsoli
5  screen.debug();
6
7  // Mozesz tez debugowac konkretny element
8  const panel = screen.getByRole('main');
9  screen.debug(panel);
10});

screen.debug()
wyswietli HTML calego wyrenderowanego komponentu, co pomaga zrozumiec, dlaczego selektor nie znajduje elementu. To jak system diagnostyczny na statku kosmicznym -- gdy cos nie dziala, najpierw sprawdzasz logi!

React Testing Library to fundament nowoczesnego testowania komponentów React. Zamiast testowac detale implementacji, testujesz to, co naprawde wazne -- doswiadczenie uzytkownika.

Przejdź do CodeWorlds