В Vue.js атрибут key играет критически важную роль при
работе с списками компонентов или элементов. Он позволяет Vue эффективно
отслеживать изменения в DOM, минимизируя перерисовки и сохраняя
внутреннее состояние компонентов. В тестах это особенно важно, так как
некорректные ключи могут привести к неожиданному поведению компонентов и
тестов.
keyАтрибут key используется для:
key гарантирует его сохранение при обновлении родительского
списка.Пример:
<template>
<ul>
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
</ul>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 1, name: 'Элемент 1' },
{ id: 2, name: 'Элемент 2' },
]
}
}
}
</script>
Во Vue Test Utils есть несколько способов убедиться, что компоненты получают правильные ключи.
1. Проверка наличия ключей у элементов
Метод findAll возвращает коллекцию обёрток компонентов
или элементов. Каждая обёртка имеет метод attributes(),
позволяющий проверить атрибут key:
import { mount } from '@vue/test-utils';
import MyList from '@/components/MyList.vue';
const wrapper = mount(MyList);
const items = wrapper.findAll('li');
expect(items[0].attributes('key')).toBe('1');
expect(items[1].attributes('key')).toBe('2');
Особенность: key не является реактивным
атрибутом и не попадает в props. Для проверки необходимо
использовать attributes() или напрямую проверять VNode,
если нужно более глубокое тестирование.
2. Проверка ключей у компонентов
Для компонентов, рендерящихся в списке, важно убедиться, что ключи установлены правильно, чтобы компоненты не пересоздавались при изменении данных:
const wrapper = mount({
template: `
<div>
<child-component v-for="item in items" :key="item.id" :item="item" />
</div>
`,
components: { ChildComponent },
data() {
return {
items: [
{ id: 1, name: 'A' },
{ id: 2, name: 'B' }
]
}
}
});
const children = wrapper.findAllComponents(ChildComponent);
expect(children[0].vm.$options.key).toBe(1); // Доступ через внутренний VNode
expect(children[1].vm.$options.key).toBe(2);
Для Vue 3 проверка ключа через внутренний VNode выглядит так:
children.forEach((child, index) => {
expect(child.vm.$.vnode.key).toBe(wrapper.vm.items[index].id);
});
Сохранение состояния Если ключ не уникален или отсутствует, Vue может пересоздать компонент при обновлении списка, что приведёт к потере локального состояния. Тесты помогают выявить такие ошибки.
Оптимизация рендеринга Неправильные ключи
заставляют Vue удалять и создавать DOM-узлы заново вместо их
переработки. В тестах это проявляется как лишние вызовы lifecycle hooks
(mounted, beforeUpdate).
Отслеживание перемещений элементов При изменении порядка элементов проверка ключей позволяет убедиться, что Vue корректно перемещает компоненты, а не создаёт новые:
await wrapper.setData({ items: [{ id: 2, name: 'B' }, { id: 1, name: 'A' }] });
const children = wrapper.findAllComponents(ChildComponent);
expect(children[0].vm.item.id).toBe(2);
expect(children[1].vm.item.id).toBe(1);
v-if и v-for одновременно
ключи критически важны для правильного рендеринга и сохранения состояния
компонентов, особенно если один и тот же компонент может появляться и
исчезать:<child-component v-for="item in items" v-if="item.visible" :key="item.id" />
Тест должен проверять, что после скрытия и повторного отображения компонента ключ остаётся прежним.
Проверка key в Vue Test Utils обеспечивает надёжность
тестов компонентов, гарантирует корректную работу с динамическими
списками и сохраняет внутреннее состояние компонентов при обновлении
данных.