Õppige React Testing Library (RTL) selgeks selle täieliku juhendiga. Saage teada, kuidas kirjutada tõhusaid, hooldatavaid ja kasutajakeskseid teste oma Reacti rakendustele.
React Testing Library: Põhjalik Juhend
Tänapäeva kiires veebiarenduse maastikul on teie Reacti rakenduste kvaliteedi ja usaldusväärsuse tagamine esmatähtis. React Testing Library (RTL) on kujunenud populaarseks ja tõhusaks lahenduseks testide kirjutamisel, mis keskenduvad kasutaja vaatenurgale. See juhend annab täieliku ülevaate RTL-ist, hõlmates kõike alates põhimõistetest kuni täiustatud tehnikateni, andes teile võimaluse luua tugevaid ja hooldatavaid Reacti rakendusi.
Miks valida React Testing Library?
Traditsioonilised testimismeetodid tuginevad sageli implementatsiooni detailidele, muutes testid hapraks ja altiks purunema väikeste koodimuudatuste korral. RTL, teisest küljest, julgustab teid testima oma komponente nii, nagu kasutaja nendega suhtleks, keskendudes sellele, mida kasutaja näeb ja kogeb. See lähenemine pakub mitmeid olulisi eeliseid:
- Kasutajakeskne testimine: RTL soodustab testide kirjutamist, mis peegeldavad kasutaja vaatenurka, tagades, et teie rakendus toimib ootuspäraselt lõppkasutaja seisukohast.
- Väiksem testide haprus: Vältides implementatsiooni detailide testimist, on RTL-i testid vähem tõenäolised purunema, kui teete koodi refaktoorimist, mis viib hooldatavamate ja tugevamate testideni.
- Parem koodidisain: RTL julgustab teid kirjutama komponente, mis on ligipääsetavad ja kergesti kasutatavad, mis viib parema üldise koodidisainini.
- Keskendumine ligipääsetavusele: RTL muudab teie komponentide ligipääsetavuse testimise lihtsamaks, tagades, et teie rakendus on kõigile kasutatav.
- Lihtsustatud testimisprotsess: RTL pakub lihtsat ja intuitiivset API-d, mis muudab testide kirjutamise ja hooldamise lihtsamaks.
Testimiskeskkonna seadistamine
Enne RTL-i kasutama hakkamist peate seadistama oma testimiskeskkonna. See hõlmab tavaliselt vajalike sõltuvuste installimist ja testimisraamistiku konfigureerimist.
Eeltingimused
- Node.js ja npm (või yarn): Veenduge, et teie süsteemi on installitud Node.js ja npm (või yarn). Saate need alla laadida ametlikult Node.js-i veebisaidilt.
- Reacti projekt: Teil peaks olema olemasolev Reacti projekt või looge uus, kasutades Create React Appi või sarnast tööriista.
Installimine
Installige järgmised paketid, kasutades npm-i või yarn-i:
npm install --save-dev @testing-library/react @testing-library/jest-dom jest babel-jest @babel/preset-env @babel/preset-react
Või, kasutades yarn-i:
yarn add --dev @testing-library/react @testing-library/jest-dom jest babel-jest @babel/preset-env @babel/preset-react
Pakettide selgitus:
- @testing-library/react: Põhiteek Reacti komponentide testimiseks.
- @testing-library/jest-dom: Pakub kohandatud Jest matchereid DOM-sõlmede kohta väidete tegemiseks.
- Jest: Populaarne JavaScripti testimisraamistik.
- babel-jest: Jesti transformer, mis kasutab teie koodi kompileerimiseks Babelit.
- @babel/preset-env: Babeli eelseade, mis määrab kindlaks Babeli pluginad ja eelseaded, mis on vajalikud teie sihtkeskkondade toetamiseks.
- @babel/preset-react: Babeli eelseade Reacti jaoks.
Konfigureerimine
Looge oma projekti juurkataloogi fail `babel.config.js` järgmise sisuga:
module.exports = {
presets: ['@babel/preset-env', '@babel/preset-react'],
};
Uuendage oma `package.json` faili, et lisada testiskript:
{
"scripts": {
"test": "jest"
}
}
Looge oma projekti juurkataloogi fail `jest.config.js`, et konfigureerida Jesti. Minimaalne konfiguratsioon võib välja näha selline:
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['/src/setupTests.js'],
};
Looge fail `src/setupTests.js` järgmise sisuga. See tagab, et Jest DOM matchers on saadaval kõigis teie testides:
import '@testing-library/jest-dom/extend-expect';
Esimese testi kirjutamine
Alustame lihtsa näitega. Oletame, et teil on Reacti komponent, mis kuvab tervitussõnumi:
// src/components/Greeting.js
import React from 'react';
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
export default Greeting;
Nüüd kirjutame selle komponendi jaoks testi:
// src/components/Greeting.test.js
import React from 'react';
import { render, screen } from '@testing-library/react';
import Greeting from './Greeting';
test('kuvab tervitussõnumi', () => {
render(<Greeting name="World" />);
const greetingElement = screen.getByText(/Hello, World!/i);
expect(greetingElement).toBeInTheDocument();
});
Selgitus:
- `render`: See funktsioon renderdab komponendi DOM-i.
- `screen`: See objekt pakub meetodeid DOM-i päringute tegemiseks.
- `getByText`: See meetod leiab elemendi selle tekstisisu järgi. `/i` lipp muudab otsingu tõstutundetuks.
- `expect`: Seda funktsiooni kasutatakse komponendi käitumise kohta väidete tegemiseks.
- `toBeInTheDocument`: See matcher kinnitab, et element on DOM-is olemas.
Testi käivitamiseks käivitage oma terminalis järgmine käsk:
npm test
Kui kõik on õigesti konfigureeritud, peaks test läbima.
Levinumad RTL-i päringud
RTL pakub erinevaid päringumeetodeid elementide leidmiseks DOM-ist. Need päringud on loodud jäljendama, kuidas kasutajad teie rakendusega suhtlevad.
`getByRole`
See päring leiab elemendi selle ARIA rolli järgi. Hea tava on kasutada `getByRole` alati, kui see on võimalik, kuna see edendab ligipääsetavust ja tagab, et teie testid on vastupidavad aluseks oleva DOM-i struktuuri muudatustele.
<button role="button">Click me</button>
const buttonElement = screen.getByRole('button');
expect(buttonElement).toBeInTheDocument();
`getByLabelText`
See päring leiab elemendi selle seotud sildi teksti järgi. See on kasulik vormielementide testimiseks.
<label htmlFor="name">Name:</label>
<input type="text" id="name" />
const nameInputElement = screen.getByLabelText('Name:');
expect(nameInputElement).toBeInTheDocument();
`getByPlaceholderText`
See päring leiab elemendi selle kohatäiteteksti (placeholder) järgi.
<input type="text" placeholder="Enter your email" />
const emailInputElement = screen.getByPlaceholderText('Enter your email');
expect(emailInputElement).toBeInTheDocument();
`getByAltText`
See päring leiab pildielemendi selle alt-teksti järgi. Ligipääsetavuse tagamiseks on oluline pakkuda kõigile piltidele tähendusrikast alt-teksti.
<img src="logo.png" alt="Company Logo" />
const logoImageElement = screen.getByAltText('Company Logo');
expect(logoImageElement).toBeInTheDocument();
`getByTitle`
See päring leiab elemendi selle title-atribuudi järgi.
<span title="Close">X</span>
const closeElement = screen.getByTitle('Close');
expect(closeElement).toBeInTheDocument();
`getByDisplayValue`
See päring leiab elemendi selle kuvatava väärtuse järgi. See on kasulik eelnevalt täidetud väärtustega vormisisendite testimiseks.
<input type="text" value="Initial Value" />
const inputElement = screen.getByDisplayValue('Initial Value');
expect(inputElement).toBeInTheDocument();
`getAllBy*` päringud
Lisaks `getBy*` päringutele pakub RTL ka `getAllBy*` päringuid, mis tagastavad massiivi sobivatest elementidest. Need on kasulikud, kui peate kinnitama, et DOM-is on mitu sama omadustega elementi.
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
const listItems = screen.getAllByRole('listitem');
expect(listItems).toHaveLength(3);
`queryBy*` päringud
`queryBy*` päringud on sarnased `getBy*` päringutega, kuid need tagastavad `null`, kui sobivat elementi ei leita, selle asemel et visata viga. See on kasulik, kui soovite kinnitada, et element *ei ole* DOM-is olemas.
const missingElement = screen.queryByText('Non-existent text');
expect(missingElement).toBeNull();
`findBy*` päringud
`findBy*` päringud on asünkroonsed versioonid `getBy*` päringutest. Need tagastavad Promise'i, mis laheneb, kui sobiv element leitakse. Need on kasulikud asünkroonsete toimingute testimiseks, näiteks andmete pärimiseks API-st.
// Asünkroonse andmete pärimise simuleerimine
const fetchData = () => new Promise(resolve => {
setTimeout(() => resolve('Data Loaded!'), 1000);
});
function MyComponent() {
const [data, setData] = React.useState(null);
React.useEffect(() => {
fetchData().then(setData);
}, []);
return <div>{data}</div>;
}
test('laeb andmed asünkroonselt', async () => {
render(<MyComponent />);
const dataElement = await screen.findByText('Data Loaded!');
expect(dataElement).toBeInTheDocument();
});
Kasutajate interaktsioonide simuleerimine
RTL pakub `fireEvent` ja `userEvent` API-sid kasutajate interaktsioonide simuleerimiseks, nagu nuppude klõpsamine, sisestusväljadele trükkimine ja vormide esitamine.
`fireEvent`
`fireEvent` võimaldab teil programmiliselt käivitada DOM-i sündmusi. See on madalama taseme API, mis annab teile peeneteralise kontrolli käivitatavate sündmuste üle.
<button onClick={() => alert('Button clicked!')}>Click me</button>
import { fireEvent } from '@testing-library/react';
test('simuleerib nupuvajutust', () => {
const alertMock = jest.spyOn(window, 'alert').mockImplementation(() => {});
render(<button onClick={() => alert('Button clicked!')}>Click me</button>);
const buttonElement = screen.getByRole('button');
fireEvent.click(buttonElement);
expect(alertMock).toHaveBeenCalledTimes(1);
alertMock.mockRestore();
});
`userEvent`
`userEvent` on kõrgema taseme API, mis simuleerib kasutajate interaktsioone realistlikumalt. See tegeleb detailidega nagu fookuse haldamine ja sündmuste järjestus, muutes teie testid robustsemaks ja vähem hapraks.
<input type="text" onChange={e => console.log(e.target.value)} />
import userEvent from '@testing-library/user-event';
test('simuleerib sisestusväljale trükkimist', () => {
const inputElement = screen.getByRole('textbox');
userEvent.type(inputElement, 'Hello, world!');
expect(inputElement).toHaveValue('Hello, world!');
});
Asünkroonse koodi testimine
Paljud Reacti rakendused hõlmavad asünkroonseid toiminguid, näiteks andmete pärimist API-st. RTL pakub mitmeid tööriistu asünkroonse koodi testimiseks.
`waitFor`
`waitFor` võimaldab teil oodata tingimuse täitumist enne väite tegemist. See on kasulik asünkroonsete toimingute testimiseks, mis võtavad aega.
function MyComponent() {
const [data, setData] = React.useState(null);
React.useEffect(() => {
setTimeout(() => {
setData('Data loaded!');
}, 1000);
}, []);
return <div>{data}</div>;
}
import { waitFor } from '@testing-library/react';
test('ootab andmete laadimist', async () => {
render(<MyComponent />);
await waitFor(() => screen.getByText('Data loaded!'));
const dataElement = screen.getByText('Data loaded!');
expect(dataElement).toBeInTheDocument();
});
`findBy*` päringud
Nagu varem mainitud, on `findBy*` päringud asünkroonsed ja tagastavad Promise'i, mis laheneb, kui sobiv element leitakse. Need on kasulikud asünkroonsete toimingute testimiseks, mis põhjustavad muudatusi DOM-is.
Hookide testimine
React Hookid on korduvkasutatavad funktsioonid, mis kapseldavad olekuga seotud loogikat. RTL pakub utiliiti `renderHook` teegist `@testing-library/react-hooks` (mis on alates v17-st aegunud ja asendatud `@testing-library/react` teegiga), et testida kohandatud Hooke eraldiseisvalt.
// src/hooks/useCounter.js
import { useState } from 'react';
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => {
setCount(prevCount => prevCount + 1);
};
const decrement = () => {
setCount(prevCount => prevCount - 1);
};
return { count, increment, decrement };
}
export default useCounter;
// src/hooks/useCounter.test.js
import { renderHook, act } from '@testing-library/react';
import useCounter from './useCounter';
test('suurendab loendurit', () => {
const { result } = renderHook(() => useCounter());
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
Selgitus:
- `renderHook`: See funktsioon renderdab Hooki ja tagastab objekti, mis sisaldab Hooki tulemust.
- `act`: Seda funktsiooni kasutatakse mistahes koodi mähkimiseks, mis põhjustab olekuvärskendusi. See tagab, et React suudab värskendusi õigesti pakendada ja töödelda.
Täiustatud testimistehnikad
Kui olete RTL-i põhitõed selgeks saanud, saate uurida täiustatud testimistehnikaid, et parandada oma testide kvaliteeti ja hooldatavust.
Moodulite mockimine
Mõnikord võib teil olla vaja mockida väliseid mooduleid või sõltuvusi, et isoleerida oma komponente ja kontrollida nende käitumist testimise ajal. Jest pakub selleks võimast mockimise API-d.
// src/api/dataService.js
export const fetchData = async () => {
const response = await fetch('/api/data');
const data = await response.json();
return data;
};
// src/components/MyComponent.js
import React, { useState, useEffect } from 'react';
import { fetchData } from '../api/dataService';
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetchData().then(setData);
}, []);
return <div>{data}</div>;
}
// src/components/MyComponent.test.js
import { render, screen, waitFor } from '@testing-library/react';
import MyComponent from './MyComponent';
import * as dataService from '../api/dataService';
jest.mock('../api/dataService');
test('pärib andmeid API-st', async () => {
dataService.fetchData.mockResolvedValue({ message: 'Mocked data!' });
render(<MyComponent />);
await waitFor(() => screen.getByText('Mocked data!'));
expect(screen.getByText('Mocked data!')).toBeInTheDocument();
expect(dataService.fetchData).toHaveBeenCalledTimes(1);
});
Selgitus:
- `jest.mock('../api/dataService')`: See rida mockib `dataService` mooduli.
- `dataService.fetchData.mockResolvedValue({ message: 'Mocked data!' })`: See rida konfigureerib mockitud `fetchData` funktsiooni tagastama Promise'i, mis laheneb määratud andmetega.
- `expect(dataService.fetchData).toHaveBeenCalledTimes(1)`: See rida kinnitab, et mockitud `fetchData` funktsiooni kutsuti üks kord.
Context Providerid
Kui teie komponent sõltub Context Providerist, peate testimise ajal oma komponendi providerisse mähkima. See tagab, et komponendil on juurdepääs contexti väärtustele.
// src/contexts/ThemeContext.js
import React, { createContext, useState } from 'react';
export const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// src/components/MyComponent.js
import React, { useContext } from 'react';
import { ThemeContext } from '../contexts/ThemeContext';
function MyComponent() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<div style={{ backgroundColor: theme === 'light' ? '#fff' : '#000', color: theme === 'light' ? '#000' : '#fff' }}>
<p>Current theme: {theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
}
// src/components/MyComponent.test.js
import { render, screen, fireEvent } from '@testing-library/react';
import MyComponent from './MyComponent';
import { ThemeProvider } from '../contexts/ThemeContext';
test('lülitab teemat', () => {
render(
<ThemeProvider>
<MyComponent />
</ThemeProvider>
);
const themeParagraph = screen.getByText(/Current theme: light/i);
const toggleButton = screen.getByRole('button', { name: /Toggle Theme/i });
expect(themeParagraph).toBeInTheDocument();
fireEvent.click(toggleButton);
expect(screen.getByText(/Current theme: dark/i)).toBeInTheDocument();
});
Selgitus:
- Me mähime `MyComponent`-i `ThemeProvider`-isse, et pakkuda testimise ajal vajalikku contexti.
Routeriga testimine
Kui testite komponente, mis kasutavad React Routerit, peate pakkuma mockitud Routeri contexti. Saate seda saavutada, kasutades `MemoryRouter` komponenti teegist `react-router-dom`.
// src/components/MyComponent.js
import React from 'react';
import { Link } from 'react-router-dom';
function MyComponent() {
return (
<div>
<Link to="/about">Go to About Page</Link>
</div>
);
}
// src/components/MyComponent.test.js
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import MyComponent from './MyComponent';
test('kuvab lingi \'Meist\' lehele', () => {
render(
<MemoryRouter>
<MyComponent />
</MemoryRouter>
);
const linkElement = screen.getByRole('link', { name: /Go to About Page/i });
expect(linkElement).toBeInTheDocument();
expect(linkElement).toHaveAttribute('href', '/about');
});
Selgitus:
- Me mähime `MyComponent`-i `MemoryRouter`-isse, et pakkuda mockitud Routeri contexti.
- Me kinnitame, et lingielemendil on õige `href` atribuut.
Parimad tavad tõhusate testide kirjutamiseks
Siin on mõned parimad tavad, mida järgida RTL-iga testide kirjutamisel:
- Keskenduge kasutajate interaktsioonidele: Kirjutage teste, mis simuleerivad, kuidas kasutajad teie rakendusega suhtlevad.
- Vältige implementatsiooni detailide testimist: Ärge testige oma komponentide sisemist toimimist. Keskenduge selle asemel vaadeldavale käitumisele.
- Kirjutage selgeid ja lühikesi teste: Muutke oma testid kergesti mõistetavaks ja hooldatavaks.
- Kasutage tähendusrikkaid testinimesid: Valige testinimed, mis kirjeldavad täpselt testitavat käitumist.
- Hoidke testid isoleerituna: Vältige testidevahelisi sõltuvusi. Iga test peaks olema iseseisev ja eraldiseisev.
- Testige äärmuslikke juhtumeid: Ärge testige ainult "õnnelikku teed". Veenduge, et testite ka äärmuslikke juhtumeid ja veatingimusi.
- Kirjutage testid enne koodi kirjutamist: Kaaluge testipõhise arenduse (TDD) kasutamist, et kirjutada testid enne koodi kirjutamist.
- Järgige "AAA" mustrit: Arrange (korralda), Act (tegutse), Assert (kinnita). See muster aitab teie teste struktureerida ja muuta need loetavamaks.
- Hoidke oma testid kiired: Aeglased testid võivad heidutada arendajaid neid sageli käivitamast. Optimeerige oma testide kiirust, mockides võrgupäringuid ja minimeerides DOM-i manipuleerimise hulka.
- Kasutage kirjeldavaid veateateid: Kui väited ebaõnnestuvad, peaksid veateated andma piisavalt teavet, et vea põhjus kiiresti tuvastada.
Kokkuvõte
React Testing Library on võimas tööriist tõhusate, hooldatavate ja kasutajakesksete testide kirjutamiseks teie Reacti rakendustele. Järgides selles juhendis toodud põhimõtteid ja tehnikaid, saate luua tugevaid ja usaldusväärseid rakendusi, mis vastavad teie kasutajate vajadustele. Pidage meeles, et keskenduge testimisele kasutaja vaatenurgast, vältige implementatsiooni detailide testimist ning kirjutage selgeid ja lühikesi teste. RTL-i omaks võttes ja parimaid tavasid rakendades saate oluliselt parandada oma Reacti projektide kvaliteeti ja hooldatavust, olenemata teie asukohast või teie globaalse sihtrühma spetsiifilistest nõuetest.