Snapshot testing to technika polegająca na "sfotografowaniu" wyniku renderowania komponentu i porównywaniu go z zapisanym wzorcem. To jak zrobienie zdjęcia konstelacji gwiazd -- jeśli przy następnym spojrzeniu jakieś gwiazdy się przesunęły, test to wykryje.
Mechanizm jest prosty. Przy pierwszym uruchomieniu testu, Jest renderuje komponent i zapisuje wynikowy HTML do specjalnego pliku
.snap w folderze __snapshots__. Przy kolejnych uruchomieniach Jest ponownie renderuje komponent i porównuje wynik z zapisanym wzorcem. Jeśli coś się zmieniło -- test nie przechodzi. To jak porównywanie dwóch zdjęć konstelacji zrobionych w odstępie czasu -- jeśli gwiazdy się przesunęły, od razu to zauważysz.Oto podstawowy przykład:
1import { render } from '@testing-library/react';
2import StatusBadge from './StatusBadge';
3
4test('renders active status badge', () => {
5 const { container } = render(<StatusBadge status="active" />);
6 expect(container.firstChild).toMatchSnapshot();
7});1// Jest Snapshot v1
2
3exports[`renders active status badge 1`] = `
4<span
5 class="badge badge-active"
6>
7 Active
8</span>
9`;Zamiast osobnego pliku, snapshot może być zapisany bezpośrednio w teście:
1test('renders fuel display', () => {
2 const { container } = render(<FuelDisplay level={75} />);
3 expect(container.firstChild).toMatchInlineSnapshot(`
4 <div
5 class="fuel-display"
6 >
7 <span>
8 Fuel: 75%
9 </span>
10 </div>
11 `);
12});Gdy celowo zmieniamy komponent, snapshoty muszą być zaktualizowane:
1# Aktualizacja wszystkich snapshotów
2npm test -- --updateSnapshot
3
4# Lub skrótowo
5npm test -- -u1// Dobry snapshot -- prosty komponent
2test('renders planet card', () => {
3 const { container } = render(
4 <PlanetCard name="Mars" distance="225M km" color="red" />
5 );
6 expect(container.firstChild).toMatchSnapshot();
7});1// ZŁY snapshot -- za duży, zbyt dynamiczny
2test('renders entire dashboard', () => {
3 const { container } = render(<Dashboard />); // 500 linii HTML!
4 expect(container).toMatchSnapshot(); // Nikt tego nie przeczyta!
5});To fundamentalne porównanie, które każdy programista React powinien rozumieć. Snapshot sprawdza całą strukturę komponentu -- każdy tag, klasę i atrybut. Targeted assertion sprawdza konkretne zachowanie -- czy tekst jest widoczny, czy przycisk jest aktywny, czy element ma odpowiednią klasę. Różnica jest jak między zrobieniem zdjęcia całego panelu sterowania a sprawdzeniem, czy konkretna kontrolka świeci na zielono.
1// Snapshot -- sprawdza CAŁĄ strukturę
2expect(container.firstChild).toMatchSnapshot();
3
4// Targeted assertion -- sprawdza KONKRETNE zachowanie (zalecane!)
5expect(screen.getByText('Active')).toHaveClass('badge-active');
6expect(screen.getByRole('button')).toBeEnabled();Zasada: Preferuj targeted assertions nad snapshoty. Snapshoty łatwo stają się "niewidoczne" -- programiści często aktualizują je automatycznie komendą
-u bez sprawdzania, co się zmieniło. Targeted assertions natomiast wymuszają świadome sprawdzenie konkretnego zachowania. Snapshoty są dobre jako dodatkowe zabezpieczenie przed nieoczekiwanymi zmianami wizualnymi, ale nie powinny być głównym sposobem testowania.Możemy dostosować jak snapshoty są formatowane:
1// W setupTests.js lub pliku konfiguracyjnym
2expect.addSnapshotSerializer({
3 test: (val) => val && val.className,
4 print: (val) => `ClassName: ${val.className}`,
5});1test('renders navigation with correct structure', () => {
2 const { container } = render(<SpaceNavigation routes={routes} />);
3
4 // Snapshot tylko części komponentu
5 expect(
6 container.querySelector('.nav-links')
7 ).toMatchSnapshot();
8});| Sytuacja | Snapshot | Targeted | |----------|----------|----------| | Prosty komponent UI | Tak | Tak | | Logika biznesowa | Nie | Tak | | Interakcje użytkownika | Nie | Tak | | Formatowanie danych | Tak | Tak | | Duży komponent | Nie | Tak | | Regresja wizualna | Tak | Nie |