Automatically save Cypress fixture from API response

Viewed 242

I have a very large API where every path returns a unique resource value, and each time I get the resource value for a particular path it's always the same. Saving each response into a fixture file would take days and days.

I would like to use my application code to retrieve the API data, and I want Cypress to save the API responses to the fixture folder.

I then want to use the fixtures to intercept calls to the API during application runs where I'm testing and want the app code to run faster. Fixtures will be returned instead of waiting for the API to speed up the tests.

    describe('fixture creation', () => {
      it('should save fixtures of every endpoint that matches a url', () => {
        // @ts-ignore
        cy.login()
        cy.intercept('https://covfefe/redfish/v1/Chassis/Asrock/PCIeDevices/**', saveResponse)
        cy.visit('/ubmc/system/pci-topology')
      })
    })

How do I write saveResponses to store the json responses from the endpoints that match the url pattern above?

    const saveResponse = req => {
      req.continue((res) => {
        console.log('saved a file', `cypress/fixtures/${ req.url.replace('https://covfefe/', '') }.json`)
        cy.writeFile(
         `cypress/fixtures/${ req.url.replace('https://covfefe/', '') }.json`,
          res.body)
      })
    }

I get the "saved a file ..." console logs, but I checked the fixtures directory and it's empty. There are no errors, and placing a debugger statement inside the res handler doesn't tell me anything meaningful.

3 Answers

Write your intercept like this to pass the response to your function.

cy.intercept('https://covfefe/redfish/v1/Chassis/Asrock/PCIeDevices/**')
  .then( (response) => {
    saveResponse(response)
  })

Im not sure what is returned in your response but you should be able to pull out the full path and use that to write your file name.

There's a lot of characters that are illegal in file names, so you would have to transform them into something else.

I'd recommend removing path separators / to avoid the fixture saving in a nested file structure. There can be permission problems when manually clearing them down.

Build a function to transform the URL to an OS-friendly name, which you can use to consistently write and read the file.

const urlToFilename = (url) => {
  const nogoChars = '#%&{}\/<>*?$!:"+|='
  const filename = nogoChars.split('').reduce((fname,char) => {
    return fname.replaceAll(char, '-')
  }, url)
  return filename
}

Problem executing cy.writeFile() in event handler

Try saving after waiting for the intercept.

cy.intercept('https://covfefe/redfish/v1/Chassis/Asrock/PCIeDevices/**')
  .as('saveMyResponse')
cy.visit('/ubmc/system/pci-topology')
cy.wait('@saveMyResponse').then(interception => {
  saveResponse(interception.request.url, interception.response.body)
})

This worked for me, saving the API responses in the fixtures folder. The fixtures are returned in the second spec below using some similar logic.

describe('fixture creation', () => {
  it('should save fixtures of every endpoint that matches a url', () => {
    cy.login()
    cy.visit('/ubmc/system/pci-topology')
    cy.intercept('https://covfefe/redfish/v1/Chassis/Asrock/PCIeDevices/**',
      req => {
        req.continue((res) => {
          cy.now('writeFile',
            `cypress/fixtures/${ req.url.replace('https://covfefe/', '') }.json`,
            res.body)
        })
      })
  })

  it('should produce results from the fixtures directory', () => {
    cy.intercept('**redfish/v1/Chassis/Asrock/PCIeDevices/**', req => {
      req.reply({
        fixture: `${ req.url.replace('https://covfefe/', '') }.json`
      })
    })

    // @ts-ignore
    cy.login()
    cy.visit('/ubmc/system/pci-topology')
  })
})

/*
~$ tree cypress/fixtures
├── redfish
│     └── v1
│         └── Chassis
│             └── Asrock
│                 └── PCIeDevices
│                     ├── 00_00_00.json
│                     ├── ...
*/
Related