Back

Simuler les appels API dans les tests Vue avec Vitest

Simuler les appels API dans les tests Vue avec Vitest

Les composants Vue vivent rarement de manière isolée. La plupart d’entre eux récupèrent des données, soumettent des formulaires ou interrogent des endpoints. Lorsque vous testez ces composants sans contrôler le réseau, vos tests deviennent lents, instables et dépendants de services externes. Simuler les appels API dans les tests Vue permet d’éliminer ces problèmes en vous donnant le contrôle sur les réponses que vos composants reçoivent.

Cet article couvre deux stratégies pratiques pour simuler les API Vue avec Vitest : remplacer directement le module API avec vi.mock, et intercepter les requêtes au niveau de la couche HTTP en utilisant Mock Service Worker (MSW). Vous apprendrez également la gestion asynchrone spécifique à Vue qui rend ces deux approches fiables.

Points clés à retenir

  • Les appels réseau réels dans les tests produisent des résultats instables, lents et non déterministes — la simulation vous donne un contrôle total sur les réponses.
  • vi.mock remplace le module API au niveau de l’import, ce qui le rend idéal pour des tests unitaires rapides et isolés.
  • MSW intercepte les requêtes au niveau de la couche réseau, permettant à votre logique fetch ou axios réelle de s’exécuter pour des tests d’intégration plus réalistes.
  • flushPromises() de @vue/test-utils est généralement nécessaire lorsque les composants attendent des requêtes asynchrones avant de mettre à jour le DOM.

Pourquoi vous devez simuler les appels API dans les tests de composants Vue avec Vitest

Les appels réseau réels dans les tests produisent des résultats non déterministes. Le même test peut réussir localement et échouer en CI simplement parce qu’une API externe est lente ou indisponible. La simulation vous donne le contrôle sur ce que le réseau renvoie, afin que vos tests restent rapides et prévisibles.

Stratégie 1 : Simuler le module API avec vi.mock

L’approche la plus directe consiste à remplacer le module responsable des appels HTTP avant même que votre composant ne le voie.

// quote.service.ts
export async function fetchQuote() {
  const response = await fetch('https://api.example.com/quotes/random')
  return response.json()
}
// QuoteCard.test.ts
import { mount, flushPromises } from '@vue/test-utils'
import { vi, test, expect } from 'vitest'
import { fetchQuote } from './quote.service'
import QuoteCard from './QuoteCard.vue'

// vi.mock est automatiquement remonté au-dessus des imports
vi.mock('./quote.service')

test('affiche une citation après le montage', async () => {
  vi.mocked(fetchQuote).mockResolvedValue({
    id: 1,
    quote: 'Citation de test',
    author: 'Testeur',
  })

  const wrapper = mount(QuoteCard)

  // Attend que toutes les promesses en attente et les mises à jour du DOM se terminent
  await flushPromises()

  expect(wrapper.text()).toContain('Citation de test')
})

Un détail crucial : vi.mock est remonté en haut du fichier par Vitest, il s’exécute donc avant tout import. Il s’agit d’un comportement intentionnel documenté dans l’API de simulation Vitest. Cela signifie que vous pouvez importer en toute sécurité la fonction réelle et recevoir quand même la version simulée dans votre test.

L’appel à flushPromises() est souvent requis dans ce pattern. Les composants Vue qui récupèrent des données au montage mettent à jour leur DOM de manière asynchrone. Des utilitaires comme flushPromises garantissent que les promesses en attente se résolvent avant l’exécution des assertions, évitant ainsi que les tests n’effectuent des assertions sur des états de chargement.

Quand utiliser cette approche : Pour tester unitairement un composant ou un service spécifique de manière isolée, lorsque vous souhaitez un contrôle strict sur les valeurs de retour et le nombre d’appels.

Stratégie 2 : MSW avec les tests Vue Vitest pour la simulation au niveau HTTP

Mock Service Worker intercepte les requêtes au niveau de la couche réseau plutôt que de remplacer les modules JavaScript. Cela rend vos tests plus réalistes car l’appel fetch ou axios réel s’exécute toujours — MSW l’intercepte simplement avant qu’il ne quitte le processus.

Installez MSW et configurez-le pour un environnement Node (par défaut pour Vitest) :

npm install -D msw
// test/server.ts
import { setupServer } from 'msw/node'
import { http, HttpResponse } from 'msw'

export const server = setupServer(
  http.get('https://api.example.com/quotes/random', () => {
    return HttpResponse.json({ id: 1, quote: 'Citation MSW', author: 'MSW' })
  })
)
// QuoteCard.test.ts
import { mount, flushPromises } from '@vue/test-utils'
import { test, expect, beforeAll, afterEach, afterAll } from 'vitest'
import { server } from './test/server'
import QuoteCard from './QuoteCard.vue'

beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

test('affiche une citation récupérée via MSW', async () => {
  const wrapper = mount(QuoteCard)
  await flushPromises()
  expect(wrapper.text()).toContain('Citation MSW')
})

flushPromises() peut toujours être nécessaire ici pour la même raison — le système de réactivité de Vue a besoin d’un tick pour appliquer les mises à jour du DOM après la résolution de la promesse.

Quand utiliser cette approche : Pour des tests de type intégration où vous souhaitez vérifier que votre composant fonctionne avec un comportement HTTP réaliste, ou lorsque plusieurs composants partagent le même endpoint. La documentation de Vitest elle-même recommande MSW pour la simulation au niveau des requêtes dans les environnements de test basés sur Node.

Choisir entre vi.mock et MSW

vi.mockMSW
Intercepte au niveauModuleRéseau
Teste la logique fetch réelle
Contrôle par test✅ Facile✅ Via server.use()
Idéal pourTests unitairesTests d’intégration

Conclusion

Les deux stratégies sont des outils valides pour simuler les appels API dans les tests Vue. Utilisez vi.mock lorsque vous souhaitez des tests unitaires rapides et isolés avec un contrôle précis sur les valeurs de retour. Utilisez MSW lorsque vous souhaitez que vos tests exercent le chemin de requête complet. Dans les deux cas, des utilitaires comme flushPromises() aident à garantir que Vue termine le rendu des mises à jour asynchrones avant l’exécution des assertions.

FAQ

Oui. De nombreuses équipes utilisent vi.mock pour des tests unitaires ciblés de composants individuels et MSW pour des tests d'intégration plus larges qui couvrent plusieurs composants ou services. Gardez-les dans des fichiers de test séparés pour éviter toute confusion sur la couche qui gère la simulation.

Vue peut encore afficher l'état de chargement lorsque votre assertion s'exécute. Si votre assertion correspond par hasard au texte de chargement, le test réussit par coïncidence. L'avertissement de la console signale généralement des rejets de promesses non gérés ou des awaits manquants. Appeler flushPromises après le montage de composants qui déclenchent des requêtes asynchrones aide à éviter ces problèmes de timing.

MSW intercepte au niveau de la couche réseau, il fonctionne donc avec n'importe quel client HTTP incluant axios, fetch et les bibliothèques construites par-dessus comme ky ou got. Votre choix de client HTTP n'affecte pas la façon dont MSW gère l'interception.

Avec vi.mock, appelez mockRejectedValue pour simuler une erreur asynchrone levée. Avec MSW, utilisez server.use à l'intérieur d'un test spécifique pour enregistrer un gestionnaire qui renvoie HttpResponse.json avec un code de statut 4xx ou 5xx. Les deux approches vous permettent de vérifier la gestion des erreurs de votre composant.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay