Skip to content

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

I am new to Cypress (and naive to JS). 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)
  });
});

Answer

Thank you all. 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 testings, I decided to use a Cypress Custom Command wrapper to wrap my in-house JS library. Though adding an extra layer may seem a little cumbersome. But I am satisfied with the result. Share my code here in case anyone might need it. 🙂

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