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.
"Im bardziej Twoje testy przypominają sposób, w jaki oprogramowanie jest używane, tym więcej pewności Ci dają." -- Kent C. Dodds
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});RTL oferuje trzy rodziny zapytań, każda do innego celu:
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');1// Zwraca null, jeśli element NIE istnieje (nie rzuca błędu)
2const error = screen.queryByText('Error occurred');
3expect(error).not.toBeInTheDocument();1// Czeka na pojawienie się elementu (zwraca Promise)
2const data = await screen.findByText('Data loaded');
3expect(data).toBeInTheDocument();Każda rodzina zapytań ma warianty:
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' });1screen.getByText('Mission Status: Active');
2screen.getByText(/mission/i); // regex, case-insensitive1// <label htmlFor="speed">Speed</label>
2// <input id="speed" />
3screen.getByLabelText('Speed');1screen.getByPlaceholderText('Enter coordinates');1// <div data-testid="fuel-gauge">...</div>
2screen.getByTestId('fuel-gauge');RTL zaleca następujący priorytet (od najlepszego):
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' });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});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.