Od snímků k chování: přechod na React Testing Library v testech
V typických projektech jsou testy často zaměřeny na základní strukturu, nikoli na funkčnost. Snímky (snapshots) zachycují stav DOM, ale selhávají při každém refaktoringu – změna tříd CSS, přesun atributů nebo optimalizace vykreslování. Skutečné chyby v logice zůstávají nezaznamenané.
Příklad problematického testu na Enzyme:
describe("UserProfileCards", () => {
it("should render", () => {
const wrapper = shallow(
<Provider store={store}>
<UserProfileCards items={mockedUserProfiles} />
</Provider>
)
expect(wrapper).toMatchSnapshot()
})
})
Tento test nedává jistotu o správném fungování komponenty. Zkontroluje strukturu, nikoli výsledek pro uživatele.
Přichycení k implementaci: falešné výpady
Testy, které se drží za interní detaily, vytvářejí dvě problémy: pád při refaktoru a přehlédnutí chyb.
Uvažujme komponentu CollapseIcon s příznakem opened:
import CollapseIcon from "./CollapseIcon"
import { shallow } from "enzyme"
describe("CollapseIcon", () => {
it("should render", () => {
const wrapper = shallow(<CollapseIcon opened={false} />)
expect(wrapper).toMatchSnapshot()
})
it("should react to closed", () => {
const wrapper = shallow(<CollapseIcon opened={false} />)
expect(wrapper.find(".collapse__icon").hasClass("collapseIcon_closed")).toEqual(true)
})
it("should react to opened", () => {
const wrapper = shallow(<CollapseIcon opened={true} />)
expect(wrapper.find(".collapse__icon").hasClass("collapseIcon_opened")).toEqual(true)
})
})
Problémy:
- Snímek nezachytí chyby v animaci.
- Ověření tříd selže při změně stylů.
- Testy proběhnou i pokud je animace poškozená.
Další případ: pevná vazba na konstanty lokalizace:
it("should render no-answers button", () => {
const button = getButton(mockCommentsList[0])
const noAnswersText = `${mockedTranslation.t(`${tNamespace}no-answers`)}
expect(button.text()).toBe(noAnswersText)
})
Změna klíče v tNamespace poruší test, i když text tlačítka je správný. Řešení: konstanty přesunout do společného modulu, který importuje jak komponenta, tak testy.
Nejasná popisování testů zhoršuje situaci:
- "should show tooltip" – bez podmínek.
- "should render without tooltipLabel" – bez očekávaného výsledku.
React Testing Library: testování chování
RTL mění paradigma: testy napodobují akce uživatele a ignorují interní detaily. Nemají přístup k state, props nebo metodám – pouze k viditelnému rozhraní.
Výhody RTL:
- Fokus na uživatele: klikání, zadávání textu, čtení prostřednictvím screen.
- Refaktoring-safe: nezávislé na třídách, id nebo interním stavu.
- API:
render(),screen.getByRole(),fireEvent.click(),waitFor(). - Asynchronní operace:
findByRole()pro načítání dat. - Přístupnost (a11y):
getByLabelText()ověřuje dostupnost.
RTL je navržen pro odolnost: testy odrážejí skutečné používání, nikoli strukturu DOM.
Seznam kontrol pro kvalitní testy
Psaní testů
- Cíl: jasně formulovat, co se testuje ("zobrazuje tooltip při isTooltipShow=true").
- Pohled uživatele: akce jako uživatel –
getByRole('button'),fireEvent. - Izolace: mocky pro API, žádné závislosti na jiných testech.
- Popisy: úplné věty, čitelné bez kódu.
- Pokrytí: happy path + hraniční případy + chyby.
Revize testů
- Je cíl jasný?
- Neobsahuje-li detaily implementace (třídy, stav)?
- Je test izolovaný?
- Jsou popisy informační?
- Jsou komentáře konstruktivní?
Organizace přechodu ve týmu
Workshop na migraci: sbírat problematické testy, rozebírat na příkladech, přecházet na RTL. Doporučení:
- Rozdělit na sesie po 45 minutách s účastí autorů.
- Společný refaktoring testů ve pair-programmingu.
- Méně teorie, více praxe na kódu.
Migrace legacy: nové testy na RTL, staré postupně přepsat. Příklad Airbnb – 3500 souborů za 6 týdnů s LLM-pipelinou (75 % automaticky).
Co je důležité
- Změna myšlení: od struktury k chování uživatele.
- RTL vs Enzyme: RTL blokuje přístup k interním částem, Enzyme jej povoluje.
- Seznamy kontrol: povinné při psaní i revizi.
- Workshopy: dialog je důležitější než monolog.
- Migrace: automatizace urychlí, ale pochopení filozofie je nezbytné.
— Editorial Team
Zatím žádné komentáře.