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
- Using Hooks: Set up and manage variables before tests.
- Using Aliases and Hooks: Store and access data with .as() in Cypress.
- Using cy.task(): Persist data across tests using Node.js tasks.
- Using Cypress – Fixtures: Use external files to manage test data.
- 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.
Also Read: What is Test Reliability in Software Testing
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.
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.
Also Read: How to Run Cypress Tests in Parallel
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.
Must Read: How to handle Cypress Asynchronous Behavior?
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') }) })
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
- Cross Browser Testing with Cypress : Tutorial
- Run Cypress tests in parallel without Dashboard: Tutorial
- Handling Test Failures in Cypress A Comprehensive Guide
- Cypress Test Runner: Tutorial
- Handling Touch and Mouse events using Cypress
- Cypress Automation Tutorial
- CSS Selectors in Cypress
- Performance Testing with Cypress: A detailed Guide
- Cypress Best Practices for Test Automation
- Test React Native Apps with Cypress
- Cypress E2E Angular Testing: Advanced Tutorial
- Cypress Locators : How to find HTML elements
- Maximizing Web Security with Cypress: A Step-by-Step Guide
- Conditional Testing in Cypress: Tutorial
- Cypress Web Testing Framework: Getting Started
- Cypress Disable Test: How to use Skip and Only in Cypress
- What’s new in Cypress 10? How it will change your current testing requirements
Use Cases
- How to Record Cypress Tests? (Detailed Guide)
- How to run your first Visual Test with Cypress
- How to Fill and Submit Forms in Cypress
- How to Automate Localization Testing using Cypress
- How to run Cypress Tests in Chrome and Edge
- How to use Cypress App Actions?
- How to Run Cypress Tests for your Create-React-App Application
- How to Run Cypress Tests in Parallel
- How to handle Click Events in Cypress
- How to Test React using Cypress
- How to Perform Visual Testing for Components in Cypress
- How to run UI tests in Cypress
- How to test redirect with Cypress
- How to Perform Screenshot Testing in Cypress
- How to write Test Case in Cypress: (with testing example)
Tool Comparisons