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

Unit тестирование в Polymer ориентировано на проверку отдельных веб-компонентов, их логики и взаимодействий с DOM без зависимости от внешней среды. Важной особенностью является то, что тестируемый компонент должен быть изолированным, чтобы тесты оставались стабильными и предсказуемыми.

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

Для тестирования компонентов в Polymer чаще всего используют Karma как тест-раннер и Mocha/Chai для описания тестов и утверждений. Установка и настройка включает следующие шаги:

npm install --save-dev karma karma-mocha karma-chai karma-chrome-launcher
npm install --save-dev @web/test-runner @web/test-runner-mocha

Конфигурация Karma (karma.conf.js) обычно выглядит так:

module.exports = function(config) {
  config.set({
    frameworks: ['mocha', 'chai'],
    files: [
      { pattern: 'src/**/*.js', type: 'module' },
      { pattern: 'test/**/*.spec.js', type: 'module' }
    ],
    browsers: ['ChromeHeadless'],
    singleRun: true
  });
};

Для проектов на Polymer 3 используется модульная система ES6, поэтому все файлы подключаются через type: 'module'.

Структура unit теста

Unit тест в Polymer обычно включает следующие элементы:

  • Импорт тестируемого компонента
  • Создание экземпляра компонента
  • Добавление компонента в DOM для тестирования
  • Проверка состояния и поведения через утверждения

Пример простого теста для компонента <my-element>:

import { fixture, html } from '@open-wc/testing';
import './my-element.js';

describe('MyElement', () => {
  let element;

  beforeEach(async () => {
    element = await fixture(html`<my-element></my-element>`);
  });

  it('должен иметь дефолтное свойство message', () => {
    chai.expect(element.message).to.equal('Hello Polymer');
  });

  it('должен отображать сообщение в DOM', () => {
    const span = element.shadowRoot.querySelector('span');
    chai.expect(span.textContent).to.equal('Hello Polymer');
  });

  it('должен менять сообщение при вызове метода updateMessage', async () => {
    element.updateMessage('New Message');
    await element.updateComplete;
    chai.expect(element.message).to.equal('New Message');
  });
});

Ключевым моментом здесь является использование fixture из библиотеки @open-wc/testing, которое создаёт компонент и автоматически добавляет его в DOM, включая Shadow DOM.

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

Polymer использует реактивные свойства с автоматическим обновлением DOM. Unit тесты должны проверять, что изменение свойств приводит к ожидаемым изменениям интерфейса:

it('должен реагировать на изменение свойства count', async () => {
  element.count = 5;
  await element.updateComplete;
  const div = element.shadowRoot.querySelector('.count-display');
  chai.expect(div.textContent).to.equal('5');
});

Использование await element.updateComplete гарантирует, что все асинхронные обновления Shadow DOM завершены перед проверкой.

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

Компоненты Polymer часто взаимодействуют через события. Unit тест должен проверять правильность их генерации:

it('должен генерировать событие custom-event', (done) => {
  element.addEventListener('custom-event', (e) => {
    chai.expect(e.detail).to.deep.equal({ value: 42 });
    done();
  });
  element.triggerEvent();
});

Метод done() нужен для асинхронного завершения теста при работе с событиями.

Моки и стабы

Для изоляции компонента от внешних зависимостей применяются моки и стабы. Например, если компонент делает fetch-запрос:

import sinon from 'sinon';

it('должен получать данные с сервера', async () => {
  const fakeResponse = { data: 'test' };
  const fetchStub = sinon.stub(window, 'fetch').resolves({
    json: async () => fakeResponse
  });

  await element.loadData();
  chai.expect(element.data).to.deep.equal(fakeResponse);

  fetchStub.restore();
});

Стаб позволяет полностью контролировать поведение внешних вызовов, не создавая реальных сетевых запросов.

Покрытие тестами

Unit тестирование должно обеспечивать проверку:

  • Инициализации свойств и состояния компонента
  • Реактивности и обновления DOM
  • Генерации событий и их правильного содержания
  • Обработки ошибок и нестандартных входных данных
  • Взаимодействия с внешними API через моки

Высокое покрытие кода тестами гарантирует, что изменения в логике компонента не сломают существующий функционал.

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

  • Каждый компонент имеет отдельный файл теста с расширением .spec.js
  • Тесты структурируются по функциональности: свойства, DOM, события, методы
  • Асинхронные операции должны дожидаться завершения через await updateComplete или колбэки done()
  • Использовать beforeEach и afterEach для создания и очистки компонентов, чтобы исключить влияние состояния предыдущих тестов

Unit тестирование в Polymer является фундаментальным инструментом для поддержания надежности компонентов, особенно в больших приложениях с множеством кастомных элементов. Правильная изоляция, проверка реактивности и событий делает тесты стабильными и предсказуемыми, что облегчает дальнейшее сопровождение и масштабирование проекта.