How to Share Variables Between Tests in Cypress

Learn how to share variables between tests in Cypress with this detailed guide.

Get Started free
How to share variables between tests in Cypress
Home Guide How to Share Variables Between Tests in Cypress

How to Share Variables Between Tests in Cypress

In Cypress, sharing data between tests is essential for maintaining consistency and ensuring efficient test automation. However, Cypress tests are designed to run independently, meaning variables cannot be easily passed between tests by default.

Overview

Managing Variables Across Multiple Cypress Tests

  1. Using Hooks: Set up and manage variables before tests.
  2. Using Aliases and Hooks: Store and access data with .as() in Cypress.
  3. Using cy.task(): Persist data across tests using Node.js tasks.
  4. Using Cypress – Fixtures: Use external files to manage test data.
  5. Using Global Variables in Cypress: Share data globally across tests with simple variable management.

This article explains the various approaches to sharing variables in Cypress, helping ensure smoother test workflows and enhanced test stability.

Sharing Variables in Cypress

In Cypress, sharing data between tests is crucial for maintaining consistency and efficient automation. However, Cypress tests are independent by default, making it difficult to pass variables directly between tests. This creates challenges in scenarios that require shared data, such as:

  • User authentication
  • Session management
  • Data-driven testing

Fortunately, Cypress provides several methods to address these challenges and share data efficiently:

  • Cypress Hooks: Use hooks to set up variables before tests run.
  • Aliases: Store and access data using .as() to share variables between commands.
  • Environment Variables: Store values globally and access them across tests.
  • Fixtures: Use external data files to import and share variables across tests.

These methods ensure seamless test execution, improve reliability, and reduce redundancy, ultimately giving developers better control over test data.

Managing Variables Across Multiple Tests

Dividing logic into separate tests and using the it() function to assign variables before each block can help share data across tests.

However, Cypress executes it() blocks sequentially, which can lead to challenges:

  • Test Fragmentation: Each variable update requires a separate block, leading to fragmented test logic.
  • Increased Complexity: Multiple blocks may complicate variable sharing.
  • Test Dependencies: Failures in one test can cascade and affect others, creating a domino effect.

To avoid these limitations, consider using Cypress hooks, aliases, or environment variables for more efficient variable management.

1. Using Hooks

Using before() or beforeEach() hooks is a marginally better method of dividing a test. You are more logically dividing your test this way. You have two phases: the preparation process, which is separate from the test, and the execution phase, which is the test itself.

This method also has the benefit of giving you explicit information in the error log when a hook fails.

2. Using aliases and hooks

Aliases are actually a part of the Cypress-bundled Mocha framework, which is used to run tests. Anytime you use the.as() command, an alias will be created in the Mocha context and may be accessed by using this keyword, as demonstrated in the example.

It will be a shared variable, allowing you to share variables between tests in the specification. This keyword, however, must be used with the traditional function expression, function(){}, and cannot be used in functions using the arrow expression () =>{}. Take a look at this example.

beforeEach( function() {
cy.request('/api/boards')
.as('boardData')
})

// using it('utilize variable', () => { ... would not work

it('utilize variable', function() {
cy.visit('/board/' + this.boardData.body[0].id) 
})

3. Using cy.task()

A Node.js server process is active in the background behind Cypress. Node can be used, and temporary data can be kept there. If you want, you can even seed a test database! Values from the last run are still present here as long as you don’t close the Cypress console.

Why do you do this? You can give a value to Node.js by using the command cy.task(). A “get” and “set” command must be written. This will be a piece of cake if you are comfortable with getters and setters like you are in Java.

assignUserId: (value) => 
{ 
return (userIdentifier = value); 
}

retrieveUserId: () => { return userIdentifier; }

cy.get('User').then(($userIdentifier) => {
cy.task('assignUserId', $userIdentifier);
});

cy.task('retrieveUserId').then((userIdentifier) => {
cy.get('User').type(userIdentifier);
});

4. Using Cypress – Fixtures

