Tests d'API Cypress : Comment tester les API avec cy.request()

Apprenez les tests d'API Cypress avec cy.request() : envoyer des requêtes, vérifier le statut et le corps, réutiliser les jetons d'authentification et simuler le trafic du navigateur avec cy.intercept().

INEZA Felin-Michel

INEZA Felin-Michel

7 July 2026

Tests d'API Cypress : Comment tester les API avec cy.request()

Apidog pour les entreprises

Déploiement sur site

SSO & RBAC

Conforme SOC 2

Découvrir Apidog Enterprise

Vous utilisez déjà Cypress pour vos tests de bout en bout. Maintenant, vous voulez interroger une API directement, vérifier le code de statut et faire des assertions sur le corps JSON sans passer par l'interface utilisateur. Cypress peut le faire. La commande cy.request() envoie de vraies requêtes HTTP depuis Node, en dehors du navigateur, vous permettant ainsi de tester un point de terminaison de manière isolée ou de configurer l'état avant l'exécution d'un test d'interface utilisateur.

Ce guide vous montre comment tester des API avec Cypress : les bases de cy.request(), l'assertion sur les réponses, l'enchaînement de requêtes pour réutiliser un jeton d'authentification, et la simulation du trafic navigateur avec cy.intercept(). Vous verrez également quand Cypress est un bon choix pour les API et quand un outil natif pour API est plus approprié.

bouton

Pourquoi tester les API avec Cypress

La plupart des suites Cypress pilotent un navigateur. Mais une grande partie de ce que vous vérifiez dans l'interface utilisateur est en fait l'API sous-jacente : est-ce que /login renvoie un jeton, est-ce que /users renvoie la bonne structure, est-ce qu'une requête POST crée l'enregistrement attendu.

Tester ces points de terminaison directement présente deux avantages. Premièrement, les vérifications d'API s'exécutent plus rapidement que les flux d'interface utilisateur car il n'y a pas de rendu, pas d'attente d'éléments. Deuxièmement, vous pouvez utiliser cy.request() pour configurer les données de test. Au lieu de parcourir un formulaire d'inscription pour créer un utilisateur, vous envoyez une seule requête POST et passez à l'assertion qui vous intéresse réellement.

Si Cypress fait déjà partie de votre pile technologique, l'ajout de tests d'API signifie qu'aucun nouvel outil n'est à installer. Vous les écrivez dans les mêmes fichiers de spécification, avec les mêmes assertions expect, lors de la même exécution CI.

Les bases de cy.request()

cy.request() effectue une requête HTTP et renvoie la réponse. Elle s'exécute depuis le processus Node de Cypress, et non depuis le navigateur, elle n'est donc pas soumise aux règles CORS ou de même origine.

La commande accepte plusieurs formes :

cy.request(url)
cy.request(url, body)
cy.request(method, url)
cy.request(method, url, body)
cy.request(options)

L'appel le plus simple passe une URL. Sans méthode, Cypress utilise GET par défaut :

cy.request('https://jsonplaceholder.typicode.com/users')

Pour toute requête au-delà d'un simple GET, passez un objet d'options. Cela vous donne un contrôle total sur la méthode, le corps et les en-têtes :

cy.request({
  method: 'POST',
  url: 'https://jsonplaceholder.typicode.com/posts',
  headers: {
    'Content-Type': 'application/json'
  },
  body: {
    title: 'API test',
    body: 'created from Cypress',
    userId: 1
  }
})

Options utiles pour cet objet :

Cette dernière option est importante pour les tests négatifs. Par défaut, cy.request() fait échouer le test pour tout statut non 2xx ou non 3xx. Si vous vérifiez qu'une mauvaise requête renvoie 400, vous devez désactiver cette option :

cy.request({
  method: 'GET',
  url: 'https://jsonplaceholder.typicode.com/users/99999',
  failOnStatusCode: false
}).then((response) => {
  expect(response.status).to.eq(404)
})

Assertions sur le statut et le corps de la réponse

cy.request() renvoie un objet de réponse. Chaînez .then() pour le lire. La réponse possède quatre propriétés que vous utiliserez le plus souvent :

Voici un test complet qui vérifie le statut, la structure du corps et un champ spécifique :

describe('Users API', () => {
  it('returns a list of users', () => {
    cy.request('https://jsonplaceholder.typicode.com/users').then((response) => {
      expect(response.status).to.eq(200)
      expect(response.body).to.be.an('array')
      expect(response.body).to.have.length(10)
      expect(response.body[0]).to.have.property('email')
    })
  })
})

