Пошук уроків, статей та іншого контенту
Познайомитеся з React Testing Library та навчитеся рендерити компоненти в тестовому середовищі.
React Testing Library — це набір інструментів для тестування React-компонентів через їхню поведінку та доступний інтерфейс.
Замість перевірки внутрішнього стану компонента або його реалізації ми перевіряємо те, що бачить і з чим взаємодіє користувач:
заголовки;
кнопки;
поля введення;
текст;
повідомлення;
доступні ролі елементів.
Наприклад, тест має перевіряти, що на сторінці є кнопка «Зберегти», а не те, що компонент викликав певний внутрішній метод.
React Testing Library складається з кількох пакетів. Для тестування React-компонентів потрібні:
npm install --save-dev @testing-library/react @testing-library/jest-dom vitest jsdomУ цьому уроці використовується Vitest як тестовий рушій.
Додайте команду для запуску тестів у package.json:
{
"scripts": {
"test": "vitest"
}
}Для тестування компонентів потрібне середовище jsdom. Воно імітує браузерне DOM-середовище під час запуску тестів у Node.js.
Створимо простий компонент привітання.
Greetingexport function Greeting({ name }) {
return <h1>Привіт, {name}!</h1>;
}Компонент отримує властивість name і відображає заголовок.
Створіть файл Greeting.test.jsx:
/** @vitest-environment jsdom */
import { describe, expect, it } from 'vitest';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/vitest';
import { Greeting } from './Greeting';
describe('Greeting', () => {
it('відображає ім’я користувача', () => {
render(<Greeting name="Олена" />);
const heading = screen.getByRole('heading', {
name: 'Привіт, Олена!'
});
expect(heading).toBeInTheDocument();
});
});Запустіть тест:
npm testVitest знайде файл Greeting.test.jsx, відрендерить компонент і перевірить, чи присутній потрібний заголовок.
renderФункція render відображає React-компонент у тестовому DOM.
render(<Greeting name="Олена" />);Цей виклик створює тестове DOM-дерево, у якому з’являється:
<h1>Привіт, Олена!</h1>render приймає JSX-елемент, тому можна передавати властивості, дочірні компоненти та інші необхідні дані:
render(
<Greeting name="Андрій" />
);Після виклику render компонент уже доступний для пошуку через об’єкт screen.
screenscreen містить методи для пошуку елементів у відрендереному DOM.
Найчастіше використовують:
getByRole — пошук за доступною роллю;
getByText — пошук за текстом;
getByLabelText — пошук поля за його підписом;
getByTestId — пошук за спеціальним атрибутом data-testid.
Найкращий базовий варіант — getByRole.
const heading = screen.getByRole('heading', {
name: 'Привіт, Олена!'
});У цьому прикладі:
heading — роль заголовка;
name — доступна назва заголовка.
Для кнопки можна використати роль button:
const button = screen.getByRole('button', {
name: 'Зберегти'
});Для текстового поля — роль textbox:
const input = screen.getByRole('textbox');Пошук за роллю наближений до того, як користувач або допоміжні технології сприймають сторінку.
Якщо елемент не має зручної ролі або потрібно перевірити звичайний текст, можна використати getByText:
const message = screen.getByText('Дані успішно збережено');Для полів форми з підписом зручно використовувати getByLabelText:
function UserForm() {
return (
<label>
Ім’я
<input type="text" />
</label>
);
}Тест:
render(<UserForm />);
const input = screen.getByLabelText('Ім’я');
expect(input).toBeInTheDocument();Такий пошук перевіряє не лише наявність поля, а й коректний зв’язок між полем та його підписом.
Для перевірок використовується expect.
Наприклад:
expect(heading).toBeInTheDocument();Метод toBeInTheDocument надає пакет @testing-library/jest-dom. Він дозволяє робити перевірки, пов’язані з DOM.
Інші корисні перевірки:
expect(button).toBeVisible();
expect(button).toBeEnabled();
expect(input).toHaveValue('');
expect(message).toHaveTextContent('успішно');Щоб використовувати ці перевірки у Vitest, у тесті потрібно імпортувати:
import '@testing-library/jest-dom/vitest';Компонент із заголовком і повідомленням:
export function Welcome({ userName }) {
return (
<section>
<h1>Вітаємо!</h1>
<p>Раді бачити вас, {userName}.</p>
</section>
);
}Тест:
/** @vitest-environment jsdom */
import { describe, expect, it } from 'vitest';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/vitest';
import { Welcome } from './Welcome';
describe('Welcome', () => {
it('відображає привітання для користувача', () => {
render(<Welcome userName="Марія" />);
expect(
screen.getByRole('heading', { name: 'Вітаємо!' })
).toBeInTheDocument();
expect(
screen.getByText('Раді бачити вас, Марія.')
).toBeInTheDocument();
});
});У цьому тесті ми:
відрендерили Welcome з властивістю userName;
знайшли заголовок за роллю та назвою;
знайшли абзац за його текстом;
перевірили, що обидва елементи є в DOM.
Окрім getBy..., бібліотека має варіанти queryBy... і findBy....
getBy...getBy... використовується для синхронного пошуку елемента.
Якщо елемент не знайдено, тест одразу завершується помилкою.
const heading = screen.getByRole('heading');Це зручно, коли елемент має бути присутнім одразу після рендерингу.
queryBy...queryBy... повертає null, якщо елемент не знайдено.
const errorMessage = screen.queryByText('Сталася помилка');
expect(errorMessage).not.toBeInTheDocument();Цей варіант зручно використовувати, коли потрібно перевірити відсутність елемента.
findBy...findBy... повертає проміс і чекає на появу елемента в DOM. Він потрібен для асинхронних сценаріїв, коли елемент з’являється не відразу.
const result = await screen.findByText('Дані завантажено');
expect(result).toBeInTheDocument();Для простих компонентів, які одразу відображають розмітку, достатньо getBy....
Кожен тест має бути незалежним від інших тестів. React Testing Library зазвичай автоматично очищує DOM після кожного тесту.
Тому в більшості випадків не потрібно вручну писати:
cleanup();Кожен тест має самостійно виконувати render:
it('відображає перше ім’я', () => {
render(<Greeting name="Олена" />);
expect(screen.getByText('Привіт, Олена!')).toBeInTheDocument();
});
it('відображає друге ім’я', () => {
render(<Greeting name="Андрій" />);
expect(screen.getByText('Привіт, Андрій!')).toBeInTheDocument();
});Тести не повинні покладатися на DOM, створений попереднім тестом.
Під час тестування відображення компонента зазвичай виконують такі кроки:
Підготувати вхідні дані.
Відрендерити компонент через render.
Знайти елемент через screen.
Перевірити результат через expect.
it('відображає назву товару', () => {
render(<ProductCard title="Ноутбук" />);
const title = screen.getByRole('heading', {
name: 'Ноутбук'
});
expect(title).toBeInTheDocument();
});Такий підхід робить тест зрозумілим: він описує очікуваний результат, а не внутрішню реалізацію компонента.
renderНеправильно:
const heading = screen.getByRole('heading');
render(<Greeting name="Олена" />);Спочатку потрібно відрендерити компонент:
render(<Greeting name="Олена" />);
const heading = screen.getByRole('heading');Пошук за текстом має відповідати фактичному тексту в DOM:
render(<Greeting name="Олена" />);
screen.getByText('Привіт, Анна!');Такий тест завершиться помилкою, бо компонент відображає інше ім’я.
data-testidАтрибут data-testid можна використовувати як запасний варіант:
<div data-testid="profile">Профіль</div>const profile = screen.getByTestId('profile');Але спочатку варто спробувати знайти елемент за роллю, текстом або підписом. Тести, що використовують доступні властивості елементів, краще відображають реальну взаємодію користувача.
Не потрібно перевіряти, які саме внутрішні змінні або методи використовує компонент. Перевіряйте результат, доступний у DOM:
expect(screen.getByRole('heading')).toHaveTextContent('Вітаємо!');React Testing Library допомагає тестувати компоненти через їхню поведінку в DOM.
render відображає React-компонент у тестовому середовищі.
screen надає методи для пошуку відрендерених елементів.
Для пошуку бажано спочатку використовувати getByRole.
getByText шукає елемент за текстом.
getByLabelText підходить для полів із підписами.
queryBy... зручно використовувати для перевірки відсутності елемента.
findBy... використовується для елементів, які з’являються асинхронно.
Перевірки DOM можна виконувати за допомогою @testing-library/jest-dom.
Кожен тест має самостійно рендерити компонент і перевіряти видимий результат.