Отправка форм

В тестировании компонентов Vue формы требуют особого внимания, так как они включают взаимодействие пользователя с DOM, валидацию данных и часто — асинхронные процессы. Vue Test Utils предоставляет набор инструментов для эффективного моделирования этих взаимодействий и проверки корректности работы компонентов с формами.


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

Для начала необходимо смонтировать компонент с помощью mount или shallowMount:

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

const wrapper = mount(MyForm)

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


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

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

  • wrapper.find(selector) — возвращает первый элемент, соответствующий селектору.
  • wrapper.findAll(selector) — возвращает коллекцию всех соответствующих элементов.
  • wrapper.get(selector) — аналог find, но бросает ошибку, если элемент не найден.

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

const input = wrapper.get('input[name="username"]')
const password = wrapper.get('input[name="password"]')
const submitButton = wrapper.get('button[type="submit"]')

Совет: использовать get, если отсутствие элемента считается ошибкой теста. Это делает тест более надёжным.


Ввод данных в поля

Для имитации ввода текста используется метод setValue:

await input.setValue('user123')
await password.setValue('secret')

Метод setValue автоматически обновляет v-model в компоненте и триггерит события input или change, если они необходимы.

Ключевой момент: Для асинхронного обновления состояния компонента после ввода следует использовать await, чтобы гарантировать завершение всех реактивных обновлений перед следующими действиями.


Отправка формы

Отправку формы можно смоделировать через метод trigger:

await wrapper.get('form').trigger('submit.prevent')

Здесь используется .prevent, если в компоненте применяется @submit.prevent для предотвращения стандартного поведения браузера.

После триггера можно проверить:

  • вызовы методов компонента через jest.fn() или vi.fn();
  • изменения состояния или данных;
  • появление сообщений об ошибках.

Пример проверки вызова метода handleSubmit:

const handleSubmit = vi.spyOn(wrapper.vm, 'handleSubmit')
await wrapper.get('form').trigger('submit.prevent')
expect(handleSubmit).toHaveBeenCalled()

Проверка валидации

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

await input.setValue('')
await wrapper.get('form').trigger('submit.prevent')

expect(wrapper.text()).toContain('Поле обязательно для заполнения')

Если используется сторонняя библиотека валидации (например, Vuelidate или Yup), важно подождать асинхронного выполнения проверок:

await wrapper.vm.$nextTick()

или

await flushPromises()

Работа с чекбоксами и радио

Для чекбоксов используется setChecked:

const checkbox = wrapper.get('input[type="checkbox"]')
await checkbox.setChecked(true)
expect(wrapper.vm.acceptTerms).toBe(true)

Для радиокнопок аналогично:

const option = wrapper.get('input[value="option1"]')
await option.setChecked()
expect(wrapper.vm.selectedOption).toBe('option1')

Особенность: при работе с группами радио и чекбоксов важно правильно выбрать селектор, чтобы тест охватывал нужный элемент.


Асинхронные формы

Если отправка формы инициирует асинхронный процесс (например, запрос на сервер), используется мок функции fetch или axios:

import axios from 'axios'
vi.mock('axios')

axios.post.mockResolvedValue({ data: { success: true } })

await wrapper.get('form').trigger('submit.prevent')
await flushPromises()

expect(wrapper.vm.successMessage).toBe('Форма успешно отправлена')

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


Проверка динамических форм

Для форм с динамическими полями (например, добавление нескольких адресов) Vue Test Utils позволяет:

await wrapper.get('button.add-address').trigger('click')
const addresses = wrapper.findAll('input[name="address"]')
expect(addresses.length).toBe(2)

Динамически добавленные элементы можно взаимодействовать точно так же, как статические.


Снимки состояния формы

Для комплексной проверки можно использовать снимки состояния (snapshot):

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

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


Практические рекомендации

  • Всегда использовать await при взаимодействии с элементами, чтобы реактивность Vue успевала обновляться.
  • Отдавать предпочтение get при поиске элементов, чтобы тесты не проходили незаметно при отсутствии элементов.
  • Для асинхронной отправки форм использовать flushPromises или nextTick.
  • Проверять состояние компонента (wrapper.vm) и DOM одновременно для полной уверенности в корректности работы.

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