Кэширование и повторные запросы

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

Основы кэширования в тестах Vue

Кэширование данных позволяет избежать повторного выполнения асинхронных операций, таких как запросы к серверу или тяжелые вычисления, что ускоряет тесты и делает их более предсказуемыми. В контексте Vue Test Utils кэширование чаще всего применяется при:

  • тестировании компонентов, которые делают HTTP-запросы через axios или fetch;
  • проверке вычисляемых свойств (computed) и реактивных данных (reactive, ref), зависящих от внешних источников;
  • симуляции глобальных стейтов через Vuex или Pinia.

Использование моков для кэширования запросов

Для повторного использования данных в тестах обычно применяются моки. Например, мок-функции jest.fn() позволяют хранить результат первого вызова и возвращать его при повторных вызовах.

import { mount } from '@vue/test-utils';
import axios from 'axios';
import ComponentWithAPI from '@/components/ComponentWithAPI.vue';

jest.mock('axios');

const mockData = { id: 1, name: 'Test' };
axios.get.mockResolvedValue(mockData);

test('компонент использует кэшированные данные при повторном запросе', async () => {
  const wrapper = mount(ComponentWithAPI);

  await wrapper.vm.fetchData(); // Первый запрос
  expect(wrapper.vm.data).toEqual(mockData);

  await wrapper.vm.fetchData(); // Второй запрос
  expect(axios.get).toHaveBeenCalledTimes(1); // Проверка кэширования
});

В этом примере используется кэширование на уровне мок-функции: axios.get вызывается один раз, а повторный запрос возвращает уже сохранённые данные.

Реализация кэширования на уровне компонента

Внутри компонента можно хранить результаты запросов в локальном состоянии и использовать их при повторных вызовах:

export default {
  data() {
    return {
      cache: null,
      data: null
    };
  },
  methods: {
    async fetchData() {
      if (this.cache) {
        this.data = this.cache;
        return;
      }
      const response = await axios.get('/api/data');
      this.cache = response.data;
      this.data = response.data;
    }
  }
};

Тестирование такого компонента позволяет убедиться, что кэш работает корректно:

test('fetchData использует кэш при повторном вызове', async () => {
  const wrapper = mount(ComponentWithAPI);
  
  await wrapper.vm.fetchData();
  expect(wrapper.vm.data).toEqual(mockData);

  await wrapper.vm.fetchData();
  expect(axios.get).toHaveBeenCalledTimes(1);
});

Кэширование с использованием Vuex или Pinia

Для более крупных приложений часто применяются централизованные стейты. Кэширование данных через Vuex или Pinia позволяет компонентам повторно использовать данные без дополнительных запросов:

// store.js (Pinia)
import { defineStore } from 'pinia';
import axios from 'axios';

export const useDataStore = defineStore('data', {
  state: () => ({ cache: null }),
  actions: {
    async fetchData() {
      if (this.cache) return this.cache;
      const response = await axios.get('/api/data');
      this.cache = response.data;
      return this.cache;
    }
  }
});

Тестирование компонента с использованием такого сторa:

import { setActivePinia, createPinia } from 'pinia';
import { useDataStore } from '@/store/dataStore';

beforeEach(() => {
  setActivePinia(createPinia());
});

test('данные повторно берутся из кэша', async () => {
  const store = useDataStore();
  
  const firstCall = await store.fetchData();
  const secondCall = await store.fetchData();

  expect(firstCall).toEqual(secondCall);
  expect(axios.get).toHaveBeenCalledTimes(1);
});

Повторные запросы и асинхронные тесты

При тестировании повторных запросов важно учитывать асинхронность. Vue Test Utils предоставляет методы nextTick() и асинхронное ожидание через await wrapper.vm.$nextTick() для корректной проверки изменений реактивных данных.

test('данные обновляются после повторного запроса', async () => {
  const wrapper = mount(ComponentWithAPI);

  await wrapper.vm.fetchData();
  await wrapper.vm.$nextTick();

  wrapper.vm.cache = null; // Очистка кэша
  await wrapper.vm.fetchData();
  await wrapper.vm.$nextTick();

  expect(axios.get).toHaveBeenCalledTimes(2);
});

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

  • Моки и шпионы позволяют контролировать количество вызовов API и имитацию кэширования.
  • Локальный кэш компонента помогает избежать повторных запросов в пределах одного экземпляра.
  • Централизованный кэш в Vuex/Pinia обеспечивает повторное использование данных между компонентами.
  • Асинхронное тестирование требует корректного ожидания реактивных изменений через nextTick() или await.

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