Composable - звичайна функція, що використовує реактивні API Vue. Як її тестувати, залежить від того, що вона використовує.
1. Лише реактивність (ref, computed, watch) - викликати напряму:
import { useCounter } from './useCounter'
it('increments and clamps to max', () => {
const { count, increment } = useCounter({ max: 2 })
increment()
increment()
increment()
expect(count.value).toBe(2)
})
Компонент не потрібен - функція працює й поза ним.
2. Хуки життєвого циклу чи inject (onMounted, onUnmounted, inject) - потрібен екземпляр компонента. Без нього Vue попередить, що хук викликано поза setup, і він не спрацює. Допоміжна функція монтує тимчасовий застосунок:
import { createApp } from 'vue'
function withSetup<T>(composable: () => T): [T, ReturnType<typeof createApp>] {
let result!: T
const app = createApp({
setup() {
result = composable()
return () => {}
},
})
app.mount(document.createElement('div'))
return [result, app]
}
it('removes the listener on unmount', () => {
const [{ width }, app] = withSetup(() => useWindowWidth())
// ...
app.unmount() // перевірити прибирання
})
Для inject перед монтуванням додають app.provide(Key, value).
Що перевіряти в composables:
- реакцію на зміну вхідних даних - якщо composable приймає ref чи геттер, змінити його й перевірити результат (з
await nextTick()дляwatch); - прибирання - обробники, таймери, підписки знімаються при розмонтуванні;
- асинхронні стани -
isLoading,error,dataпісля успішного й невдалого запиту (з замоканим API іflushPromises); - граничні випадки вхідних даних.
Коли краще тестувати через компонент: якщо composable тісно пов'язаний з конкретним компонентом і окремо не використовується - тест компонента покриє його природніше.
Composable, що приймає MaybeRefOrGetter, варто протестувати з усіма трьома формами аргументу: звичайним значенням, ref і геттером (toValue усередині).