5

Running Cypress 3.1.1 with cypress-cucumber-preprocessor 1.5.1. I need to pass some static data from one step to another (in the same scenario/test). I can do this using an alias, like this: cy.wrap(someString).as('myString'), but then I have to access it asynchronously:

cy.get('@myString').then(myString => ...)

This is rather cumbersome, particularly when I have to pass multiple values, requiring multiple wrapped closures, for no apparent benefit. (Currently I'm working around this by aliasing an object, but I shouldn't need to do this.)

How can I pass primitive values from one step to another synchronously?

I thought I might be able to simply set this.myString='' to set the value on the Mocha shared context object, but in that case, the property exists but is set to undefined when accessed in later steps.

Even creating my own context variable with let outside of the step definition does not work. Is this simply a limitation of Cypress and/or the cypress-cucumber-preprocessor?

hackel
  • 1,181
  • 1
  • 14
  • 21
  • I am unsure if this should be a comment or not, but I feel like you have to use .its and .invoke to do this with any measure of control. https://docs.cypress.io/api/commands/invoke.html#Examples https://docs.cypress.io/api/commands/its.html#Requests – Phillipe Bojorquez Nov 28 '18 at 02:22

3 Answers3

5

I managed to get it working the following way:

  1. Add 2 tasks to the /plugins/index.js
const testStore = {}
    module.exports = (on, config) => {
      on('task', {
        pushValue({ name, value }) {
          console.log(name, value)
          testStore[name] = value
          console.log(testStore)
          return true
        },
      })
      on('task', {
        getValue(name) {
          return testStore[name]
        },
      })
  1. Then you can add a variable in any test and reach it in any other place:
it('test', ()=>{
   cy.task('pushValue', { name: 'orderNumber', value: orderNumber })
})
it('test 2', ()=>{
    cy.task('getValue', 'orderNumber').then((order) => {
      cy.visit(`/bookings/${order}`)
    })   
})
Caconde
  • 4,177
  • 7
  • 35
  • 32
0

Here is a slightly more complicated (and not fully tested) method. A custom command can be added to save values to a global object.

In the Cypress test runner, all the tests seem to run sequentially, but you may have to be careful if using CI and parallel execution.

In /support/commands.js

export const testStore = {}

Cypress.Commands.add('saveAs', { prevSubject: true }, (value, propName) => {
  console.log('saveAs', value, propName)
  testStore[propName] = value;
  return value; 
})

In myTest.spec.js

import { testStore } from '../support/commands.js'
...

it('should have a title', () => {
  cy.title()
    .saveAs('title')             // save for next test
    .should('contain', 'myTitle) // this test's expectation
});

it('should test something else', () => {
  cy.get('.myElement').contains(testStore.title);
});
  • Almost worked :) There's a weird race condition: when you cy.log(testStore) you can see that there's {title: 'some titile}. But when you cy.log(testStore.title) it's empty :( – Murat Jumashev Apr 27 '21 at 08:38
0

Try this! Although this is in Java, you can modify it to run in JS/TS with minor modifications to the model.

The idea is to use a test context and a scenario context to store your information and use it across your test steps.

import { ScenarioContext } from "./ScenarioContext";

export class TestContext {

    private static sc : ScenarioContext;

    static startScenario() {
        TestContext.sc = new ScenarioContext();
    }

    static getScenarioContext() {
        return TestContext.sc;
    }

}
gagarwa
  • 1,426
  • 1
  • 15
  • 28