简体   繁体   中英

Cypress: Custom command returns array: How loop to run test suite?

Problem:

Trying to call tests within an array of items returned from a Cypress custom command.

Approaches attempted using npm package mocha-each and another test using the forEach function.

Custom Command:

I created a custom Cypress command that returns an array of AppParamsType :

/// <reference types="Cypress" />

import { AppParamsType } from 'support';

declare global {
  namespace Cypress {
    interface Chainable {
      cmdGetAppsParams: () => Chainable<AppParamsType[]>;
    }
  }
}

export function cmdGetAppsParams() {
  const paramsApps: AppParamsType[] = [];

  cy.cmdAppKeys()
    .then(($appKeys: string[]) => {
      cy.wrap($appKeys).each(($appKey: string) => {
        cy.cmdProviderAppParams($appKey).then((paramApp: AppParamsType) => {
          paramsApps.push(paramApp);
        });
      });
    })
    .then(() => {
      return cy.wrap(paramsApps);
    });
}

Cypress.Commands.add('cmdGetAppsParams', cmdGetAppsParams);

Test using Custom Command:

The following Cypress test calls the custom command cmdGetAppsParams() to return an array of items.

The array is being iterated with one test using npm package mocha-each and another test using Array forEach . Neither approach calls the tests within the loops.

import * as forEach from 'mocha-each';

let apps: AppParamsType[];

describe('DESCRIBE Apps Add Apps Spec', () => {
  before('BEFORE', () => {
    cy.cmdGetAppsParams().then(($apps: AppParamsType[]) => {
      expect($apps).to.be.an('array').not.empty;
      apps = $apps;
    });
  });

  it('TEST Apps Params Array', () => {
    cy.task('log', { line: 'A', data: apps });
    expect(apps).to.be.an('array').not.empty;
  });

  it('TEST each item mocha forEach', () => {
    cy.task('log', { line: 'B', data: apps });
    forEach(apps).it('item', (item: AppParamsType) => {
      cy.task('log', { line: 'B.1', data: item });
      expect(item).to.be.an('object').not.null;
    });
  });

  it('TEST each item array forEach', () => {
    cy.task('log', { line:'C', data: apps });
    expect(apps).to.be.an('array').not.empty;
    apps.forEach((item: AppParamsType) => {
      it('TEST App Param', () => {
        cy.task('log', { line: 'C.1', data: item });
        expect(item).to.be.an('object').not.null;
      });
    });
  });

The results I am seeing is that the outer tests, indicated by labels 'A' , 'B' and 'C' , are getting called. But, not the inner tests, which would be indicated by labels 'B.1' and 'C.1' :

{
  "line": "A",
  "data": [
    ***
  ]
}
{
  "line": "B",
  "data": [
    ***
  ]
}
{
  "line": "C",
  "data": [
    ***
  ]
}

Nesting an it() inside an it() looks novel. I'm surprised you are not getting an error from it.

The basic problem when generating tests dynamically is that the Cypress runner needs to know exactly how many tests will be generated before it starts running them. But any Cypress commands (including custom commands) will not run until the entire test script has finished running (excluding callback code), so you can't get the apps list from a custom command.

The best way to proceed is to convert cy.cmdAppKeys() , cy.cmdGetAppsParams() , and cy.cmdProviderAppParams() from custom commands to a plain javascript function, and then run that function at the top of the script, eg

const apps = getMyApps();  // synchronous JS function, 
                           // will run as soon as the test starts

apps.forEach((item: AppParamsType) => {

  const titleForTest = `Test App Param ${item.name}`; // Construct an informative title
  it(titleForTest, () => {
    ...
  })
})

If you can provide details of the custom commands cy.cmdAppKeys() and cy.cmdProviderAppParams() , may be able to help convert to the synchronous function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM