Объектные и массивные props

В Vue.js компоненты обмениваются данными через props. Когда props представляют собой объекты или массивы, тестирование их поведения требует особого внимания. Vue Test Utils предоставляет инструменты для точной проверки работы компонентов с такими сложными структурами данных.


Передача объектных и массивных props

Компонент может принимать props как объекты или массивы, например:

// Компонент
export default {
  props: {
    user: Object,
    items: Array
  },
  template: `
    <div>
      <p>{{ user.name }}</p>
      <ul>
        <li v-for="item in items" :key="item.id">{{ item.label }}</li>
      </ul>
    </div>
  `
};

При тестировании через Vue Test Utils можно передавать сложные структуры в props при монтировании:

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

const wrapper = mount(MyComponent, {
  props: {
    user: { name: 'Alice', age: 25 },
    items: [
      { id: 1, label: 'Первый' },
      { id: 2, label: 'Второй' }
    ]
  }
});

Важно: объектные и массивные props передаются по ссылке, поэтому любые изменения в тесте могут повлиять на исходные данные. Если нужно изолировать данные, их следует клонировать:

const userCopy = { ...user };
const itemsCopy = items.map(item => ({ ...item }));

Проверка объектных props

Для проверки работы с объектными props удобно использовать методы .props(), .text(), а также прямое обращение к реактивным данным:

expect(wrapper.props('user')).toEqual({ name: 'Alice', age: 25 });
expect(wrapper.text()).toContain('Alice');

Если компонент изменяет внутреннюю копию объекта, необходимо использовать wrapper.vm для доступа к реактивным свойствам:

wrapper.vm.user.name = 'Bob';
await wrapper.vm.$nextTick();
expect(wrapper.text()).toContain('Bob');

Проверка массивных props

Массивы требуют проверки как количества элементов, так и их содержимого:

const listItems = wrapper.findAll('li');
expect(listItems).toHaveLength(2);
expect(listItems[0].text()).toBe('Первый');
expect(listItems[1].text()).toBe('Второй');

Для динамических изменений массива используется метод setProps или изменение реактивной копии:

wrapper.setProps({ items: [...wrapper.props('items'), { id: 3, label: 'Третий' }] });
await wrapper.vm.$nextTick();
expect(wrapper.findAll('li')).toHaveLength(3);
expect(wrapper.text()).toContain('Третий');

Особенности сравнения объектов и массивов

  • Глубокое сравнение. Jest по умолчанию сравнивает объекты по ссылке при toBe. Для сравнения значений используется toEqual.
  • Реактивность. Vue отслеживает изменения только в реактивных объектах. Прямое присваивание нового объекта через setProps корректно обновляет компонент.
  • Изменение вложенных структур. Для корректного отслеживания изменений вложенных объектов рекомендуется использовать Vue.set или заменять весь объект/массив новым экземпляром.

Мокирование props для изоляции тестов

Иногда требуется протестировать компонент независимо от исходных данных:

const wrapper = mount(MyComponent, {
  props: {
    user: jest.fn(() => ({ name: 'Mocked', age: 0 }))(),
    items: []
  }
});

Такой подход позволяет полностью контролировать поведение компонентных props без влияния внешних объектов.


Использование computed props и watcher для объектов и массивов

Если компонент вычисляет значения на основе сложных props или отслеживает их через watch, Vue Test Utils позволяет имитировать изменения:

// Изменение массива
wrapper.setProps({ items: [{ id: 1, label: 'Обновлённый' }] });
await wrapper.vm.$nextTick();
expect(wrapper.text()).toContain('Обновлённый');

// Проверка реактивного watcher
wrapper.vm.user.age = 30;
await wrapper.vm.$nextTick();
expect(wrapper.vm.user.age).toBe(30);

Watcher срабатывает при любом изменении реактивной копии, но не при мутации исходного объекта, переданного напрямую без клонирования.


Практика работы с глубокими объектами

Для многослойных объектов часто используют глубокое клонирование перед тестом:

const deepClone = obj => JSON.parse(JSON.stringify(obj));
const wrapper = mount(MyComponent, {
  props: { user: deepClone(originalUser) }
});

Это предотвращает непреднамеренные побочные эффекты между тестами.


Выводы по тестированию объектных и массивных props

  • Передавать объекты и массивы нужно внимательно, учитывая реактивность Vue и передачу по ссылке.
  • Для проверки содержимого использовать .props(), .text(), .findAll().
  • Любые изменения внутри теста лучше делать на клонированных копиях данных.
  • Для глубоких изменений и динамических массивов применять setProps или полное обновление объекта.
  • Мокирование props и использование watcher-комбинаций повышает точность тестов и предотвращает ложноположительные результаты.

Эта методология обеспечивает корректное и детальное тестирование компонентов Vue при работе с объектными и массивными props, позволяя отслеживать их реактивные изменения и точное отображение в шаблоне.