web-dev-qa-db-fra.com

Cypress.io Comment gérer le code asynchrone

Je suis en train de déplacer nos anciens tests de capybara vers cypress.io car notre application va de manière SPA.

Dans notre cas, nous avons plus de 2000 tests couvrant de nombreuses fonctionnalités. Le modèle le plus courant pour tester la fonctionnalité est d'avoir un utilisateur avec une offre créée et publiée.

Au début, j'ai écrit un cas où le cyprès allait à travers la page et cliquait sur tout. Cela a fonctionné, mais j'ai vu que l'offre de création + publication a pris près de 1,5 minute pour se terminer. Et parfois, nous avons besoin de plusieurs offres. Nous avons donc un test qui prend 5 minutes et il nous reste 1999 à réécrire.

Nous avons trouvé REST API pour créer l'offre et l'utilisateur, essentiellement un raccourci pour la préparation d'env test.

Je suis arrivé au point où tout fonctionne avec async/await. Voici donc la chose. Si je veux utiliser du code JS asynchrone normal avec du cyprès, j'obtiens Error: Cypress detected that you returned a promise from a command while also invoking one or more cy commands in that promise.

Voici à quoi cela ressemble:

    const faker = require('faker')
    import User from '../../support/User';

    describe('Toggle button for description offer', () => {
      const user = new User({
        first_name: faker.name.firstName(),
        last_name: faker.name.firstName(),
        email: `QA_${faker.internet.email()}`,
        password: 'xxx'
      })
      let offer = null

      before(async () => {
        await user.createOnServer()
        offer = await user.createOffer()
        await offer.publish()
      })

      beforeEach(() => {
        user.login()
        cy.visit(`/offers/${offer.details.id}`)
        cy.get('.offer-description__content button').as('showMoreButton')
      })

      it('XXX', function () {
        ...some test
      })
    })

Cet extrait fonctionne comme prévu. Premièrement, il se déclenche avant et crée un environnement entier puis, une fois terminé, il va plus loin à beforeEach et commence les tests.

Maintenant, je voudrais fusionner avant et avant

  before(async () => {
    await user.createOnServer()
    offer = await user.createOffer()
    await offer.publish()
    user.login()
    cy.visit(`/offers/${offer.details.id}`)
    cy.get('.offer-description__content button').as('showMoreButton')
  })

Ce qui échouera en raison du mot clé async. Maintenant, la question est: comment le réécrire pour utiliser ensemble les commandes async/wait et cypress? J'ai essayé de le réécrire avec Promise normal mais ça ne marchera pas trop ...

Toute aide appréciée.

7
Daniel Słaby

Votre problème vient du fait que les commandes de cyprès ne sont pas des promesses , bien qu'elles se comportent comme des promesses.

Je peux penser à deux options:

  • Essayez de refactoriser votre code de test pour ne pas utiliser async/wait, car ces commandes ne se comportent pas comme prévu lors de l'exécution de votre code sur cypress (vérifiez ceci bug ). Cypress a déjà toute une façon de gérer le code asynchrone car il crée une file d'attente de commandes qui s'exécute toujours de manière séquentielle et dans l'ordre attendu. Cela signifie que vous pouvez observer les effets de votre code asynchrone pour valider qu'il s'est produit avant de poursuivre votre test. Par exemple, si User.createUserOnServer doit attendre un appel d'API réussi, ajoutez du code à votre test qui attendra la fin de la demande, en utilisant cy.server (), cy.route () et cy.wait () , comme au dessous de:

    cy.server();
    cy.route('POST', '/users/').as('createUser');
    // do something to trigger your request here, like user.createOnServer()
    cy.wait('@createUser', { timeout: 10000});
    
  • Utilisez une autre bibliothèque tierce qui modifie le fonctionnement de cypress avec async/wait, comme cypress-promise . Cette bibliothèque peut vous aider à traiter les commandes de cyprès comme des promesses que vous pouvez await dans votre code before (en savoir plus à ce sujet article ).

6
Guilherme Lemmi

J'ai un problème similaire concernant async/wait à l'intérieur des blocs it/test. J'ai résolu mon problème en enveloppant le corps dans un async IIFE:

describe('Test Case', () => {
  (async () => {
     // expressions here
  })()
})
2
isotopeee