В Vue.js слоты предоставляют возможность передачи контента из родительского компонента в дочерний. Scoped slots (слоты с областью видимости) позволяют передавать данные из дочернего компонента в родительский через slot props. Для юнит-тестирования компонентов с slot-scope параметрами важно не только убедиться, что слот отображается, но и проверить корректность передаваемых данных.
Scoped slot определяется с помощью атрибута v-slot (в
Vue 2.6+ используется синтаксис v-slot, в Vue 2.5 и ниже —
slot-scope):
<ChildComponent>
<template v-slot:default="slotProps">
<p>{{ slotProps.text }}</p>
</template>
</ChildComponent>
В данном примере дочерний компонент передает объект
slotProps родителю, содержащий ключ text. В
тестах важно убедиться, что данные, переданные через слот, соответствуют
ожиданиям.
Vue Test Utils предоставляет возможность замокать
слот через объект slots при вызове
mount или shallowMount. Для scoped slots
используется свойство scopedSlots (в Vue 2) или можно
передавать слот как функцию (в Vue 3):
import { mount } from '@vue/test-utils'
import ChildComponent from '@/components/ChildComponent.vue'
const wrapper = mount(ChildComponent, {
scopedSlots: {
default: `<template slot-scope="props"><span>{{ props.text }}</span></template>`
}
})
При таком подходе тест сможет отследить, что слот отрисован и что
параметр props.text правильно передается.
Для проверки данных, передаваемых в scoped slot, можно использовать следующие методы:
text():expect(wrapper.text()).toContain('Ожидаемый текст');
const slotFn = jest.fn(props => `<span>${props.text}</span>`);
const wrapper = mount(ChildComponent, {
scopedSlots: { default: slotFn }
});
expect(slotFn).toHaveBeenCalledWith(expect.objectContaining({ text: 'Hello World' }));
В этом примере используется jest.fn для отслеживания
вызовов слота и проверки переданных параметров.
shallowMount позволяет изолировать тестируемый
компонент, игнорируя дочерние компоненты. Scoped slots при этом также
можно замокать:
import { shallowMount } from '@vue/test-utils'
const wrapper = shallowMount(ChildComponent, {
scopedSlots: {
default: props => `<div>${props.message}</div>`
}
})
expect(wrapper.html()).toContain('<div>Hello</div>');
Использование shallowMount ускоряет тестирование и
снижает количество побочных эффектов от вложенных компонентов.
Если компонент передает несколько параметров через слот, проверку
можно проводить через объект props:
const wrapper = mount(ChildComponent, {
scopedSlots: {
default: props => `<div>${props.text} - ${props.count}</div>`
}
});
const slotDiv = wrapper.find('div');
expect(slotDiv.text()).toBe('Hello - 5');
Метод find позволяет локализовать конкретный
DOM-элемент, созданный слотом, и проверить его содержимое.
const wrapper = mount(ChildComponent, {
slots: {
default: ({ text }) => `<span>${text}</span>`
}
});
jest.fn и проверять количество
вызовов:expect(slotFn).toHaveBeenCalledTimes(2);
import { mount } from '@vue/test-utils'
import ListComponent from '@/components/ListComponent.vue'
const slotFn = jest.fn(props => `<li>${props.item}</li>`);
const wrapper = mount(ListComponent, {
props: { items: ['A', 'B', 'C'] },
scopedSlots: { default: slotFn }
});
expect(slotFn).toHaveBeenCalledTimes(3);
expect(slotFn.mock.calls[0][0]).toEqual({ item: 'A' });
expect(slotFn.mock.calls[1][0]).toEqual({ item: 'B' });
expect(slotFn.mock.calls[2][0]).toEqual({ item: 'C' });
В этом примере проверяется, что слот вызван для каждого элемента
массива, а параметры item передаются корректно.
shallowMount, чтобы не тестировать внутренности дочерних
компонентов.slot-scope устарел в пользу v-slot.Этот подход позволяет не только убедиться в визуальном отображении слотов, но и гарантировать корректность передачи данных через scoped slot, что особенно важно для компонентов, построенных на композиции и динамических списках.