Структура простого теста

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

Структура теста строится вокруг трёх опорных элементов:

  • окружение тестирования,
  • монтирование компонента,
  • утверждения (assertions).

Файл теста и соглашения

Тесты располагаются рядом с компонентами или в отдельной директории tests. На практике чаще используется структура:

components/
  Button.vue
tests/
  Button.spec.js

Файл теста почти всегда имеет суффикс .spec.js или .test.js. Это соглашение используется тестовыми раннерами (Jest, Vitest) для автоматического обнаружения тестов.


Импорты и базовое окружение

Минимальный тест начинается с импорта функций Vue Test Utils и тестируемого компонента:

import { mount } from '@vue/test-utils'
import Button from '@/components/Button.vue'
  • mount — полностью монтирует компонент со всеми дочерними компонентами.
  • компонент импортируется напрямую, без промежуточных обёрток.

Дополнительно может импортироваться тестовый раннер:

import { describe, it, expect } from 'vitest'

Контейнер describe

Каждый файл теста организуется вокруг блока describe:

describe('Button.vue', () => {
  // тесты
})

describe:

  • логически группирует тесты одного компонента;
  • формирует читаемую иерархию отчётов;
  • не выполняет проверок сам по себе.

Название блока обычно совпадает с именем компонента.


Минимальный тест: проверка рендера

Простейший тест проверяет, что компонент вообще монтируется:

it('рендерится без ошибок', () => {
  const wrapper = mount(Button)
  expect(wrapper.exists()).toBe(true)
})

Структура теста всегда одинакова:

  1. Подготовка — создание wrapper.
  2. Действие — опционально.
  3. Проверка — вызов expect.

Wrapper как центр теста

wrapper — объект-обёртка над экземпляром компонента. Через него осуществляется весь контроль:

  • доступ к DOM,
  • доступ к props,
  • доступ к состоянию,
  • эмуляция событий.

Пример базовых возможностей:

wrapper.text()
wrapper.html()
wrapper.find('button')
wrapper.classes()

wrapper создаётся на каждый тест, чтобы исключить утечки состояния.


Передача props

Большинство компонентов зависят от входных данных. Props передаются при монтировании:

const wrapper = mount(Button, {
  props: {
    label: 'Отправить'
  }
})

Проверка результата:

expect(wrapper.text()).toContain('Отправить')

Изменение props после монтирования:

await wrapper.setProps({ label: 'Сохранить' })

Асинхронность обязательна, так как Vue обновляет DOM не мгновенно.


Поиск элементов

Vue Test Utils предоставляет методы поиска:

wrapper.find('button')
wrapper.find('.primary')
wrapper.find('[data-test="submit"]')

Корректный подход — использовать data-test атрибуты:

<button data-test="submit">OK</button>
wrapper.find('[data-test="submit"]')

Такой способ не зависит от верстки и классов.


Проверка содержимого

Типичные утверждения для DOM:

expect(wrapper.text()).toBe('OK')
expect(wrapper.find('button').exists()).toBe(true)
expect(wrapper.findAll('li')).toHaveLength(3)

Для классов:

expect(wrapper.classes()).toContain('active')

Для атрибутов:

expect(wrapper.attributes('disabled')).toBeDefined()

Работа с событиями

События инициируются через trigger:

await wrapper.find('button').trigger('click')

После этого проверяется результат:

  • изменение DOM,
  • изменение состояния,
  • эмит события.

Проверка эмита:

expect(wrapper.emitted()).toHaveProperty('click')

Или с аргументами:

expect(wrapper.emitted('submit')[0]).toEqual([payload])

Асинхронность в тестах

Vue обновляет DOM асинхронно. Любое действие, вызывающее реактивное изменение, требует await:

await wrapper.trigger('click')
await wrapper.setProps(...)
await wrapper.setValue('text')

Без await тест может завершиться до применения изменений.


Изоляция логики

Один тест — одна проверка. Даже простой компонент тестируется несколькими тестами:

it('отображает текст из props', ...)
it('эмитит событие при клике', ...)
it('имеет disabled состояние', ...)

Это упрощает отладку и делает отчёты тестов однозначными.


Базовый шаблон простого теста

Собранная структура в чистом виде:

import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import Button from '@/components/Button.vue'

describe('Button.vue', () => {
  it('отображает переданный текст', () => {
    const wrapper = mount(Button, {
      props: {
        label: 'Нажать'
      }
    })

    expect(wrapper.text()).toBe('Нажать')
  })
})

Этот шаблон повторяется в большинстве тестов и служит фундаментом для более сложных сценариев: моков, слотов, сторонов состояния и асинхронной логики.