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

Подходы к тестированию

В экосистеме Svelte компоненты представляют собой изолированные единицы интерфейса, что делает их тестирование более предсказуемым и модульным. В сочетании с Carbon Components Svelte необходимо учитывать специфические особенности: реактивность, слоты, события и стилизацию через SCSS-классы библиотеки.

Существует несколько уровней тестирования:

  1. Юнит-тестирование — проверка отдельного компонента без взаимодействия с внешними зависимостями. Для Svelte используется библиотека @testing-library/svelte.
  2. Интеграционное тестирование — проверка взаимодействия нескольких компонентов между собой, например, формы с кнопками и выпадающими списками.
  3. End-to-End (E2E) тестирование — симуляция поведения пользователя в браузере. Используются Cypress или Playwright.

Настройка окружения

Для корректного тестирования компонентов Carbon Components Svelte требуется:

  • Node.js версии не ниже 18
  • SvelteKit или Vite для сборки проекта
  • Установка зависимостей:
npm install --save-dev @testing-library/svelte @testing-library/jest-dom jest
npm install carbon-components-svelte
  • Настройка jest.config.js с поддержкой Svelte:
module.exports = {
  transform: {
    '^.+\\.svelte$': ['svelte-jester', { preprocess: true }],
    '^.+\\.js$': 'babel-jest',
  },
  moduleFileExtensions: ['js', 'svelte'],
  setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],
};

Юнит-тестирование компонентов

Юнит-тесты проверяют корректность рендеринга и работы событий. Для примера рассмотрим компонент Button из Carbon Components Svelte.

Тест рендеринга кнопки:

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

test('рендеринг кнопки с текстом', () => {
  const { getByText } = render(Button, { props: { text: 'Нажми меня' } });
  expect(getByText('Нажми меня')).toBeInTheDocument();
});

Тест обработки события click:

test('обработка клика по кнопке', async () => {
  const handleClick = jest.fn();
  const { getByText } = render(Button, { props: { text: 'Клик', onClick: handleClick } });
  
  const button = getByText('Клик');
  await fireEvent.click(button);
  
  expect(handleClick).toHaveBeenCalledTimes(1);
});

Тестирование слотов и реактивных свойств

Компоненты Carbon Components Svelte часто используют слоты и реактивные переменные. Например, Modal:

<Modal bind:open>
  <h2 slot="heading">Заголовок модального окна</h2>
  <p>Содержимое модального окна</p>
</Modal>

Тестирование слота:

import { render } from '@testing-library/svelte';
import Modal from 'carbon-components-svelte/Modal.svelte';

test('рендер слота heading', () => {
  const { getByText } = render(Modal, { slots: { heading: '<h2>Заголовок</h2>' } });
  expect(getByText('Заголовок')).toBeInTheDocument();
});

Тестирование реактивного свойства open:

test('открытие и закрытие модального окна', async () => {
  const { component } = render(Modal, { props: { open: false } });
  
  component.$set({ open: true });
  expect(component.open).toBe(true);
  
  component.$set({ open: false });
  expect(component.open).toBe(false);
});

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

Интеграционные тесты проверяют работу нескольких компонентов вместе. Например, форма с кнопкой и селектом:

<Form>
  <Sel ect options={['Option 1', 'Option 2']} bind:value={selected} />
  <Button text="Отправить" on:click={submitForm} />
</Form>

Тестирование последовательности действий:

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

test('выбор опции и отправка формы', async () => {
  const { getByText, getByRole } = render(FormWrapper);
  
  const sel ect = getByRole('combobox');
  await fireEvent.change(select, { target: { value: 'Option 2' } });
  expect(sel ect.value).toBe('Option 2');
  
  const button = getByText('Отправить');
  await fireEvent.click(button);
  
  expect(someSubmitHandler).toHaveBeenCalled();
});

Проверка стилей и классов

Carbon Components Svelte активно использует классы из библиотеки carbon-components. Для проверки применяемых классов:

import { render } fr om '@testing-library/svelte';
import Button fr om 'carbon-components-svelte/Button.svelte';

test('проверка применяемого класса', () => {
  const { getByText } = render(Button, { props: { text: 'Кнопка', kind: 'primary' } });
  const button = getByText('Кнопка');
  expect(button).toHaveClass('bx--btn--primary');
});

Эмуляция пользовательских событий

Для сложных компонентов, таких как DataTable, требуется имитировать клики по строкам, сортировку и фильтры:

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

test('сортировка столбца', async () => {
  const { getByText } = render(DataTable, { props: { headers, rows } });
  const header = getByText('Имя');
  
  await fireEvent.click(header);
  expect(rows[0].name).toBe('Алексей'); // проверка отсортированного значения
});

Рекомендации по организации тестов

  • Каждый компонент тестировать в отдельном файле ComponentName.test.js.
  • Использовать mock-функции для внешних обработчиков событий.
  • Проверять как визуальное отображение (рендеринг), так и реактивное поведение.
  • Включать проверки классов и слотов для компонентов Carbon, чтобы избежать регрессий при обновлениях библиотеки.

Тщательное тестирование компонентов Carbon Components Svelte обеспечивает стабильность UI, минимизирует баги и гарантирует корректное поведение интерфейса в разных сценариях.