Cypress fixtures allow for easy management of test data by storing it in external files, such as .json files, within the fixtures folder.

This makes it easier to reuse and import data into tests, ensuring consistency and reducing redundancy.

Example:

describe('Testing on Browserstack', function () {

  // Part of before hook

  before(function() {

    // Retrieve fixture data

    cy.fixture('sample').then(function(userData) {

      this.userData = userData;

    });

  });



  // Test case

  it('Test Scenario 1', function () {

    // Navigate to URL

    cy.visit("https://signup.example.com/register/register.php");
    

    // Use data from fixture

    cy.get(':nth-child(3) > [width="185"] > input').type(this.userData.userName);

    cy.get('#mobno').type(this.userData.phoneNumber);

  });

});

By using fixtures, Cypress enables code reuse, allowing the same test script to run with different sets of data, improving maintainability and flexibility.

Talk to an Expert

5. Using Global Variables in Cypress

Global variables in Cypress allow data to be shared across multiple tests, improving efficiency and consistency. These variables are accessible throughout the test suite and can be set using Cypress hooks like before() or beforeEach().

Example:

let globalBoardId;  // Declare global variable



describe('Cypress Global Variables Example', function() {



  before(function() {

    cy.request('/api/boards')

      .then(response => {

        globalBoardId = response.body[0].id; // Store value in global variable

      });

  });



  it('Test 1 - Uses Global Variable', function() {

    cy.visit('/board/' + globalBoardId)

      .should('be.visible');

  });



  it('Test 2 - Reuses Global Variable', function() {

    cy.get('#board-title').should('contain', 'Board ID: ' + globalBoardId);

  });



});

In this example, the global variable globalBoardId is set once in the before() hook and used across multiple tests. This avoids redundant API calls and ensures data consistency.

Global variables improve efficiency by avoiding repetitive data fetching, ensure consistency across tests, and provide simplicity for easy data sharing, while requiring proper management to prevent conflicts.

Best practices for sharing variables in Cypress tests

Cypress executes commands in a chain, ensuring each command waits for the previous one to complete, preventing race conditions. For example:

cy.get('li')

  .should('have.length', 5)  // ensure previous command retrieves elements

  .eq(4)                     // ensure previous assertion is successful

  .click()                    // ensure previous command is complete

No command runs until the previous one finishes. The test fails (typically within 4 seconds) if any command fails to complete in time.

1. Handling Variables in the Command Chain

Consider this scenario:

it('assigns value to variable', () => {

  console.log('>>> log one');

  let boardId;



  cy.request('/api/boards')

    .then(response => {

      console.log('>>> log two');

      boardId = response.body[0].id;

    });



  console.log('>>> log three');

  cy.visit('/board/' + boardId);

});

Here, boardId is set asynchronously, outside the Cypress command chain. The .visit() command executes before boardId is assigned, leading to an issue.

2. Inside Chain vs. Outside Chain Concept: In Cypress, variables passed outside the chain (e.g., boardId) are not immediately available. Here’s a corrected example:

it('captures value in variable', () => {

  let identifier;



  cy.request('/api/boards')

    .then(response => {

      identifier = response.body[0].id;

    });



  cy.visit('/board/' + identifier);

});

In this case, the variable is declared and used in the correct sequence, but Cypress still waits for the asynchronous call to complete before executing the .visit().

3. Keep Variables Inside the Command Chain: The best practice is to use variables inside the Cypress command chain to avoid issues:

it('holds value in variable', () => {

  let boardId;  // initialize variable



  cy.request('/api/boards')

    .then(response => {

      boardId = response.body[0].id;  // set value

      cy.visit('/board/' + boardId);   // use the newly set value

    });

});

By keeping variables inside the command chain, Cypress ensures that data is properly passed between commands.

Sharing variables between Test Files using Environment Variables

We can create environment variables that the test automation framework can use globally and that all test cases can access. In our project’s cypress.json file, we can store this kind of customized environment variable.

We must specify the key as “env” in the cypress.json file and then set the value because a customized variable is not exposed by default Cypress configurations.

