Eesti

Õ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:

Testimiskeskkonna seadistamine

Enne RTL-i kasutama hakkamist peate seadistama oma testimiskeskkonna. See hõlmab tavaliselt vajalike sõltuvuste installimist ja testimisraamistiku konfigureerimist.

Eeltingimused

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:

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:

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:

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:

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:

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:

Parimad tavad tõhusate testide kirjutamiseks

Siin on mõned parimad tavad, mida järgida RTL-iga testide kirjutamisel:

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.