Warm tip: This article is reproduced from serverfault.com, please click

How to dynamically generate Cypress tests based on data received in `before()`?

发布于 2020-11-28 04:22:33

This example is very close to what I need, except that the urls are not known ahead of time (can't hardcode them).

The urls are generated in the before() hook by running a script:

before(() => {
  cy.exec(<run script that generates a temporary urls.json file>);
  cy.readFile("./urls.json")....
});

How could I dynamically generate separate tests based on the generated urls.json?

The reason they need to be separate tests is this.

Questioner
Misha Moroshko
Viewed
0
Richard Matsen 2020-11-29 03:26:30

The test enumerator .forEach() runs before the before() hook, but that's ok if you know exactly how many urls you need to process.

In the Cypress example you cited, setting urls in before().

let urls = []; 

describe('Logo', () => {

  before(() => {
    cy.exec('npm run generator')
      .then(() => {  // writing the file will be async
        cy.readFile("./urls.json").then(data => {
          urls = data;
      });
    });
  })

  Cypress._.range(0, 2).forEach(index => {       // only need the number of tests here

    it(`Should display logo #${index}`, () => {
      const url = urls[index]                    // runs after before()
      cy.visit(url)
      ...
    })
  })
})

Note, url can't be in the test description any more, but index can.

If the number of urls is unknown, it is still technically possible by setting the test enumerator to a maximum, but the results in the log are messy. Unused test slots still show as passing.


The basic problem is the generator script needs to run in the Cypress Node process, but the spec runs in the browser process.

But ipc communication between browser and node is done via async cy.* commands that can only run in callbacks, which can only run during the execution phase.

You would be better off running the generator script externally, something like

"scripts": {
  "gen:test": "npm run generator & cypress open"
}

then using a simple require() to pick up the data

const data = require('./urls.json')
let urls = data.urls;
const testCount = data.urls.length;  

describe('Logo', () => {

  before(() => {
    // not required
  })

  Cypress._.range(0, testCount).forEach(index => {

  or

  urls.forEach((url, index) => {