Конфигурация для Vue 3 и Vue 2

Vue Test Utils (VTU) является официальной библиотекой для юнит-тестирования компонентов Vue. Она обеспечивает создание обёрток компонентов, доступ к их данным, методам и жизненному циклу, а также симуляцию событий. Несмотря на схожесть API, конфигурация для Vue 3 и Vue 2 имеет свои особенности, которые необходимо учитывать для корректного тестирования.


Установка и подключение

Для Vue 3:

npm install @vue/test-utils@next --save-dev
npm install vue@3

Для Vue 2:

npm install @vue/test-utils --save-dev
npm install vue@2

Важное отличие — для Vue 3 используется пакет @vue/test-utils@next, который поддерживает Composition API и новые методы жизненного цикла.


Создание конфигурации VTU

Глобальная конфигурация позволяет задать общие настройки для всех тестов: плагины, компоненты, директивы, mocks и stubs.

Для Vue 3:

import { config } from '@vue/test-utils'
import MyPlugin from '@/plugins/MyPlugin'

config.global.plugins = [MyPlugin]
config.global.components = {
  'MyButton': MyButton
}
config.global.mocks = {
  $t: (msg) => msg  // mock для i18n
}
config.global.stubs = {
  'router-link': true
}
config.global.directives = {
  focus: {
    mounted(el) {
      el.focus()
    }
  }
}

Для Vue 2 конфигурация немного отличается:

import Vue from 'vue'
import { config } from '@vue/test-utils'
import MyPlugin from '@/plugins/MyPlugin'

Vue.use(MyPlugin)

config.stubs = {
  'router-link': true
}
config.mocks = {
  $t: (msg) => msg
}
config.logModifiedComponents = false

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

  • В Vue 3 глобальные плагины и компоненты подключаются через config.global.
  • В Vue 2 плагины регистрируются через Vue.use(), а глобальные компоненты через Vue.component().
  • Директивы в Vue 2 обычно регистрируются глобально через Vue.directive().

Настройка mount и shallowMount

mount создаёт полноценный экземпляр компонента с рендером всех дочерних компонентов. shallowMount рендерит компонент, но заменяет все дочерние на заглушки (stubs).

Пример для Vue 3:

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

const wrapper = mount(MyComponent, {
  global: {
    plugins: [MyPlugin],
    mocks: { $t: (msg) => msg },
    stubs: ['ChildComponent']
  }
})

const shallowWrapper = shallowMount(MyComponent, {
  global: {
    stubs: ['ChildComponent']
  }
})

Для Vue 2:

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

const wrapper = mount(MyComponent, {
  mocks: { $t: (msg) => msg },
  stubs: ['ChildComponent']
})

const shallowWrapper = shallowMount(MyComponent, {
  stubs: ['ChildComponent']
})

Ключевое отличие: Vue 3 использует объект global для всех глобальных настроек, тогда как Vue 2 напрямую передаёт mocks и stubs в параметры.


Настройка Jest и Vue Test Utils

Для интеграции VTU с Jest требуется корректная настройка:

Vue 3 + Jest:

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'jsdom',
  moduleFileExtensions: ['js', 'json', 'vue'],
  transform: {
    '^.+\\.vue$': '@vue/vue3-jest',
    '^.+\\.js$': 'babel-jest'
  },
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1'
  }
}

Vue 2 + Jest:

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'jsdom',
  moduleFileExtensions: ['js', 'json', 'vue'],
  transform: {
    '^.+\\.vue$': 'vue-jest',
    '^.+\\.js$': 'babel-jest'
  },
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1'
  }
}

Отличия трансформеров:

  • Для Vue 3 используется @vue/vue3-jest, поддерживающий Composition API.
  • Для Vue 2 используется vue-jest, совместимый с Options API.

Использование mocks и provide/inject

Mocks позволяют подменять глобальные свойства, такие как $router, $store, $axios.

Vue 3:

const wrapper = mount(MyComponent, {
  global: {
    mocks: {
      $store: { state: { count: 0 }, commit: jest.fn() }
    },
    provide: {
      api: { fetchData: jest.fn() }
    }
  }
})

Vue 2:

const wrapper = mount(MyComponent, {
  mocks: {
    $store: { state: { count: 0 }, commit: jest.fn() }
  },
  provide: {
    api: { fetchData: jest.fn() }
  }
})

Замечание: в Vue 3 provide и inject полностью интегрированы с Composition API, что упрощает тестирование зависимостей.


Статические и динамические stubs

Stubs позволяют заменить дочерние компоненты на заглушки:

Vue 3:

shallowMount(MyComponent, {
  global: {
    stubs: {
      'ChildComponent': { template: '<div class="stub"></div>' },
      'AnotherChild': true  // автоматическая заглушка
    }
  }
})

Vue 2:

shallowMount(MyComponent, {
  stubs: {
    'ChildComponent': { template: '<div class="stub"></div>' },
    'AnotherChild': true
  }
})

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

  • Vue 3 позволяет использовать объектные stubs с полной кастомизацией.
  • Vue 2 поддерживает аналогичный синтаксис, но сложные stubs с Composition API могут работать нестабильно.

Конфигурация жизненного цикла и асинхронных обновлений

Vue Test Utils автоматически обрабатывает жизненный цикл компонента:

  • mount и shallowMount вызывают beforeMount, mounted.
  • Обновления через wrapper.setData, wrapper.setProps синхронизируются с DOM через nextTick.

Пример для Vue 3:

await wrapper.setProps({ visible: true })
await wrapper.vm.$nextTick()
expect(wrapper.text()).toContain('Контент')

Vue 2:

wrapper.setProps({ visible: true })
await wrapper.vm.$nextTick()
expect(wrapper.text()).toContain('Контент')

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

Для Vue 3:

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

let wrapper: VueWrapper<any>
wrapper = mount(MyComponent)

Vue 2:

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

let wrapper: Wrapper<Vue>
wrapper = mount(MyComponent)

Отличие: в Vue 3 используется VueWrapper, а в Vue 2 — Wrapper<Vue>.


Настройка snapshots

VTU позволяет создавать снимки компонентов для отслеживания изменений разметки:

const wrapper = mount(MyComponent)
expect(wrapper.html()).toMatchSnapshot()

Snapshot-тесты одинаковы для Vue 2 и Vue 3, однако формат HTML в Vue 3 может отличаться из-за нового рендера.


Эта конфигурация обеспечивает гибкое и детализированное тестирование как для Vue 3, так и для Vue 2, учитывая различия в глобальных настройках, плагинах, stubs и mocks. Она создаёт основу для надёжных юнит-тестов с интеграцией в Jest или другие тестовые среды.