Порядок выполнения хуков при монтировании

В Vue.js жизненный цикл компонента строго регламентирован. Понимание порядка вызова хуков жизненного цикла критично для корректного тестирования с использованием Vue Test Utils. Монтирование компонента в тестовой среде практически идентично реальному процессу в приложении, но имеет особенности, влияющие на доступность данных и рендеринг.


1. Основные хуки жизненного цикла

Vue.js определяет следующие хуки, участвующие в процессе монтирования:

  1. beforeCreate Вызывается сразу после инициализации экземпляра Vue. На этом этапе реактивность данных ещё не настроена, а data, computed, props и методы недоступны.

  2. created Инициализация реактивных свойств завершена, доступны data, props, методы и вычисляемые свойства. DOM ещё не создан, поэтому доступ к $el невозможен.

  3. beforeMount Хук вызывается перед монтированием в DOM. В тестовой среде это момент перед тем, как компонент будет реально «привязан» к виртуальному DOM.

  4. mounted Срабатывает после монтирования компонента. В этот момент $el доступен, можно выполнять операции, связанные с реальным DOM.

  5. beforeUpdate и updated Эти хуки не относятся напрямую к первичному монтированию, но важны при повторных обновлениях компонента в тестах.


2. Монтирование через Vue Test Utils

Для тестирования Vue-компонентов используется функция mount или shallowMount из Vue Test Utils. Их задача — создать экземпляр компонента, смонтировать его и вернуть объект-обёртку (wrapper), через который происходит взаимодействие с компонентом.

Пример базового монтирования:

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

const wrapper = mount(MyComponent)

При таком вызове последовательность хуков будет следующей:

  1. beforeCreate
  2. created
  3. beforeMount
  4. mounted

Если в компоненте определён дочерний компонент, его монтирование произойдёт рекурсивно, соблюдая тот же порядок для каждого дочернего компонента.


3. Особенности порядка вызова при тестировании

  1. Асинхронные операции в mounted Если в mounted выполняются асинхронные задачи (например, API-запрос через axios), монтирование завершено, но данные ещё не обновлены. Для тестов нужно использовать await nextTick():

    import { nextTick } from 'vue'
    
    await nextTick()
    expect(wrapper.text()).toContain('Загруженные данные')
  2. Псевдо-DOM и JSDOM При запуске тестов через Jest или Vitest компонент монтируется в виртуальном DOM (JSDOM). $el существует, но методы, связанные с реальным браузером (например, getBoundingClientRect), требуют мокирования.

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


4. Логирование порядка хуков

Для наглядного контроля последовательности можно добавить консольный вывод в каждый хук:

export default {
  name: 'MyComponent',
  data() { return { count: 0 } },
  beforeCreate() { console.log('beforeCreate') },
  created() { console.log('created') },
  beforeMount() { console.log('beforeMount') },
  mounted() { console.log('mounted') }
}

При запуске теста через mount вывод будет:

beforeCreate
created
beforeMount
mounted

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


5. Влияние props и слотов на порядок

  • Props устанавливаются до created, поэтому их значения доступны в хуке created.
  • Слоты рендерятся до mounted. Если компонент зависит от слотов для вычислений, их нужно передавать в тесте при монтировании:
const wrapper = mount(MyComponent, {
  slots: { default: '<div>Слот</div>' }
})
  • v-if и динамические компоненты могут влиять на вызов mounted дочерних компонентов. Если условие v-if изначально false, mounted дочернего компонента не вызовется.

6. Рекомендации по тестированию

  • Проверять изменения данных лучше после nextTick, чтобы убедиться, что Vue завершил реактивное обновление.
  • Для тестирования взаимодействий, зависящих от DOM, использовать mounted и выше.
  • Для тестов на изоляцию дочерних компонентов — использовать shallowMount, чтобы исключить рекурсивное монтирование.
  • Асинхронные хуки (async mounted) требуют ожидания завершения промисов перед проверкой состояния компонента.

7. Сводная таблица последовательности

Хук Доступность data/props Доступность DOM
beforeCreate нет нет
created да нет
beforeMount да нет
mounted да да

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