Search code examples
javascriptnode.jscypress

Cypress - how to properly wait for result of an imported JS function


I would like to write a JS library as a wrapper to 3rd party APIs. I write the API wrapper as an individual file (instead of using Cypress Custom functions) because I believe I can share the library with teams NOT using Cypress E2E tool.

The problem I am facing is "I cannot let my code to be executed sequentially in order"

From the result, I can see:

  1. the data didn't return successfully
  2. it looks like the "getTestPlanIdByName:20974" were executed last, but I expect it should be executed before "line 01b testPlanId:{}"

I need to help to know the correct way to handle the flow sequentially in Cypress/Javascript, thanks.

enter image description here

API Library(api-util.js)

let axios = require('axios'); 
const proxy = "http://10.8.8.8:8080/";
const apiPatToken = 'OmdrvbvvvvvvvvWZqa2E='

let proxyAgentHttps = require('https-proxy-agent');
let proxyAgentHttp = require('http-proxy-agent');
let agentHttps = new proxyAgentHttps(proxy);
let agentHttp = new proxyAgentHttp(proxy);

let config = {
  baseURL: 'https://dev.3rdparty.com/mycompany/myaccount/_apis',
  url: 'DUMMY_INJECTED_LATER',
  httpsAgent: agentHttps,
  httpAgent: agentHttp,
  proxy:false,
  headers: {
    'Authorization': `Basic ${apiPatToken}`
  }
}

export async function getTestPlanIdByName(testplan_name){
  config.url = '/test/plans?api-version=5.0'
  let found = ''
  axios.request(config).then( resp => {
    found = resp.data.value.find(function(item, index, array){
      return item.name === testplan_name
    })
  })
  .then(() => {
    console.log("getTestPlanIdByName:"+found.id)
    return found.id
  })
  .catch(err => console.log(err))
}

My Cypress code

import * as UTIL from 'api-util.js'

describe('CI-', () => {
  let testPlanId = 'none'

  it('01 Get TestPlanID', () => {
    //use cy.log() get a Promise for flow control
    cy.log() 
    .then(() => {   
      new Cypress.Promise((resolve, reject) => {
        console.log("01a testPlanId:"+JSON.stringify(testPlanId))
        testPlanId = UTIL.getTestPlanIdByName("TESTPLAN-Regression") 
        console.log("01b testPlanId:"+JSON.stringify(testPlanId))
      })
    })
    .then(() => {   
      console.log("01c testPlanId:"+JSON.stringify(testPlanId))
    })
  });

  it('02 Get TestSuitesList', () => {
    console.log("02 testPlanId:"+testPlanId)
    // UTIL.getTestSuitesIdList(testPlanId)
  });
});

Solution

  • Cypress flow isn't 100% compatible with standard JS Promise (Wait for an own function (which returns a promise) before tests are executed). After relentless testing, I decided to use a Cypress Custom Command wrapper to wrap my in-house JS library. Although adding an extra layer may seem a little cumbersome, I am satisfied with the result.

    Cypress Code

      before('Prepare TestPlanId', () => {
        cy.getTestPlanIdByName(testPlanName)
        .then((result) => {
          testPlanId = result
          console.log("#01_SDET_testplan:Prepare TestPlanId# "+testPlanId)
        })
      });
    

    Cypress Custom Command

    Cypress.Commands.add('getTestPlanIdByName', (wk_testplan_name) => {
      return new Cypress.Promise((resolve, reject) => {
        TESTPLAN_API.getTestPlanIdByName(wk_testplan_name)
        .then(function (data) {
          resolve(data);
        })
      });
    })
    

    In-house JS library

    export async function getTestPlanIdByName(wk_testplan_name){
    
      return new Promise((resolve, reject) => {
          config.method = 'get'
          config.url = '/test/plans?api-version=5.0'
          let found = ''
    
          axios.request(config).then( resp => {
            found = resp.data.value.find(function(item, index, array){
              return item.name === wk_testplan_name
            })
          })
          .then(() => {
            resolve(found.id)
          })
          .catch(err => console.log(err))
      })
    }