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.
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) => {