In the real test, we must also use Cypress.env and pass the value declared in the json file in order to access this variable.

describe('ExampleSite Test', function () {
// test case
it('Scenario A', function (){
// navigate to application using environment variable
cy.visit(Cypress.env('siteUrl'))
cy.getCookies()
cy.setCookie('cookieName', 'cookieValue')
});
});

We now know that Cypress is a test automation framework, and much like other test automation frameworks, it must run the same set of tests in a variety of test environments, including DEV, QA, UAT, and others. However, some values or variables, such as the application URL or credentials, could have different values in various test environments. Cypress offers methods for test scripts to access environment variables in order to deal with such circumstances. Environment variables are what Cypress considers to be all the variables within the “env” tag in the config.json file. Below is an example of its syntax:

{
"env": {
"api_key": "api_value"
}
}

// Retrieve all the environment variables
Cypress.env()

// Retrieve a specific environment variable using its key
Cypress.env('api_key')

Next, let’s consider a different instance.

{
"env": {
"Param1": "Data1",
"Param2": "Data2"
}
}

Cypress.env(); // {Param1: "Data1", Param2: "Data2"}

Cypress.env("Param1"); // It will return "Data1"

Run Cypress Tests on Real Devices

The “Cypress.env()” method in Cypress can be used to obtain environment variables.

For your Cypress tests, learn how to specify environment variables on BrowserStack.

Cypress Wrap

When utilizing cypress commands like should, type, or click on an object or jquery element, you may first want to wrap it in order to yield the objects that were placed in it and yield its resolved value.

cy.wrap(entity)
cy.wrap(entity, configurations)

cy.wrap({Character: 'John'})

const Champion = () => {
return 'John'
}

cy.wrap({ name: Champion }).invoke('name').should('eq', 'John')
  • Hero is a javascript object, and Cypress cannot be used to interact with it.
  • We use the key name passed with the object Hero in the wrap to assert that it should be equal to Naruto, and it returns true. We then utilize the wrap to convert the object Hero into cypress.
describe('Utilizing Wrap Command', () => {

it("Wrapping Various Data Types", () => {
// Variable
let colorStatement = 'Red Or Blue'
cy.wrap(colorStatement).should('eq', 'Red Or Blue')

// Object
let Character = {name: 'Itachi'}
cy.wrap(Character).should('have.property', 'name', 'Itachi')

// Array
let Characters = ['Itachi', 'Sasuke', 'Naruto', 'Sakura']
cy.wrap(Characters).should('include', 'Sakura')
}) 
})

BrowserStack Automate Banner

Run Cypress Tests on Real Device Cloud

Cypress is a powerful tool for testing web applications, but to get the most accurate results, it’s recommended that tests be run on real devices and browsers.

BrowserStack Automate allows you to run Cypress tests on 3,500+ real devices and browsers, providing a comprehensive testing environment.

Benefits of Using BrowserStack with Cypress:

  • Real Device Testing: Test on a real device cloud to simulate real user conditions for accurate results.
  • Cross-Browser Compatibility: Run tests across a wide range of browsers to ensure app performance and consistency.
  • Powerful Debugging Tools: Access Appium Logs, Network Logs, Screenshots, and Video Recordings to effectively resolve issues.
  • Seamless Integrations: Integrate with tools like JIRA, Trello, GitHub, and Slack for efficient workflow management and defect tracking.

Conclusion

Sharing variables between tests in Cypress is essential for maintaining consistency and efficiency in test automation. Developers can effectively manage data across multiple tests by using methods like global variables, fixtures, environment variables, and Cypress hooks.

For the most accurate results, testing on real devices and browsers with tools like BrowserStack ensures that tests are executed under real user conditions. Following these practices helps improve test reliability and streamline the testing process.

Useful Resources for Cypress

Understanding Cypress

Use Cases

Tool Comparisons

Tags
Automation Testing Cypress

Get answers on our Discord Community

Join our Discord community to connect with others! Get your questions answered and stay informed.

Join Discord Community
Discord