Cypress writeFile into a new Fixture or a Folder

51 views Asked by At

How do you store an array or a collection strings into a variable. Then take that information and save it into a new fixture. The intention is to then re-use that fixture in a different scenario or test.

Example: I have a dropdown where if you click on it, it displays the following options; Apple, Banana, Pear.

I want to save all three fruits into a list somewhere outside of my test.

2

There are 2 answers

0
agoff On

cy.writeFile can be used to write data to a file. You can then use cy.readFile or cy.fixture to read that data from the file.

// Getting the strings 
let texts = []
cy.get('dropdown') // this probably will need to be changed to fit your scenario
  .find('option')
  .each(($option) => {
    texts.push($option.text());
  });
cy.writeFile('path/to/new/file.json', texts);

// Later...
cy.readFile('path/to/new/file.json').then((data) => { ... });
// or
cy.fixture('file.json').then((data) => { ... }); // if file is stored in the fixtures directory

Alternatively, if you are running all of the tests in the same spec file, you could use a Cypress environment variable.

describe('test', () => {
  before(() => {
    cy.visit('/foo'); // visit page
    cy.get('dropdown')
      .find('option')
      .each(($option) => {
        Cypress.env('dropdownOptions', (Cypress.env('dropdownOptions') ?? []).push($option.text());
      });
  });

  it('tests something', () => {
    cy.wrap(Cypress.env('dropdownOptions')).should('have.length, 3);
  });
});

A few things to note: the getter/setter paradigm of Cypress.env can get a little clunky. There are probably cleaner ways to iterate through the options and store the data, but this was just an example. Also, Cypress.env is synchronous, so if you want to use it in a Cypress command chain, you'll need to either use cy.wrap to work around that, or another strategy.

1
Radclyffe On

I use a custom command to do the same thing, for example

cypress/support/commands.js

Cypress.Commands.add('saveAsFixture', (selector, fixtureName) => {
  cy.get(selector)
    .then($els => $els.get().map((e) => e.innerText))
    .then(values => cy.writeFile(`cypress/fixtures/${fixtureName}.json`, values))
})

In the test

cy.visit(...)
cy.saveAsFixture('option', 'fruits')

// in a later spec 
cy.fixture('fruits').then((fruits) => {
   // ["Apple", "Banana", "Pear"]

})

The problem is coordinating the specs to process is the right order.

To make it less flaky I use an "index" test. This forces the tests to run in a specific order.

import './get-fruits.cy.js'
import './use-fruits-fixture.cy.js'
...

Lately I substituted this plugin cypress-data-session to get more functionality.

An example:

cy.dataSession({
  name: 'created user',
  setup() {
    // create a user
  },
  shareAcrossSpecs: true,
})

...

cy.dataSession({
  name: 'logged in user',
  dependsOn: 'created user',
  setup() {
    // take the user object from
    // the data session "created user"
    // and log in
  },
})