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

Vue Test Utils (VTU) — официальный инструмент для тестирования компонентов Vue. Одной из ключевых задач при тестировании является проверка поведения компонентов во время их жизненного цикла. Хук onMounted используется для выполнения логики сразу после монтирования компонента. Тестирование кода внутри onMounted требует особого подхода, так как эта логика выполняется автоматически при монтировании компонента.

Основные принципы работы onMounted

onMounted вызывается один раз после того, как компонент был вставлен в DOM. Обычно внутри него выполняются:

  • Загрузка данных с сервера.
  • Инициализация сторонних библиотек.
  • Подписка на события.
  • Изменение локального состояния компонента.

Проверка этих действий в тестах требует контроля над асинхронными процессами и имитации внешних зависимостей.

Монтирование компонентов для тестирования

В VTU существует несколько способов монтирования компонентов:

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

const wrapper = mount(MyComponent);
  • mount полностью рендерит компонент с дочерними компонентами.
  • shallowMount рендерит компонент без дочерних компонентов, заменяя их заглушками. Этот метод полезен для изоляции логики onMounted и сокращения времени тестов.

Тестирование синхронной логики внутри onMounted

Если в onMounted выполняется синхронный код, проверка заключается в проверке состояния после монтирования:

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

test('увеличивает count при монтировании', () => {
  const wrapper = mount(Counter);
  expect(wrapper.vm.count).toBe(1);
});

В данном примере onMounted увеличивает значение count. После монтирования состояние компонента сразу доступно для проверки.

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

Асинхронный код внутри onMounted — например, запросы к API — требует использования nextTick или flushPromises для ожидания завершения всех асинхронных операций:

import { mount } from '@vue/test-utils';
import flushPromises from 'flush-promises';
import UserList from '@/components/UserList.vue';
import axios from 'axios';

jest.mock('axios');

test('загружает список пользователей при монтировании', async () => {
  axios.get.mockResolvedValue({ data: [{ id: 1, name: 'Alice' }] });
  
  const wrapper = mount(UserList);
  
  await flushPromises(); // Ожидание завершения промисов внутри onMounted
  
  expect(wrapper.vm.users).toEqual([{ id: 1, name: 'Alice' }]);
});

flushPromises позволяет дождаться всех отложенных промисов, которые были созданы в onMounted, что делает тест стабильным и предсказуемым.

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

Логика onMounted часто зависит от внешних сервисов. Для изоляции компонента необходимо мокировать эти зависимости:

import { mount } from '@vue/test-utils';
import AnalyticsButton from '@/components/AnalyticsButton.vue';
import analytics from '@/services/analytics';

jest.mock('@/services/analytics');

test('вызывает метод analytics.track при монтировании', () => {
  mount(AnalyticsButton);
  expect(analytics.track).toHaveBeenCalledWith('component_mounted');
});

Мокирование позволяет тестировать компонент без реального подключения к внешним API, что ускоряет тесты и делает их независимыми от состояния сервера.

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

Иногда onMounted изменяет DOM напрямую, например добавляет класс или устанавливает фокус. Для проверки изменений DOM используется wrapper.find и wrapper.classes():

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

test('устанавливает фокус на input при монтировании', () => {
  const wrapper = mount(FocusInput, { attachTo: document.body });
  
  const input = wrapper.find('input').element;
  
  expect(document.activeElement).toBe(input);
});

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

Проверка побочных эффектов

onMounted может запускать побочные эффекты, например подписки на события через window.addEventListener. В тестах такие эффекты можно проверять через мокированные функции:

test('подписка на событие resize при монтировании', () => {
  const addEventListenerSpy = jest.spyOn(window, 'addEventListener');
  
  mount(MyComponent);
  
  expect(addEventListenerSpy).toHaveBeenCalledWith('resize', expect.any(Function));
  
  addEventListenerSpy.mockRestore();
});

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

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

  • Каждую отдельную логику внутри onMounted следует тестировать отдельным тестом.
  • Для асинхронного кода использовать async/await и flushPromises.
  • Мокировать все внешние зависимости, чтобы тесты оставались изолированными.
  • Проверять не только состояние vm, но и DOM и вызовы внешних функций при необходимости.

Тщательное тестирование onMounted обеспечивает уверенность, что компоненты корректно инициализируются и ведут себя предсказуемо при монтировании, независимо от внешних сервисов и асинхронных операций.