Passer au contenu

Tester les slots

Introduction aux slots

Les slots sont une fonctionnalité puissante de Vue qui permet d’injecter du contenu depuis un composant parent dans un composant enfant. Tester correctement les slots est essentiel pour vérifier que votre composant se comporte comme prévu avec différents contenus injectés.

Tester les slots par défaut avec template

La façon la plus simple de tester un slot par défaut est d’utiliser la propriété slots de l’option mount:

import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import Card from '@/components/Card.vue'
describe('Card.vue', () => {
it('renders default slot content', () => {
const wrapper = mount(Card, {
slots: {
default: 'Contenu du slot par défaut'
}
})
expect(wrapper.text()).toContain('Contenu du slot par défaut')
})
})

Utiliser des templates pour des contenus complexes

Pour des contenus de slot plus complexes, vous pouvez utiliser des templates:

import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import Layout from '@/components/Layout.vue'
describe('Layout.vue', () => {
it('renders complex slot content', () => {
const wrapper = mount(Layout, {
slots: {
header: '<h1>Titre de la page</h1>',
default: '<div class="content">Contenu principal</div>',
footer: '<footer>Pied de page</footer>'
}
})
expect(wrapper.find('h1').exists()).toBe(true)
expect(wrapper.find('h1').text()).toBe('Titre de la page')
expect(wrapper.find('.content').text()).toBe('Contenu principal')
expect(wrapper.find('footer').text()).toBe('Pied de page')
})
})

Utiliser des composants dans les slots

Vous pouvez également passer des composants dans les slots:

import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import TabContainer from '@/components/TabContainer.vue'
import Tab from '@/components/Tab.vue'
describe('TabContainer.vue', () => {
it('renders tabs passed as slot content', () => {
const wrapper = mount(TabContainer, {
slots: {
default: [
h(Tab, { title: 'Tab 1' }, () => 'Contenu de l\'onglet 1'),
h(Tab, { title: 'Tab 2' }, () => 'Contenu de l\'onglet 2')
]
}
})
// Vérifier que les onglets sont rendus
const tabs = wrapper.findAllComponents(Tab)
expect(tabs.length).toBe(2)
})
})

Utiliser hyperscript (h) pour les slots

Pour des cas plus complexes ou lorsque vous avez besoin de plus de contrôle, vous pouvez utiliser la fonction h (hyperscript) pour créer vos slots:

import { mount } from '@vue/test-utils'
import { h } from 'vue'
import { describe, it, expect, vi } from 'vitest'
import Dialog from '@/components/Dialog.vue'
import Button from '@/components/Button.vue'
describe('Dialog.vue', () => {
it('emits close event when button in footer slot is clicked', async () => {
// Espionner l'événement click
const onClickSpy = vi.fn()
const wrapper = mount(Dialog, {
props: {
title: 'Confirmation'
},
slots: {
default: h('p', 'Êtes-vous sûr de vouloir continuer?'),
footer: h(Button, {
onClick: onClickSpy,
class: 'close-button'
}, () => 'Fermer')
}
})
// Vérifier que le contenu est bien rendu
expect(wrapper.find('p').text()).toBe('Êtes-vous sûr de vouloir continuer?')
// Simuler le clic sur le bouton de fermeture
await wrapper.find('.close-button').trigger('click')
// Vérifier que le gestionnaire d'événements a été appelé
expect(onClickSpy).toHaveBeenCalled()
})
})

Tester les scoped slots

Les scoped slots permettent au composant de passer des données au contenu du slot. Voici comment les tester:

import { mount } from '@vue/test-utils'
import { h } from 'vue'
import { describe, it, expect } from 'vitest'
import UserList from '@/components/UserList.vue'
describe('UserList.vue', () => {
it('renders users with scoped slot', () => {
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
const wrapper = mount(UserList, {
props: {
users
},
slots: {
// Utiliser un scoped slot qui reçoit la prop 'user'
default: ({ user, index }) => h('div', { class: 'user-item' }, `${index + 1}. ${user.name}`)
}
})
const userItems = wrapper.findAll('.user-item')
expect(userItems.length).toBe(2)
expect(userItems[0].text()).toBe('1. Alice')
expect(userItems[1].text()).toBe('2. Bob')
})
})

Combiner les espions avec les slots pour vérifier les interactions

Vous pouvez combiner les espions avec les slots pour tester les interactions entre les composants:

import { mount } from '@vue/test-utils'
import { h } from 'vue'
import { describe, it, expect, vi } from 'vitest'
import Dropdown from '@/components/Dropdown.vue'
describe('Dropdown.vue', () => {
it('calls itemSelected when an item is clicked', async () => {
const onItemClick = vi.fn()
const items = ['Option 1', 'Option 2', 'Option 3']
const wrapper = mount(Dropdown, {
props: {
items,
onItemSelected: onItemClick
},
slots: {
// Slot personnalisé pour le rendu des éléments
item: ({ item, index }) => h('div', {
class: 'dropdown-item',
'data-index': index,
onClick: () => onItemClick(item, index)
}, item)
}
})
// Ouvrir le dropdown
await wrapper.find('.dropdown-toggle').trigger('click')
// Cliquer sur le deuxième élément
await wrapper.findAll('.dropdown-item')[1].trigger('click')
// Vérifier que la fonction a été appelée avec le bon élément
expect(onItemClick).toHaveBeenCalledWith('Option 2', 1)
})
})