Cypress: Issues with request() with each loop

Viewed 1265

I'm working on a test-framework with Cypress and facing an issue where I try to perform an each loop on and each iteration performs a request function on an <a> tag, then perform an assertion that the response contains specifics values from a regex expression. I can see it start performing the request link, but apparently the body from the response is so large that the browser stops running visually showing the Cypress UI to freeze or appear to be unresponsive. (The test might still be running, but the Cypress UI appears to be frozen or very chuggy.)

I've tried looking for solutions about this issue, but nothing shows up as a solution or alternative to my predicament. I have thought of using a for each loop to go through the tags, but I think would be slower and worse off then what I have right now. Has anyone come across this when working with Cypress?

Code: Function test to view and validate content links for the list

const steamHeader = new SteamGlobalHeader(cy);

steamHeader.getActionSection().get('#language_dropdown')
            .within(() => {
                const langList = '/^schinese|tchinese|japanese|koreana'+
                '|thai|bulgarian|czech|danish|german|spanish|latam|greek'+
                '|french|italian|hungarian|dutch|norwegian|polish|portuguese'+
                '|brazilian|romanian|russian|finnish|swedish|turkish'+
                '|vietnamese|http://translation.steampowered.com$/';
                steamHeader.get('a[class="popup_menu_item tight"]').should('have.length', 28)
                .each(($a) => {
                    steamHeader.inspectRequestURL(steamHeader.get($a), 'href', 'body', langList);
                });

            });

Function for inspectRequestURL() (Part of Base Page for POM using Cypress)

inspectRequestURL(givenValue, propValue, requestSection, requestTarget){
        givenValue.then(($a) => {
            const prop = $a.prop(propValue);

            this.cy.request(prop).its(requestSection).should('include', requestTarget);
        })
    }
1 Answers

While this may not be the solution for everyone. Some suggested that I create a task (cy.task()) and use code from Node js to handle the request. For my requests, I used axios package to handle get requests and return a boolean if content matches value, as well as status code.

EDIT: However, I still see the assert fails due to timeouts about midway through my list or near the end. I retested this again a few days later with Steam website, and now my test runs can be completed without issue within 1.5 minutes. I did create an alternate approach to perform requests for all links at once instead of going through the iteration. (Completion time was faster by at least 10 seconds.)

Edit: (Old Approach): Task found in cypress/plugins/index.js:

const axios = require('axios').default;
 // use axios
module.exports = (on, config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config
  on('task', {
    //Work on request and return, learn what gets returned
    getURLBodyResponseContains: ({href, target}) => {
        return axios.get(href)
          .then( (response) => {
            //console.log('target: '+ target);
            if (response.data.match(target)) {
              return { answer: true, status: response.status };
            } else {
              return { answer: false, status: response.status };
            }
          })
          .catch((error) => console.log(error));
          
          
    }
})

Test Code:

it.only('Test Lanuage list', () => {
        const steamHeader = new SteamGlobalHeader(cy);

        steamHeader.getActionItem('span', 'language').click();

        steamHeader.getActionSection().get('#language_dropdown')
            .within(() => {
                const langList = /^schinese|tchinese|japanese|koreana|thai|bulgarian|czech|danish|german|spanish|latam|greek|french|italian|hungarian|dutch|norwegian|polish|portuguese|brazilian|romanian|russian|finnish|swedish|turkish|vietnamese|Steam Translation Server/;
                steamHeader.get('a[class="popup_menu_item tight"]').as('languageLinks');
                steamHeader.get('@languageLinks').should('have.length', 28);
                
                steamHeader.get('@languageLinks').each(($a) => {
                    steamHeader.getCy().task('getURLBodyResponseContains', {href: $a.prop('href'), target: langList}, {timeout: 100000}).as('returnValue');
                    steamHeader.get('@returnValue').its('status').should('equal', 200);
                    steamHeader.get('@returnValue').its('answer').should('be.true');
                    
                });
            });

    });

New Approach: I retested my test code a few days later, and now I'm not hitting the timeout issues in high frequency. While to trying to figure out alternatives, I came up with an approach of performing requests for all at once instead one by one. Once the requests are all done, return the outcome back as one array, then perform a forEach loop, wrap the object's properties and run your set of assertions. Using this approach, I noticed the test time was 10 seconds faster.

Task Code:

const axios = require('axios').default;
 // use axios
module.exports = (on, config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config
  on('task', {
    //Work on request and return, learn what gets returned
    getURLBodyResponseContains: ({href, target}) => {
        return axios.get(href)
          .then( (response) => {
            //console.log('target: '+ target);
            if (response.data.match(target)) {
              return { answer: true, status: response.status };
            } else {
              return { answer: false, status: response.status };
            }
          })
          .catch((error) => console.log(error));  
    },

    getURLListBodyResponseContains: ({hrefList, target}) => {
     return Promise.all(hrefList.map((href) => {
// Would have wanted to reuse the task from above, but not sure you could reuse a  task within a task.
        return checkIfRequestContains(href, target);
      }))
        .then((result) => {
          return result;
        })
        .catch((error) => console.log(error));
    }
  })
}

function checkIfRequestContains(url, target){
  return axios.get(url)
  .then( (response) => {
    //console.log('target: '+ target);
    if (response.data.match(target)) {
      return { answer: true, status: response.status };
    } else {
      return { answer: false, status: response.status };
    }
  })
  .catch((error) => console.log(error)); 
}

Test Code:

it('Test Language list', () => {
        const steamHeader = new SteamGlobalHeader(cy);

        steamHeader.getActionItem('span', 'language').click();

        steamHeader.getActionSection().get('#language_dropdown')
            .within(() => {
                const langList = /^schinese|tchinese|japanese|koreana|thai|bulgarian|czech|danish|german|spanish|latam|greek|french|italian|hungarian|dutch|norwegian|polish|portuguese|brazilian|romanian|russian|finnish|swedish|turkish|vietnamese|Steam Translation Server/;
                steamHeader.get('a[class="popup_menu_item tight"]').as('languageLinks');
                steamHeader.get('@languageLinks').should('have.length', 28);

                //This using task on whole array.
                let urlList = [];
                steamHeader.get('@languageLinks').each(($a) => {
                    urlList.push($a.prop('href'));
                });
                steamHeader.getCy().task('getURLListBodyResponseContains', {hrefList: urlList, target: langList}, {timeout: 100000}).as('returnValue');
                steamHeader.get('@returnValue').then(($value) => {
                    console.log($value);
                    $value.forEach((val) => {
                        console.log(val);
                        steamHeader.getCy().wrap(val).its('status').should('eq', 200);
                        steamHeader.getCy().wrap(val).its('answer').should('be.true');
                    })
                }); 


                //This approach using each loop
               /* steamHeader.get('@languageLinks').each(($a) => {
                    steamHeader.getCy().task('getURLBodyResponseContains', {href: $a.prop('href'), target: langList}, {timeout: 100000}).as('returnValue');
                    steamHeader.get('@returnValue').its('status').should('equal', 200);
                    steamHeader.get('@returnValue').its('answer').should('be.true');
                    
                }); */
            });

    })
Related