How can I get an array of URLs from the Cypress environment variable and then loop over them and run the tests for each one individually?

Viewed 202

In my cypress.json file I have the following

{
    "env":{
        "urls":["https://somedomain/index.html","https://someotherdomain/index.html"]
    }
}

Then in my spec.js file I have

describe('Test', () => { 
    Cypress.env('urls').forEach(url => {
        before(() => {
            cy.visit(url) 
        })
        describe(`Current file: ${url}`, () => {
            it('Contains Header Element', () => {
                cy.get('header')
            })
        
            it('Contains Main Element', () => {
                cy.get('main')      
            })
        })
    })
})

What I want to happen is to gets the first url from env.urls and runs all the tests against it, then gets the second url and runs all the tests against it. Instead it is visiting both urls first (which does makes sense since it is in the before block) and then running the tests afterwards. What is the correct way to structure this?

Incidentally, originally I tried to put the env.urls array into a .json file and retrieve it using cy.readFile() and then loop over the contents, but I couldn't figure out how to make that work at all since it wanted the cy.readFile() to be inside of a test.

2 Answers

To read URLs or any data outside a test, use require().

To explain the problem, Cypress merges consecutive before() hooks in the same block, but introducing a context block between them prevents it.

const urls = require('../fixtures/urls.json')  // alternative to cy.readFile()
                                               // data is read at test loading time
                                               // instead of during the test

describe('Test', () => { 
  
  urls.forEach(url => {

    describe(`Current file: ${url}`, () => {   // multiple blocks define here
                                               // one for each url
      before(() => {
        cy.visit(url) 
      })

      it('Contains Header Element', () => {
        ...
      })
      
      it('Contains Main Element', () => {
        ...
      })
    })
  })
})

The before block needs to be inside the describe block. Rest everything looks good.

Cypress.env('urls').forEach((url) => {
  describe(`Test for ${url}`, () => {
    before(() => {
      cy.visit(url)
    })

    it('Contains Header Element', () => {
      cy.get('header')
    })

    it('Contains Main Element', () => {
      cy.get('main')
    })
  })
})
Related