Cypress.io How to handle async code

一笑奈何 提交于 2019-12-20 01:14:05

问题


I'm in the middle of process of moving our old capybara tests to cypress.io as our application is going SPA way.

In our case we have over 2000 tests covering a lot of features. So common pattern to test feature is to have an user with created and published offer.

On the beginning I wrote case where cypress were going trough page and clicking everything. It worked but I saw that offer create + publish took almost 1,5 minute to finish. And sometimes we need multiple offers. So we have a test which takes 5 minutes and we have 1999 left to rewrite.

We came up with REST API to create offer and user, basically shortcut for test env preparation.

I came to the point where everything is working using async/await. So here's the thing. If I want to use normal async JS code with cypress I get Error: Cypress detected that you returned a promise from a command while also invoking one or more cy commands in that promise.

Here's how it looks like:

    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
      })
    })

This snippet works as expected. Firstly it fires before and creates whole env then when it's done it goes further to beforeEach and starts testing.

Now I would like to merge before and beforeEach like

  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')
  })

Which will fail because of async keyword. Now the question is: how to rewrite it to use async/await and cypress commands together? I tried to rewrite it with normal Promise but It won't work too ...

Any help appreciated.


回答1:


Your problem stems from the fact that cypress commands are not promises, although behaving like promises.

I can think of two options:

  • Try to refactor your test code to not use async/await, as these commands don't behave as expected when running your code on cypress (check this bug). Cypress already has a whole way of dealing with async code as it creates a command queue that always run sequentially and in the expected order. That means you could observe the effects of your async code to validate that it happened before moving forward on your test. For instance, if User.createUserOnServer must wait a successful API call, add code to your test that will wait for the request to complete, using cy.server(), cy.route() and cy.wait(), like below:

    cy.server();
    cy.route('POST', '/users/').as('createUser');
    // do something to trigger your request here, like user.createOnServer()
    cy.wait('@createUser', { timeout: 10000});
    
  • Use another third-party library that changes how cypress works with async/await, like cypress-promise. This lib may help you to treat cypress commands as promises that you can await in your before code (read more about it in this article).




回答2:


I'm having a similar issue regarding async/await inside it / test blocks. I solved my problem by wrapping the body inside an async IIFE:

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


来源:https://stackoverflow.com/questions/49980311/cypress-io-how-to-handle-async-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!