Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Тесты: Vitest и Vue Test Utils

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

Установка

В проекте списка задач todo-app выполните:

npm install -D vitest @vue/test-utils jsdom

jsdom имитирует браузер внутри Node.js — компонентам нужен DOM. Укажите его в vite.config.js, в объекте настроек рядом с plugins:

// vite.config.js
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
 
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) },
  },
  test: {
    environment: 'jsdom',
  },
})

И добавьте команду в раздел scripts файла package.json: "test:unit": "vitest". Если отметить Vitest при создании проекта, create-vue сделает всё это сам.

Первый тест

Тесты кладут в папку __tests__ рядом с компонентами. Создайте src/components/__tests__/TodoItem.spec.js для компонента TodoItem из урока про события:

// src/components/__tests__/TodoItem.spec.js
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import TodoItem from '../TodoItem.vue'
 
describe('TodoItem', () => {
  it('показывает текст задачи', () => {
    const wrapper = mount(TodoItem, {
      props: { todo: { id: 1, text: 'Купить хлеб', done: false } },
    })
 
    expect(wrapper.text()).toContain('Купить хлеб')
  })
})

Запустите:

npm run test:unit

В терминале появится строка с галочкой ✓ src/components/__tests__/TodoItem.spec.js (1 test). mount создаёт компонент с переданными props, wrapper.text() возвращает весь его текст. Vitest продолжает следить за файлами и перезапускает тесты при сохранении.

Клики и события

// src/components/__tests__/TodoItem.spec.js
it('сообщает об удалении', async () => {
  const wrapper = mount(TodoItem, {
    props: { todo: { id: 1, text: 'Купить хлеб', done: false } },
  })
 
  await wrapper.find('button').trigger('click')
 
  expect(wrapper.emitted('remove')).toHaveLength(1)
})

find ищет элемент по CSS-селектору, trigger вызывает событие. await нужен, чтобы Vue успел обновить разметку. emitted('remove') возвращает список всех вызовов события.

МетодЧто делает
wrapper.find('селектор')Находит элемент
wrapper.text(), wrapper.html()Текст и разметка
await el.trigger('click')Вызывает событие
await el.setValue('текст')Вводит значение в поле
wrapper.emitted('имя')Сгенерированные события и их аргументы

Тест хранилища

Хранилище Pinia проверяют без компонентов — достаточно создать активный экземпляр Pinia:

// src/stores/__tests__/posts.spec.js
import { describe, it, expect, beforeEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { usePostsStore } from '../posts.js'
 
describe('posts store', () => {
  beforeEach(() => setActivePinia(createPinia()))
 
  it('добавляет статью в начало', () => {
    const store = usePostsStore()
    store.addPost('Новая', 'Текст')
 
    expect(store.count).toBe(1)
    expect(store.posts[0].title).toBe('Новая')
  })
})

Это тест для проекта blog: Vitest устанавливается в него так же.

Частая ошибка

Проверять результат без await после trigger или setValue. Vue обновляет DOM не сразу, а в следующем такте, и тест прочитает старую разметку — он упадёт, хотя компонент работает правильно. Всегда пишите await перед этими методами и объявляйте функцию теста как async.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.