Étant donné que response.body est déjà un objet parsé, vous pouvez faire des assertions dessus avec Chai standard. Vous pouvez vérifier le type, la longueur, les propriétés imbriquées ou les valeurs exactes. C'est la même syntaxe d'assertion que celle que vous utilisez pour les tests d'interface utilisateur, il n'y a donc rien de nouveau à apprendre.

Vous pouvez également faire des assertions sur les en-têtes de réponse, ce qui est pratique pour vérifier le type de contenu ou la mise en cache :

cy.request('https://jsonplaceholder.typicode.com/users').then((response) => {
  expect(response.headers['content-type']).to.include('application/json')
})

Pour une étude plus approfondie de la structuration de ces vérifications, consultez notre guide sur les assertions d'API et les plus larges meilleures pratiques de test d'API.

Enchaîner les requêtes et réutiliser un jeton d'authentification

Les API réelles nécessitent une authentification. Le schéma courant est de se connecter une fois, de récupérer le jeton, puis de l'envoyer avec chaque requête subséquente. cy.request() s'enchaîne de manière fluide pour cela.

Envoyez la requête de connexion, lisez le jeton du corps de la réponse, puis utilisez-le dans l'appel suivant :

describe('Authenticated API flow', () => {
  it('logs in and fetches a protected resource', () => {
    cy.request({
      method: 'POST',
      url: 'https://api.example.com/login',
      body: {
        email: 'user@example.com',
        password: 'secret'
      }
    }).then((loginResponse) => {
      expect(loginResponse.status).to.eq(200)
      const token = loginResponse.body.token

      cy.request({
        method: 'GET',
        url: 'https://api.example.com/profile',
        headers: {
          Authorization: `Bearer ${token}`
        }
      }).then((profileResponse) => {
        expect(profileResponse.status).to.eq(200)
        expect(profileResponse.body).to.have.property('email', 'user@example.com')
      })
    })
  })
})

Si plusieurs tests ont besoin du même jeton, déplacez la connexion dans un beforeEach et stockez le jeton avec Cypress.env() ou un alias enveloppé afin que chaque test puisse le récupérer. Cela permet de centraliser la configuration de l'authentification au lieu de la répéter dans chaque spécification.

Ce modèle de connexion puis d'utilisation est le même que celui que vous écririez dans tout flux de tests d'intégration d'API, où un appel alimente le suivant en données.

cy.intercept() pour la simulation

cy.request() interroge la véritable API. Parfois, vous voulez l'inverse : intercepter les requêtes faites par votre application front-end et renvoyer une fausse réponse. C'est le rôle de cy.intercept().

Il y a une distinction importante ici. cy.intercept() n'intercepte que les requêtes faites par votre application front-end dans le navigateur. Il n'intercepte pas cy.request(), car cy.request() contourne entièrement le navigateur. Utilisez cy.intercept() lorsque vous testez la façon dont votre interface utilisateur réagit à une réponse API donnée, et non lorsque vous testez l'API elle-même.

Vous pouvez espionner une requête, la simuler avec une réponse statique, ou l'attendre. Pour simuler, passez un objet de réponse :

cy.intercept('GET', '/api/users', {
  statusCode: 200,
  body: [{ id: 1, name: 'Ada' }]
})

Désormais, toute requête de navigateur vers /api/users renvoie cette charge utile fixe. Cela vous permet de tester des cas limites difficiles à déclencher sur un backend en production, comme une liste vide, une erreur 500, ou une réponse lente.

Pour affirmer que la requête a eu lieu, aliassez-la avec .as() et attendez-la :

it('shows an error banner when the API fails', () => {
  cy.intercept('GET', '/api/users', {
    statusCode: 500,
    body: { message: 'Server error' }
  }).as('getUsers')

  cy.visit('/dashboard')
  cy.wait('@getUsers').its('response.statusCode').should('eq', 500)
  cy.contains('Something went wrong').should('be.visible')
})

La ligne cy.wait('@getUsers') met le test en pause jusqu'à ce que la requête interceptée soit résolue, puis vous fournit la requête et la réponse pour faire des assertions. Configurez l'interception avant l'action qui déclenche la requête, sinon elle ne capturera rien. Si vous hésitez entre simuler une réponse et mocker un service entier, nos articles sur le mocking d'API et la simulation d'API vs mocking d'API détaillent les compromis.

Quand Cypress est pertinent pour les API, et quand il ne l'est pas

Cypress est un excellent choix pour les vérifications d'API qui s'inscrivent dans une suite de tests d'interface utilisateur. Si vous écrivez déjà des tests de bout en bout et que vous avez besoin d'amorcer des données, de vérifier un point de terminaison dont votre interface utilisateur dépend, ou de simuler une réponse pour tester la gestion des erreurs, cy.request() et cy.intercept() centralisent tout. Pas de changement de contexte, pas de deuxième outil.

