Тестирование computed свойств

Computed свойства в Vue представляют собой реактивные вычисляемые значения, которые зависят от данных компонента и автоматически пересчитываются при их изменении. Тестирование таких свойств требует понимания как реактивности Vue, так и особенностей работы Vue Test Utils.

Отличие computed от методов

Основное отличие: computed свойства кэшируются на основе своих зависимостей, тогда как методы вызываются каждый раз при рендеринге. Это означает, что тестирование computed должно учитывать:

  • корректность вычислений,
  • реактивное обновление при изменении зависимостей,
  • взаимодействие с другими computed и data.

Подготовка к тестированию

Для тестирования computed свойств используется mount или shallowMount из Vue Test Utils. ShallowMount позволяет изолировать компонент, избегая рендеринга дочерних компонентов, что удобно для юнит-тестов.

import { shallowMount } from '@vue/test-utils';
import ComponentWithComputed from '@/components/ComponentWithComputed.vue';

const wrapper = shallowMount(ComponentWithComputed);

Тестирование вычисления значения

Самый простой случай — проверка возвращаемого значения computed свойства на основе текущего состояния data.

it('правильно вычисляет полное имя', () => {
  const wrapper = shallowMount(ComponentWithComputed, {
    data() {
      return { firstName: 'Иван', lastName: 'Петров' };
    }
  });

  expect(wrapper.vm.fullName).toBe('Иван Петров');
});

Здесь fullName — computed свойство, зависящее от firstName и lastName.

Проверка реактивного обновления

Computed свойства должны автоматически обновляться при изменении зависимостей. Для проверки этого изменяют data компонента и проверяют новое значение computed свойства.

it('обновляет fullName при изменении firstName', async () => {
  const wrapper = shallowMount(ComponentWithComputed, {
    data() {
      return { firstName: 'Иван', lastName: 'Петров' };
    }
  });

  wrapper.setData({ firstName: 'Алексей' });
  await wrapper.vm.$nextTick();

  expect(wrapper.vm.fullName).toBe('Алексей Петров');
});

Ключевой момент: после изменения данных всегда следует ожидать завершения реактивного цикла с помощью await wrapper.vm.$nextTick(), иначе computed свойство может ещё не обновиться.

Тестирование вычислений с геттерами и сеттерами

Computed свойства могут содержать не только геттер, но и сеттер. В таком случае тестирование должно проверять оба сценария: чтение и запись.

computed: {
  fullName: {
    get() {
      return `${this.firstName} ${this.lastName}`;
    },
    set(value) {
      const names = value.split(' ');
      this.firstName = names[0];
      this.lastName = names[1];
    }
  }
}

Тест геттера:

expect(wrapper.vm.fullName).toBe('Иван Петров');

Тест сеттера:

wrapper.vm.fullName = 'Алексей Сидоров';
await wrapper.vm.$nextTick();

expect(wrapper.vm.firstName).toBe('Алексей');
expect(wrapper.vm.lastName).toBe('Сидоров');

Тестирование зависимых computed свойств

Иногда одно computed свойство зависит от другого. В таких случаях важно проверять последовательное обновление.

computed: {
  greeting() {
    return `Привет, ${this.fullName}`;
  },
  fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

Тестирование:

wrapper.setData({ firstName: 'Мария' });
await wrapper.vm.$nextTick();

expect(wrapper.vm.fullName).toBe('Мария Петров');
expect(wrapper.vm.greeting).toBe('Привет, Мария Петров');

Особенности тестирования с props

Computed свойства часто зависят от props. В таких случаях для теста используется опция propsData.

const wrapper = shallowMount(ComponentWithComputed, {
  propsData: { basePrice: 100 }
});

expect(wrapper.vm.priceWithTax).toBe(120); // computed добавляет 20% налог

Изменение prop и проверка реактивности:

await wrapper.setProps({ basePrice: 200 });
expect(wrapper.vm.priceWithTax).toBe(240);

Использование spy для наблюдения за вызовами

Если computed свойство использует методы компонента, можно использовать jest.spyOn для отслеживания вызовов.

jest.spyOn(wrapper.vm, 'calculateDiscount');
wrapper.vm.discountedPrice;
expect(wrapper.vm.calculateDiscount).toHaveBeenCalled();

Это помогает убедиться, что внутри computed свойства вызываются нужные функции.

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

  • Тестировать отдельно геттеры и сеттеры computed свойств.
  • Проверять реактивность после изменения data или props через await wrapper.vm.$nextTick().
  • Использовать shallowMount для изоляции компонента.
  • Проверять цепочки зависимых computed свойств, чтобы убедиться в корректной последовательности вычислений.
  • Если computed использует методы, можно применять spy для проверки вызовов.

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