Интеграционное тестирование

Интеграционное тестирование — это важная часть процесса разработки, которая помогает удостовериться, что различные части приложения работают корректно в связке между собой. В контексте фреймворка Svelte, интеграционные тесты проверяют взаимодействие компонентов, их связи с состоянием и правильную работу логики взаимодействия между ними. Вместо того чтобы фокусироваться только на отдельном компоненте или функции, интеграционные тесты охватывают более широкие аспекты, включая обработку событий, асинхронные операции и корректное отображение данных.

Инструменты для тестирования в Svelte

Для интеграционного тестирования в Svelte существует несколько популярных инструментов, включая Jest, Mocha и Testing Library. Однако чаще всего для интеграционного тестирования в Svelte используется @testing-library/svelte, так как он предоставляет удобный API для взаимодействия с DOM и проверки функциональности компонентов на более высоком уровне, чем unit-тесты.

@testing-library/svelte ориентирован на тестирование компонентов так, как их видит пользователь, что позволяет имитировать реальные сценарии использования.

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

Для начала нужно установить необходимые пакеты:

npm install --save-dev @testing-library/svelte jest jest-environment-jsdom

Далее, необходимо настроить Jest, чтобы использовать подходящее окружение для тестов:

{
  "testEnvironment": "jest-environment-jsdom",
  "transform": {
    "^.+\\.svelte$": "jest-transform-svelte"
  }
}

После этого можно начать писать интеграционные тесты с использованием @testing-library/svelte.

Основы работы с @testing-library/svelte

@testing-library/svelte предоставляет несколько методов для тестирования компонентов. Среди них — рендеринг компонента, выбор элементов и взаимодействие с ними, проверка текстового контента, атрибутов и событий.

Для рендеринга компонента используется метод render:

import { render } from '@testing-library/svelte';
import MyComponent from './MyComponent.svelte';

test('компонент рендерится правильно', () => {
  const { getByText } = render(MyComponent);
  expect(getByText('Привет, мир!')).toBeInTheDocument();
});

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

При интеграционном тестировании важно проверять, как компоненты взаимодействуют друг с другом. Например, если компонент вызывает событие, его нужно отловить и проверить корректность работы:

import { render, fireEvent } from '@testing-library/svelte';
import Button from './Button.svelte';
import Counter from './Counter.svelte';

test('клик по кнопке увеличивает счётчик', async () => {
  const { getByText } = render(Counter);
  const button = getByText('Увеличить');
  
  await fireEvent.click(button);
  
  expect(getByText('Счёт: 1')).toBeInTheDocument();
});

Здесь компонент Counter включает в себя кнопку, которая вызывает изменение состояния при каждом клике. Тест проверяет, что состояние компонента обновляется правильно.

Асинхронные операции

Многие современные приложения используют асинхронные операции для загрузки данных с сервера или выполнения других долгих задач. Для таких случаев необходимо проверять, как компоненты ведут себя во время выполнения асинхронных операций. В @testing-library/svelte для этого предусмотрены специальные методы.

Пример:

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

test('отображение данных после загрузки', async () => {
  const { getByText } = render(DataFetcher);

  await waitFor(() => getByText('Данные загружены'));

  expect(getByText('Данные загружены')).toBeInTheDocument();
});

Здесь компонент DataFetcher выполняет асинхронный запрос к API, и тест проверяет, что текст появляется на экране только после успешной загрузки данных.

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

Состояние является неотъемлемой частью любого приложения на Svelte. В интеграционных тестах важно проверять, как состояние компонента изменяется в ответ на действия пользователя или другие события.

Пример использования состояния:

import { render, fireEvent } from '@testing-library/svelte';
import TodoApp from './TodoApp.svelte';

test('добавление нового todo', async () => {
  const { getByPlaceholderText, getByText } = render(TodoApp);
  const input = getByPlaceholderText('Добавить новое дело');
  const button = getByText('Добавить');
  
  await fireEvent.input(input, { target: { value: 'Купить молоко' } });
  await fireEvent.click(button);
  
  expect(getByText('Купить молоко')).toBeInTheDocument();
});

В этом примере компонент TodoApp использует внутреннее состояние для хранения списка задач. Тест проверяет, что новая задача появляется в списке после того, как пользователь введёт текст и нажмёт кнопку.

Работа с контекстом

Svelte имеет встроенную поддержку для использования контекста, который позволяет передавать данные между компонентами, не являющимися прямыми родителями и детьми. Для тестирования таких компонентов можно использовать методы работы с контекстом, чтобы проверить, как данные передаются между компонентами.

Пример работы с контекстом:

import { render, getByText } from '@testing-library/svelte';
import Parent from './Parent.svelte';
import Child from './Child.svelte';

test('передача контекста между компонентами', () => {
  const { getByText } = render(Parent);
  const child = getByText('Данные из контекста');
  
  expect(child).toBeInTheDocument();
});

Здесь компонент Parent передаёт данные в компонент Child через контекст, и тест проверяет, что эти данные отображаются корректно.

Мокирование зависимостей

Иногда компоненты зависят от внешних сервисов или API. Для того чтобы тесты не зависели от реальных данных, можно использовать мокирование. В Jest для этого используется библиотека jest.mock(), которая позволяет заменять реальные функции на моки и проверять их поведение.

Пример:

import { render, fireEvent } from '@testing-library/svelte';
import TodoApp from './TodoApp.svelte';

jest.mock('../services/api', () => ({
  fetchTodos: jest.fn().mockResolvedValue([{ id: 1, text: 'Задача 1' }])
}));

test('загрузка задач с API', async () => {
  const { getByText } = render(TodoApp);
  await fireEvent.click(getByText('Загрузить задачи'));
  
  expect(getByText('Задача 1')).toBeInTheDocument();
});

Здесь мы заменили реальную функцию API на мок, чтобы тестировать компонент, не вызывая реальный запрос к серверу.

Советы по написанию интеграционных тестов

  • Тестируйте взаимодействия, а не реализацию: Сосредоточьтесь на том, как компонент ведёт себя с точки зрения пользователя, а не на внутренней логике его работы.
  • Избегайте чрезмерных моков: Моки полезны, но они могут скрывать проблемы, если их слишком много. Лучше работать с реальными данными, где это возможно.
  • Используйте асинхронные ожидания: Для компонентов, которые выполняют асинхронные операции, всегда используйте await waitFor() или аналогичные функции для синхронизации тестов с завершением асинхронных действий.

Заключение

Интеграционное тестирование в Svelte помогает убедиться, что компоненты правильно взаимодействуют друг с другом и корректно обновляют состояние. Использование библиотеки @testing-library/svelte позволяет легко создавать тесты, которые фокусируются на реальных взаимодействиях пользователя с интерфейсом.