C'est également approprié pour quelques tests de fumée API autonomes lorsque Cypress est votre seul exécutant de tests et que vous ne voulez pas ajouter une autre dépendance.

Cela devient moins pratique pour une suite de tests API volumineuse et autonome. Cypress a été conçu pour le navigateur, le test d'API est donc une capacité ajoutée par-dessus, et non la conception fondamentale. Quelques lacunes apparaissent à mesure que la suite s'agrandit :

C'est là qu'un outil natif pour API est plus approprié. Apidog est conçu autour de l'API elle-même : vous concevez un point de terminaison une seule fois, puis construisez des scénarios de test contre celui-ci avec un constructeur de requêtes visuel et des assertions visuelles, sans nécessiter de code pour les cas courants. Les requêtes, les environnements et l'authentification résident dans un espace de travail partagé, ainsi votre équipe n'a pas à les redériver à partir des fichiers de test.

Pour l'intégration continue (CI), l'interface en ligne de commande (CLI) d'Apidog exécute vos scénarios de test enregistrés en mode sans affichage dans toute étape pouvant exécuter Node :

npm install -g apidog-cli

apidog run \
  --access-token "$APIDOG_ACCESS_TOKEN" \
  -t <scenarioOrSuiteId> \
  -e <environmentId> \
  -r cli,html,junit

L'option -t cible un scénario ou une suite enregistrée, -e sélectionne un environnement, et -r choisit les formats de rapport (cli, html, json, junit). La sortie JUnit s'intègre directement dans la plupart des tableaux de bord CI. Ajoutez -d ou --iteration-data pour exécuter un test à partir d'un fichier de données, et --upload-report pour envoyer les résultats à votre espace de travail. La CLI exécute des scénarios enregistrés ; ce n'est pas un expéditeur de requêtes interactif.

Une façon utile de voir les choses : utilisez cy.request() pour les vérifications d'API qui supportent vos tests de navigateur, et optez pour un outil natif pour API lorsque le test d'API est la tâche principale. Si vous comparez les options, nos récapitulatifs des outils d'automatisation des tests API qui s'exécutent en CI/CD et des plus larges 30 meilleurs outils de test API couvrent le domaine.

FAQ

Est-ce que cy.request() s'exécute dans le navigateur ?

Non. cy.request() s'exécute depuis le processus Node de Cypress, en dehors du navigateur. C'est pourquoi elle n'est pas bloquée par la politique CORS ou de même origine, et pourquoi cy.intercept() ne peut pas l'intercepter. Si vous avez besoin d'une requête effectuée par le navigateur, déclenchez-la via votre application et capturez-la avec cy.intercept().

Comment tester une réponse 400 ou 404 sans faire échouer le test ?

Par défaut, cy.request() échoue pour tout statut non 2xx ou non 3xx. Définissez failOnStatusCode: false dans l'objet d'options, puis faites vous-même une assertion sur le statut avec expect(response.status).to.eq(404).

Puis-je utiliser cy.request() pour me connecter avant un test d'interface utilisateur ?

Oui, et c'est un schéma courant. Envoyez une requête POST à votre point de terminaison de connexion avec cy.request(), lisez le jeton depuis response.body, et stockez-le (dans Cypress.env(), localStorage, ou un cookie) afin que votre test d'interface utilisateur démarre déjà authentifié. Cela contourne le formulaire de connexion et accélère la suite.

Quelle est la différence entre cy.request() et cy.intercept() ?

cy.request() envoie une vraie requête HTTP et renvoie la réponse réelle, vous l'utilisez donc pour tester une API. cy.intercept() surveille ou simule les requêtes que votre front-end effectue dans le navigateur, vous l'utilisez donc pour contrôler ce que votre interface utilisateur reçoit. L'une interroge le réseau ; l'autre le façonne.

Devrais-je utiliser Cypress ou un outil dédié pour les tests d'API ?

Utilisez Cypress lorsque les vérifications d'API supportent une suite de tests de navigateur que vous exécutez déjà. Pour une suite API autonome volumineuse, des pipelines API uniquement CI, ou une définition d'API partagée à partir de laquelle toute votre équipe travaille, un outil natif pour API comme Apidog est plus adapté. Consultez nos bonnes pratiques de test d'API pour savoir comment décider.

Pratiquez le Design-first d'API dans Apidog

Découvrez une manière plus simple de créer et utiliser des API