Модульное тестирование

SkateJS — это современная библиотека для создания веб-компонентов на основе стандартов Web Components. Она предоставляет удобный API для декларативного описания компонентов, работы с их состоянием и жизненным циклом. Модульное тестирование в контексте SkateJS играет ключевую роль в обеспечении стабильности и предсказуемого поведения компонентов.

Структура компонента

Компонент в SkateJS создается с помощью функции skate, которая принимает объект с настройками:

import { skate } from 'skatejs';

skate('my-element', {
  props: {
    title: String
  },
  render({ title }, { element }) {
    element.textContent = title;
  }
});

Ключевые элементы компонента для тестирования:

  • props — свойства компонента, на которые можно воздействовать в тестах для проверки реактивности.
  • render — функция рендеринга, которая обновляет DOM элемента при изменении состояния.
  • lifecycle hooks — методы connectedCallback, disconnectedCallback, updated, которые позволяют тестировать жизненный цикл компонента.

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

Для модульного тестирования SkateJS компонентов обычно используют:

  • Jest — популярный тест-раннер с возможностью мокирования.
  • @testing-library/dom и @testing-library/jest-dom — для удобного взаимодействия с DOM и проверки состояния элементов.
  • jsdom — виртуальный DOM, позволяющий запускать тесты вне браузера.

Пример базовой конфигурации с Jest и jsdom:

// jest.config.js
module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect']
};

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

Свойства компонента в SkateJS являются реактивными. Для проверки их влияния на DOM можно использовать следующий подход:

import { skate } from 'skatejs';
import '@testing-library/jest-dom';
import { screen } from '@testing-library/dom';

skate('my-element', {
  props: { title: String },
  render({ title }, { element }) {
    element.textContent = title;
  }
});

test('компонент корректно обновляет текст при изменении свойства', () => {
  const el = document.createElement('my-element');
  document.body.appendChild(el);
  el.title = 'Привет';
  expect(el).toHaveTextContent('Привет');
  el.title = 'Мир';
  expect(el).toHaveTextContent('Мир');
});

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

  • Свойства должны быть объявлены через props, иначе реактивность не срабатывает.
  • Изменения props автоматически вызывают render, что упрощает проверку отображения.

Тестирование событий

SkateJS поддерживает работу с событиями через стандартный DOM API. Проверка событий позволяет убедиться, что компонент корректно взаимодействует с внешним окружением:

test('компонент генерирует событие при клике', () => {
  const el = document.createElement('my-element');
  document.body.appendChild(el);

  const handler = jest.fn();
  el.addEventListener('custom-event', handler);

  el.dispatchEvent(new CustomEvent('custom-event'));
  expect(handler).toHaveBeenCalled();
});

Рекомендации:

  • Использовать CustomEvent для пользовательских событий.
  • Проверять вызовы обработчиков через jest.fn() или аналогичные функции-моки.

Тестирование жизненного цикла

SkateJS предоставляет несколько хуков жизненного цикла, которые можно тестировать отдельно:

skate('lifecycle-element', {
  connected() {
    this._connectedCalled = true;
  },
  disconnected() {
    this._disconnectedCalled = true;
  }
});

test('проверка connectedCallback и disconnectedCallback', () => {
  const el = document.createElement('lifecycle-element');
  expect(el._connectedCalled).toBeUndefined();
  document.body.appendChild(el);
  expect(el._connectedCalled).toBe(true);
  document.body.removeChild(el);
  expect(el._disconnectedCalled).toBe(true);
});

Особенности тестирования жизненного цикла:

  • connectedCallback срабатывает при вставке элемента в DOM.
  • disconnectedCallback срабатывает при удалении элемента.
  • Для обновлений состояния используется updated, который можно тестировать через изменение props.

Изоляция тестов

Для модульного тестирования важно избегать зависимости компонентов друг от друга. В SkateJS это достигается:

  • Использованием чистых функций в render.
  • Мокированием сторонних библиотек и сервисов.
  • Очисткой DOM между тестами:
afterEach(() => {
  document.body.innerHTML = '';
});

Проверка асинхронных обновлений

Некоторые компоненты могут обновляться асинхронно, например, при использовании requestAnimationFrame или Promise. Для таких случаев:

test('асинхронное обновление DOM', async () => {
  const el = document.createElement('my-element');
  document.body.appendChild(el);
  el.title = 'Новый текст';
  await new Promise(resolve => setTimeout(resolve, 0));
  expect(el).toHaveTextContent('Новый текст');
});

Использование await или act() из @testing-library/react (в случае интеграции) позволяет корректно проверять изменения DOM.

Стратегии тестирования

  • Тестирование единичного свойства — проверка реактивного поведения props.
  • Тестирование событий — проверка генерации и обработки событий.
  • Тестирование рендера — проверка правильности отображения контента.
  • Тестирование жизненного цикла — проверка connected/disconnected/updated.

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