Unit тестирование с Jest/Vitest

Quasar поддерживает интеграцию с современными инструментами тестирования JavaScript, такими как Jest и Vitest. Основная цель unit-тестирования — проверка отдельных модулей, компонентов или функций на корректность их работы без зависимости от внешнего состояния.

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

# Для Jest
npm install --save-dev jest @vue/test-utils babel-jest vue-jest

# Для Vitest
npm install --save-dev vitest @vue/test-utils jsdom

В случае с Quasar, рекомендуется использовать CLI для интеграции тестового фреймворка:

quasar new test jest
# или
quasar new test vitest

CLI создаст структуру тестов, конфигурационные файлы (jest.config.js или vitest.config.js) и пример тестового файла.


Структура тестов в Quasar

Тесты обычно располагаются в директории src/components/__tests__ или tests/unit. Для компонентов Vue/Quasar структура файла теста имеет следующий вид:

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

describe('MyComponent', () => {
  it('рендерит текст правильно', () => {
    const wrapper = mount(MyComponent, {
      props: { title: 'Привет' }
    })
    expect(wrapper.text()).toContain('Привет')
  })
})
  • mount — создает полный рендер компонента с дочерними компонентами.
  • shallowMount — рендерит компонент без дочерних компонентов, что ускоряет тестирование.
  • describe — группирует тесты по функциональности.
  • it или test — отдельный тест-кейс.
  • expect — основной инструмент для утверждений (assertions).

Тестирование Quasar-компонентов

Quasar предоставляет множество UI-компонентов (QButton, QInput, QDialog и др.). При тестировании необходимо учитывать их специфические свойства и события.

Пример проверки события клика на кнопке QButton:

import { mount } from '@vue/test-utils'
import { QBtn } from 'quasar'

describe('QBtn', () => {
  it('вызывает обработчик click', async () => {
    const onCl ick = vi.fn() // Для Vitest, для Jest используем jest.fn()
    const wrapper = mount(QBtn, {
      props: { label: 'Нажми', onClick }
    })

    await wrapper.trigger('click')
    expect(onClick).toHaveBeenCalled()
  })
})

Особенности Quasar-компонентов:

  • Многие компоненты используют асинхронные эффекты и порталы (например, QDialog, QMenu).
  • Для тестирования таких компонентов рекомендуется использовать flushPromises(), чтобы дождаться завершения всех асинхронных операций:
import { flushPromises } from '@vue/test-utils'

await wrapper.find('button').trigger('click')
await flushPromises()
expect(wrapper.html()).toContain('Диалог открыт')

Мокинг и изоляция зависимостей

Unit-тесты должны проверять только целевой компонент или функцию. Для этого используются моки:

import axios from 'axios'
import { fetchData } from '../api'

jest.mock('axios')

it('получает данные с API', async () => {
  axios.get.mockResolvedValue({ data: { id: 1, name: 'Тест' } })
  const result = await fetchData()
  expect(result.name).toBe('Тест')
})

В Vitest синтаксис почти идентичен:

import { vi } from 'vitest'
import axios from 'axios'
import { fetchData } from '../api'

vi.mock('axios', () => ({
  get: vi.fn(() => Promise.resolve({ data: { id: 1, name: 'Тест' } }))
}))

Использование моков позволяет изолировать тест от внешних API, глобальных состояний и сложных зависимостей.


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

Quasar-компоненты часто используют асинхронные события, таймеры или промисы. Для корректного тестирования необходимо использовать async/await и инструменты фреймворка:

it('асинхронно обновляет состояние', async () => {
  const wrapper = mount(MyComponent)
  wrapper.vm.loadData() // метод, который делает fetch
  await flushPromises()
  expect(wrapper.vm.items.length).toBeGreaterThan(0)
})

Для Jest можно использовать done колбэк для старых версий:

it('тест с колбэком', (done) => {
  setTimeout(() => {
    expect(true).toBe(true)
    done()
  }, 100)
})

Snapshot-тестирование

Snapshot-тесты позволяют фиксировать текущий рендер компонента и автоматически проверять изменения:

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

it('совпадает со снапшотом', () => {
  const wrapper = mount(MyComponent, { props: { title: 'Тест' } })
  expect(wrapper.html()).toMatchSnapshot()
})

При изменении шаблона тест упадет, что помогает отследить непреднамеренные визуальные изменения.


Организация больших тестовых наборов

Для масштабируемых проектов рекомендуется:

  1. Группировать тесты по директориям: components, pages, store.
  2. Использовать вспомогательные функции для рендера компонентов и моков.
  3. Включать тесты на события, props, computed, методы, watchers.
  4. Автоматически запускать тесты при коммите с помощью lint-staged и husky.
npx husky add .husky/pre-commit "npm test"
  1. Использовать конфигурацию jest.config.js или vitest.config.js для поддержки алиасов Quasar (@/components, @/pages).

Интеграция с Quasar Store (Pinia/Vuex)

При тестировании компонентов с состоянием Quasar Store важно изолировать store или использовать мок-версию:

import { createTestingPinia } from '@pinia/testing'
import { mount } from '@vue/test-utils'
import MyComponent from '../MyComponent.vue'

const wrapper = mount(MyComponent, {
  global: {
    plugins: [createTestingPinia()]
  }
})

Это позволяет контролировать состояние и следить за вызовами действий без воздействия на глобальный store приложения.


Заключение по практическим рекомендациям

  • Всегда использовать shallowMount для быстрого тестирования и mount для полного рендера.
  • Для компонентов с асинхронной логикой применять flushPromises или waitFor (Vitest).
  • Мокать сторонние зависимости (API, Store, Router).
  • Использовать snapshot-тесты для контроля визуальных изменений компонентов.
  • Структурировать тесты по директориям и функциональным блокам для удобства поддержки.

Unit-тестирование с Jest и Vitest в Quasar позволяет создать надежный, поддерживаемый код, легко выявлять баги и контролировать поведение компонентов при изменениях проекта.