Мокирование компонентов Element Plus

Мокирование (mocking) компонентов в Element Plus используется для упрощения тестирования, изоляции отдельных частей приложения и проверки взаимодействия компонентов без необходимости поднимать весь стек зависимостей. Это особенно важно при работе с большими интерфейсами на Vue 3, где компоненты Element Plus предоставляют сложную логику и внутренние состояния.


Основы мокирования компонентов

В контексте Vue 3 и Element Plus мокирование обычно применяется через тестовые фреймворки, такие как Jest или Vitest, совместно с утилитами Vue Test Utils. Мокирование позволяет подменять:

  • Внешние зависимости (например, API-вызывы внутри методов компонента)
  • Встроенные компоненты Element Plus
  • События и слоты компонента

Пример базового мокирования компонента ElButton:

import { mount } from '@vue/test-utils'
import { ElButton } from 'element-plus'
import MyComponent from '@/components/MyComponent.vue'

jest.mock('element-plus', () => ({
  ...jest.requireActual('element-plus'),
  ElButton: {
    name: 'ElButton',
    template: '<button data-mock>{{ $slots.default() }}</button>'
  }
}))

test('мокирование кнопки', () => {
  const wrapper = mount(MyComponent)
  expect(wrapper.find('button[data-mock]').exists()).toBe(true)
})

Ключевые моменты:

  • jest.mock позволяет подменить реальный компонент на упрощённый вариант.
  • В шаблоне можно оставить слоты, чтобы сохранить возможность тестировать внутреннее содержимое компонента.
  • Это снижает зависимость от стилей и сложной логики Element Plus при тестах.

Мокирование компонентов с событиями

Element Plus компоненты часто используют события (@click, @change). При мокировании необходимо учитывать их обработку:

jest.mock('element-plus', () => ({
  ...jest.requireActual('element-plus'),
  ElInput: {
    name: 'ElInput',
    template: '<input @input="$emit(\'input\', $event.target.value)" />'
  }
}))

test('тест input', async () => {
  const wrapper = mount(MyComponent)
  const input = wrapper.find('input')
  await input.setValue('тест')
  expect(wrapper.emitted('update:modelValue')[0]).toEqual(['тест'])
})

Особенности:

  • Поддержка событий обязательна для компонентов, от которых зависит реактивность родителя.
  • Мокированный компонент может эмулировать только нужные события, игнорируя остальную логику.

Использование слотов при мокировании

Многие компоненты Element Plus активно используют слоты: default, prepend, append. При мокировании важно правильно передавать слоты для тестирования взаимодействий:

jest.mock('element-plus', () => ({
  ...jest.requireActual('element-plus'),
  ElSelect: {
    name: 'ElSelect',
    template: '<div data-mock><slot /></div>'
  }
}))

Такой подход:

  • Позволяет тестировать, что слоты корректно рендерятся.
  • Изолирует компонент от сложной логики выбора или выпадающих списков.

Мокирование с помощью фабрики компонентов

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

function mockElComponent(name, template = '<div data-mock></div>') {
  return {
    name,
    template
  }
}

// Пример применения:
jest.mock('element-plus', () => ({
  ...jest.requireActual('element-plus'),
  ElDialog: mockElComponent('ElDialog', '<div data-dialog><slot /></div>')
}))

Преимущества:

  • Унификация моков компонентов.
  • Легкая настройка шаблонов для тестирования слотов и событий.
  • Упрощение поддержки тестов при обновлении Element Plus.

Советы по мокированию сложных компонентов

  1. Разделять визуальный рендер и логику. Не стоит мокировать весь компонент, если достаточно проверить только события или слоты.
  2. Использовать shallowMount из Vue Test Utils, чтобы автоматически игнорировать дочерние компоненты.
  3. Сохранять интерфейс компонентов, включая props и события, чтобы тесты оставались реалистичными.
  4. Документировать моки, чтобы другие разработчики понимали, что подменяется и почему.

Интеграция с глобальными провайдерами

Element Plus использует глобальные настройки через app.use(ElementPlus). При мокировании тестируемого компонента можно также замокировать глобальные провайдеры:

import { ElMessage } from 'element-plus'

jest.mock('element-plus', () => ({
  ...jest.requireActual('element-plus'),
  ElMessage: { success: jest.fn(), error: jest.fn() }
}))

Это позволяет:

  • Проверять вызовы глобальных уведомлений без фактического отображения.
  • Изолировать тесты от глобального состояния приложения.

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

jest.mock('element-plus', () => ({
  ...jest.requireActual('element-plus'),
  ElButton: { name: 'ElButton', template: '<button data-btn><slot /></button>' },
  ElInput: { name: 'ElInput', template: '<input data-input @input="$emit(\'input\', $event.target.value)" />' }
}))

test('взаимодействие кнопки и input', async () => {
  const wrapper = mount(MyComponent)
  await wrapper.find('input[data-input]').setValue('тест')
  await wrapper.find('button[data-btn]').trigger('click')
  expect(wrapper.emitted()).toHaveProperty('submit')
})

Выводы из практики:

  • Мокирование нескольких компонентов упрощает тестирование сложных форм и диалогов.
  • Можно отслеживать события между компонентами без необходимости рендерить всю библиотеку Element Plus.

Эти техники позволяют создавать стабильные, быстрые и поддерживаемые тесты для приложений на Vue 3, где Element Plus играет ключевую роль. Мокирование компонентов уменьшает зависимость от визуальных особенностей, ускоряет тесты и обеспечивает контроль над событиями, слотами и глобальными провайдерами.