Component Testing Library

Component Testing Library (CTL) предназначена для тестирования отдельных компонентов в SvelteKit, обеспечивая удобный и высокоуровневый API для взаимодействия с DOM и проверки поведения компонентов. В отличие от традиционного unit-тестирования, CTL фокусируется на пользовательском опыте и взаимодействиях, а не на внутренней реализации компонентов.

Установка и настройка

Для интеграции CTL в проект SvelteKit используется следующая команда:

npm install --save-dev @testing-library/svelte @testing-library/jest-dom jest

После установки необходимо настроить окружение для Jest или Vitest, подключив соответствующие адаптеры и расширения для DOM-assertions:

import '@testing-library/jest-dom';

Рендеринг компонентов

Основной функцией является render(). Она позволяет создать виртуальный экземпляр компонента и работать с ним в тестах:

import { render } from '@testing-library/svelte';
import Button from '../src/components/Button.svelte';

test('рендерит кнопку с текстом', () => {
  const { getByText } = render(Button, { props: { label: 'Отправить' } });
  expect(getByText('Отправить')).toBeInTheDocument();
});

Ключевые моменты:

  • render(Component, { props }) — создаёт экземпляр компонента с заданными свойствами.
  • Возвращаемый объект содержит методы поиска элементов: getByText, getByRole, queryByTestId, findByText.
  • Использование jest-dom позволяет делать наглядные утверждения о состоянии элементов: toBeVisible(), toHaveClass(), toHaveAttribute().

Взаимодействие с компонентами

Для имитации действий пользователя используется объект fireEvent или userEvent:

import { fireEvent } from '@testing-library/svelte';

test('обрабатывает клик по кнопке', async () => {
  const { getByText } = render(Button, { props: { label: 'Кликни меня' } });
  const button = getByText('Кликни меня');

  await fireEvent.click(button);

  expect(button).toHaveClass('active');
});

Особенности:

  • fireEvent имитирует события DOM (click, input, change).
  • Асинхронные действия требуют использования await для корректного применения изменений.
  • userEvent предоставляет более реалистичные симуляции пользовательских действий (например, ввод текста через клавиатуру).

Проверка состояния компонента

CTL позволяет тестировать реактивные свойства и состояние компонента без прямого доступа к внутренним переменным:

import Counter from '../src/components/Counter.svelte';

test('увеличивает значение счетчика', async () => {
  const { getByText } = render(Counter);
  
  const incrementButton = getByText('Увеличить');
  const countDisplay = getByText('0');

  await fireEvent.click(incrementButton);
  expect(countDisplay).toHaveTextContent('1');
});

Важные моменты:

  • Проверка текста и атрибутов через toHaveTextContent, toHaveAttribute.
  • Работа с реактивными переменными компонента через визуальный интерфейс, а не через прямой доступ к внутреннему состоянию.
  • CTL поддерживает асинхронные обновления, что особенно важно при работе с await tick() или асинхронными методами внутри Svelte.

Тестирование слотов и вложенных компонентов

SvelteKit активно использует слоты, и Component Testing Library предоставляет удобные способы тестирования вложенного контента:

import Card from '../src/components/Card.svelte';
import { render } from '@testing-library/svelte';

test('рендерит слоты', () => {
  const { getByText } = render(Card, {
    slots: { default: '<p>Контент слота</p>' }
  });

  expect(getByText('Контент слота')).toBeInTheDocument();
});

Особенности:

  • Слот передаётся как HTML-строка в объект slots.
  • Поддерживаются именованные слоты: { header: '<h1>Заголовок</h1>', footer: '<p>Футер</p>' }.
  • Позволяет тестировать динамическую вставку контента без изменения исходного компонента.

Асинхронные компоненты и API-запросы

Компоненты, которые используют onMount или асинхронные данные, требуют особого подхода:

import UserCard from '../src/components/UserCard.svelte';
import { render, waitFor } from '@testing-library/svelte';

test('загружает данные пользователя', async () => {
  const { getByText } = render(UserCard, { props: { userId: 1 } });

  await waitFor(() => getByText('Имя пользователя'));
  expect(getByText('Имя пользователя')).toBeInTheDocument();
});
  • waitFor ожидает изменения DOM до выполнения проверки.
  • Позволяет корректно тестировать асинхронные рендеры и API-запросы.
  • Поддерживает таймауты и проверку ошибок при загрузке данных.

Практические рекомендации

  • Использовать семантические селекторы (getByRole, getByLabelText) вместо querySelector для улучшенной читаемости тестов.
  • Разделять тесты на рендеринг, взаимодействие и состояние, чтобы сохранять структуру и читаемость.
  • Для компонентов с динамическими данными применять waitFor или findBy* методы.
  • Проверять визуальные классы и атрибуты через jest-dom, а не напрямую через element.className.

Интеграция с CI/CD

Тесты на Component Testing Library легко интегрируются с Jest или Vitest, что позволяет запускать их автоматически при сборке проекта:

"scripts": {
  "test": "vitest run"
}
  • Поддерживаются watch-режим и отчёты о покрытии кода.
  • Позволяет отслеживать регрессии в компонентах при изменении UI или логики.

Рекомендованные подходы при масштабировании

  • Выделять тестовые данные и мок-объекты в отдельные файлы.
  • Писать тесты на ключевые взаимодействия, а не на внутренние методы.
  • Использовать CTL для UI-интеграций, а не для unit-тестов логики вне компонента.
  • Создавать вспомогательные функции для часто используемых сценариев (например, рендеринг с пропсами и слотами).

Component Testing Library в SvelteKit обеспечивает удобную и гибкую платформу для проверки компонентов в условиях, максимально приближённых к реальному взаимодействию пользователя с интерфейсом. Она интегрируется с реактивной системой Svelte, поддерживает асинхронные действия и слоты, что делает её идеальной для комплексного тестирования UI.