Зачем тестировать компоненты Vue

Тестирование компонентов Vue обеспечивает надёжность приложения, упрощает сопровождение кода и снижает вероятность регрессий. Vue Test Utils — официальная библиотека для unit-тестирования компонентов Vue, предоставляющая инструменты для рендеринга, взаимодействия и проверки состояния компонентов.

Монтирование компонентов

Базовая операция в Vue Test Utils — монтирование компонента. Для этого используется функция mount:

import { mount } from '@vue/test-utils';
import MyComponent from '@/components/MyComponent.vue';

const wrapper = mount(MyComponent);

mount создаёт полноценный экземпляр компонента, включая шаблон, логику и дочерние компоненты. Для более лёгких тестов можно использовать shallowMount, который рендерит компонент, но подменяет дочерние компоненты заглушками, что ускоряет тесты и снижает сложность.

import { shallowMount } from '@vue/test-utils';
const wrapper = shallowMount(MyComponent);

Проверка рендеринга

После монтирования проверяется корректность отображения компонентов. Основные методы:

  • wrapper.text() — возвращает текстовое содержимое компонента.
  • wrapper.html() — возвращает полный HTML-код компонента.
  • wrapper.find(selector) — находит первый элемент по селектору.
  • wrapper.findAll(selector) — возвращает массив найденных элементов.

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

const wrapper = mount(MyComponent);
expect(wrapper.find('button').text()).toBe('Нажми меня');

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

Vue Test Utils позволяет симулировать пользовательские действия: клики, ввод текста, события.

const wrapper = mount(MyComponent);
await wrapper.find('input').setValue('Тест');
await wrapper.find('form').trigger('submit.prevent');

expect(wrapper.emitted('submit')[0]).toEqual(['Тест']);
  • setValue(value) изменяет значение инпута и триггерит событие input.
  • trigger(event) вызывает событие на элементе.
  • wrapper.emitted() позволяет проверить, были ли сгенерированы события, и их payload.

Работа с props и data

Тестирование компонентов часто требует передачи props или установки состояния data:

const wrapper = mount(MyComponent, {
  props: { title: 'Заголовок' },
  data() { return { count: 5 } }
});

expect(wrapper.text()).toContain('Заголовок');
expect(wrapper.vm.count).toBe(5);

wrapper.vm предоставляет доступ к экземпляру Vue, что позволяет проверять методы, вычисляемые свойства и внутреннее состояние.

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

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

const wrapper = mount(MyComponent, {
  slots: {
    default: '<span class="slot-content">Контент слота</span>'
  }
});

expect(wrapper.find('.slot-content').exists()).toBe(true);

Можно передавать несколько слотов, именованные и динамические, что позволяет полностью проверять поведение компонента при различных вариациях контента.

Проверка реактивности

Vue Test Utils позволяет убедиться, что компонент реагирует на изменения props и данных:

wrapper.setProps({ title: 'Новый заголовок' });
await wrapper.vm.$nextTick();

expect(wrapper.text()).toContain('Новый заголовок');

setProps обновляет свойства компонента, а await wrapper.vm.$nextTick() гарантирует, что все реактивные обновления завершены перед проверкой.

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

Для unit-тестов важно изолировать компонент, подменяя зависимости, такие как Vuex, Vue Router или сторонние сервисы:

const wrapper = mount(MyComponent, {
  global: {
    mocks: {
      $t: (msg) => msg // пример мокирования функции перевода
    }
  }
});

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

Снимки (Snapshot testing)

Снимки фиксируют структуру HTML компонента и используются для обнаружения неожиданных изменений:

expect(wrapper.html()).toMatchSnapshot();

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

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

Компоненты часто содержат асинхронные методы, API-запросы или таймеры. Vue Test Utils поддерживает тестирование асинхронного кода через async/await и Jest таймеры:

await wrapper.vm.fetchData();
await wrapper.vm.$nextTick();

expect(wrapper.text()).toContain('Данные загружены');

Асинхронные события и обновления состояния требуют ожидания nextTick или использования flushPromises, чтобы убедиться, что DOM обновлён.

Отслеживание методов и вычисляемых свойств

Методы компонента можно шпионить через Jest:

const spy = jest.spyOn(MyComponent.methods, 'calculate');
const wrapper = mount(MyComponent);

wrapper.vm.calculate();
expect(spy).toHaveBeenCalled();

Вычисляемые свойства проверяются через доступ к wrapper.vm:

expect(wrapper.vm.fullName).toBe('Иван Иванов');

Интеграция с Jest

Vue Test Utils тесно интегрируется с Jest, предоставляя мощные возможности для:

  • проверки событий (emitted)
  • мокирования модулей и функций (jest.mock)
  • таймеров и асинхронного кода (jest.useFakeTimers, flushPromises)

Организация тестов

Обычная структура unit-тестов включает:

  1. Монтирование компонента (mount или shallowMount).
  2. Проверку рендеринга и структуры DOM.
  3. Симуляцию действий пользователя.
  4. Проверку реактивности и состояния.
  5. Валидацию событий и методов.
  6. Тестирование слотов и props.

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