Antonio Dragos
Antonio Dragos

Reputation: 2803

wait for service to return a non-empty response in Cypress test

In my Cypress test suite I have a command that makes an API call to an email service looking for an email with a particular subject and returns the content of that email.

Cypress.Commands.add('getMostRecentEmail', subject => {
  const requestUrl = new URL('api/mails', 'localhost')
  requestUrl.port = '3000'
  requestUrl.searchParams.append('subject', subject)

  // TODO: wait for the following request to return a non-empty response.body

  return cy.request('GET', requestUrl.toString()).then(response => {
    return response.body[0].content[0].value
  })
})

This works fine when I run the test locally, but when the test is run on CI, it fails the first time, but succeeds when Cypress automatically retries the test. Presumably this is because the email has not yet been received the first time an attempt to is made to retrieve it (the email is sent immediately before the code above executes).

response.body is the number of matching emails returned by the service, and the first time a request is made, this is empty, so response.body[0] is undefined.

Cypress reports this test as "flakey" because it doesn't succeed the first time it is attempted.

To fix this, I would like to instead wait for the request to return a non-empty response before retrieving the content of the first email.

Upvotes: 0

Views: 1824

Answers (2)

gleb bahmutov
gleb bahmutov

Reputation: 1919

Take a look at https://slides.com/bahmutov/email-testing presentation. In particular, the blog post https://www.cypress.io/blog/2021/05/24/full-testing-of-html-emails-using-ethereal-accounts/#retry-email-task talks how to retry getting the email, since it can happen only after some unknown time.

Upvotes: 1

feedy
feedy

Reputation: 1140

Create a function for your request that you can call recursively:

function makeRequestRecursively() {
    cy.request('GET', requestUrl.toString()).then(response => {
        let value = response.body[0].content[0].value;
        if (response.body[0].content[0].value != undefined) {
            return value;
        }
        else {
            // Recursively call the function after 0.5 seconds. You can adjust or remove this.
            setTimeout(function (){
                return makeRequestRecursively();        
            }, 500);
        }
    }
}

Replace:

return cy.request('GET', requestUrl.toString()).then(response => {
    return response.body[0].content[0].value
})

With:

return makeRequestRecursively()

Upvotes: 0

Related Questions