Тестирование custom middleware

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

Понимание custom middleware

Custom middleware в контексте Vue обычно представляют собой функции, которые выполняются до или после перехода на маршрут или перед выполнением действия в компоненте. Middleware может проверять авторизацию, форматировать данные или перенаправлять пользователя. Типичный пример middleware:

export default function authMiddleware(to, from, next) {
  if (!localStorage.getItem('token')) {
    next('/login');
  } else {
    next();
  }
}

Ключевой аспект тестирования — изоляция логики middleware от реальной навигации, что позволяет проверять поведение в контролируемой среде.


Интеграция middleware с компонентами

Vue Router позволяет использовать middleware через навигационные охранники (beforeEach, beforeEnter) или напрямую внутри компонентов:

const routes = [
  {
    path: '/dashboard',
    component: Dashboard,
    beforeEnter: authMiddleware
  }
];

Для unit-тестирования middleware компонент можно смонтировать с Vue Test Utils и имитировать переход на маршрут.


Использование Vue Test Utils для middleware

Основной инструмент — функция mount или shallowMount, позволяющая изолировать компонент. Для проверки middleware важно:

  1. Мокировать объект маршрута ($route) и объект навигации ($router).
  2. Имитация функции next, чтобы отслеживать переходы или предотвращение навигации.
  3. Проверка состояния компонента или вызовов функций после выполнения middleware.

Пример теста авторизационного middleware:

import { shallowMount } from '@vue/test-utils';
import authMiddleware from '@/middleware/authMiddleware';
import Dashboard from '@/components/Dashboard.vue';

describe('authMiddleware', () => {
  it('перенаправляет на /login при отсутствии токена', () => {
    const next = jest.fn();
    const to = {};
    const from = {};
    localStorage.removeItem('token');

    authMiddleware(to, from, next);

    expect(next).toHaveBeenCalledWith('/login');
  });

  it('пропускает навигацию при наличии токена', () => {
    const next = jest.fn();
    const to = {};
    const from = {};
    localStorage.setItem('token', '123');

    authMiddleware(to, from, next);

    expect(next).toHaveBeenCalledWith();
  });
});

В этом примере middleware полностью изолирован от Vue Router, что позволяет тестировать его логику независимо от маршрутизатора.


Тестирование асинхронного middleware

Многие middleware выполняют асинхронные операции, например запрос к API. Для корректного тестирования асинхронных middleware используется async/await и мокирование HTTP-запросов через jest.mock или msw.

Пример:

export default async function fetchUserMiddleware(to, from, next) {
  try {
    const response = await fetch('/api/user');
    const user = await response.json();
    if (!user.active) {
      next('/inactive');
    } else {
      next();
    }
  } catch {
    next('/error');
  }
}

Тест с мокированием fetch:

global.fetch = jest.fn(() =>
  Promise.resolve({
    json: () => Promise.resolve({ active: false })
  })
);

it('перенаправляет на /inactive при неактивном пользователе', async () => {
  const next = jest.fn();
  await fetchUserMiddleware({}, {}, next);
  expect(next).toHaveBeenCalledWith('/inactive');
});

Валидация взаимодействия middleware с компонентами

Иногда middleware изменяет состояние компонента или Vuex-хранилища. Для проверки можно использовать Vue Test Utils совместно с моками хранилища:

import { createStore } from 'vuex';

const store = createStore({
  state() { return { user: null }; },
  mutations: {
    setUser(state, user) { state.user = user; }
  }
});

const wrapper = shallowMount(Dashboard, {
  global: { plugins: [store] }
});

// Проверка, что middleware вызвал мутацию
expect(store.state.user).toEqual({ id: 1, name: 'Alice' });

Такой подход позволяет убедиться, что middleware корректно взаимодействует с состоянием приложения.


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

  • Всегда мокировать внешние зависимости middleware, включая маршрутизатор, локальное хранилище и API.
  • Использовать jest.fn() для отслеживания вызовов next или других колбэков.
  • Для асинхронного middleware применять async/await и flushPromises при необходимости.
  • Разделять unit-тесты middleware и интеграционные тесты компонентов с middleware, чтобы избежать сложных зависимостей.

Отладка и трассировка

Для глубокого анализа поведения middleware полезно:

  • Включать логирование вызовов next.
  • Использовать wrapper.vm.$nextTick() для ожидания обновления реактивных свойств.
  • Проверять не только перенаправления, но и побочные эффекты на состояние приложения.

Тщательное тестирование custom middleware повышает надежность маршрутизации и бизнес-логики приложения, предотвращает ошибки при переходах и позволяет уверенно модифицировать код без риска поломки критичных функций.