Vue Test Utils: тестирование компонентов

↑ 4.1 Vue 3: основы, компоненты, Composition API · ← Предыдущая · → Следующая

Обязательно~5 мин чтенияУровень: middle

Зачем это на собесе

Практика тестирования компонентов: монтирование, props, события, слоты и изоляция.

Объяснение

Vue Test Utils (VTU) — официальная библиотека для монтирования компонентов в тестах (с Vitest).

import { mount, shallowMount, flushPromises } from "@vue/test-utils";
import { describe, it, expect, vi } from "vitest";
import OrderCard from "./OrderCard.vue";
 
describe("OrderCard", () => {
  const factory = (props = {}) => mount(OrderCard, {
    props: { order: { id: 1, number: "A-1", total: 100 }, ...props },
    global: { plugins: [pinia, router], stubs: { RouterLink: true }, provide: { [ThemeKey as symbol]: theme } },
    slots: { footer: "<em>подвал</em>" },
  });
 
  it("отображает номер и сумму", () => {
    const w = factory();
    expect(w.text()).toContain("A-1");
    expect(w.find("[data-test=total]").text()).toBe("100,00 ₽");
  });
 
  it("эмитит save при клике", async () => {
    const w = factory();
    await w.get("button").trigger("click");                    // trigger возвращает nextTick
    expect(w.emitted("save")).toHaveLength(1);
    expect(w.emitted("save")![0]).toEqual([{ id: 1 }]);
  });
 
  it("обновляется при смене props", async () => {
    const w = factory();
    await w.setProps({ order: { id: 1, number: "B-2", total: 5 } });
    expect(w.text()).toContain("B-2");
  });
 
  it("v-model на input", async () => {
    const w = factory();
    await w.get("input").setValue("abc");
    expect(w.emitted("update:modelValue")![0]).toEqual(["abc"]);
  });
});
APIНазначение
mountполный рендер с дочерними компонентами
shallowMountдочерние компоненты заменены заглушками
find/get/findAll/findComponentпоиск элементов/компонентов (get бросает ошибку при отсутствии)
trigger, setValue, setPropsвзаимодействие
emitted()записанные события
wrapper.vmэкземпляр (лучше не использовать)
global.*плагины, stubs, mocks, provide, directives
flushPromisesдождаться промисов
attachTo: document.bodyмонтирование в реальный DOM (фокус, layout)

Что тестировать: публичный интерфейс — props → отображение, действия пользователя → emits/побочные эффекты, слоты. Не тестируйте внутреннее состояние и приватные методы.

Стабильные селекторы: data-test/data-testid атрибуты.

Нюансы и подводные камни

  • Не забывайте await после trigger/setValue/setProps.
  • shallowMount скрывает интеграцию — используйте осознанно.
  • wrapper.vm.x завязывает тест на реализацию.
  • Асинхронные компоненты/Suspense требуют flushPromises/обёртки.
  • Проверка структуры DOM через снапшоты — хрупкая.

Практика

  1. Покройте компонент таблицы тестами: рендер, сортировка, события, слоты.
  2. Подключите Pinia и Router через global.plugins.
  3. Замените wrapper.vm на проверки через DOM и emits.

Вопросы с ответами

Связанные темы