Conditional testing in Cypress enables you to create smarter, more flexible test scripts that adapt to dynamic UI elements, varied user flows, or environment-specific conditions.
By using conditional logic, you can handle optional modals, popups, or redirects without breaking your tests, making your automation more robust and reliable.
Overview
Why use Conditional Testing in Cypress
- Prevents test failures on dynamic content
- Improves test resilience and accuracy
- Reduces false positives from non-critical changes
- Enables realistic, adaptable test flows
- Maintains coverage without hardcoding every path
Ways to Use if for Conditional Testing in Cypress:
- Using .then(): Access resolved DOM elements and apply if logic inside the callback.
- Using .should(): Evaluate conditions during assertions and trigger alternate flows.
- Using .invoke(): Extract values (like text or attributes) to conditionally branch logic.
- Checking .length: Use jQuery-style checks ($el.length) to decide if an element exists.
- Custom Commands: Encapsulate if logic in reusable Cypress commands for clarity.
This guide explains conditional testing in Cypress, its significance, best practices and more.
What is Conditional Testing in Software Testing?
Conditional testing refers to the practice of executing specific test steps or assertions only when certain conditions are met.
It introduces logic into test cases,such as if, else, or switch conditions, to handle dynamic application behavior. This approach helps ensure that tests remain valid and effective even when parts of the application are optional, variable, or environment-dependent.
Importance of Conditional Testing in Software Testing
As modern applications grow more dynamic with feature flags, user personalization, and variable UI states, conditional logic becomes essential to maintain test reliability and relevance.
Key reasons to use conditional testing:
- Handles dynamic UI elements like modals, banners, or optional fields
- Reduces false test failures by skipping irrelevant steps
- Improves test stability across different environments (for example, dev, staging, production)
- Supports feature toggles and A/B tests in modern applications
- Enables smarter, context-aware test flows for better coverage
- Increases reusability by avoiding hard-coded assumptions in test scripts
When to use Conditional Testing in Cypress?
Use conditional testing in Cypress when:
This helps keep your tests stable, relevant, and adaptable to real-world user scenarios.
Read More: How to run specific test in Cypress
Setting up Cypress for Conditional Testing
Before implementing conditional logic in your tests, it’s important to properly set up Cypress with the right structure, dependencies, and configurations. Here are the instructions on how to set it up:
Installing Cypress and configuring the environment
Installing all prerequisites first in our project is necessary. Refer to the Cypress test Automation tutorial first.
Create a new project folder and set up a new Cypress project after ensuring all the requirements are met.
- Create the folder anywhere on your computer, then launch Visual Studio Code by choosing File>Open Folder>Choose the file from the system>click Ok.
- The next step is to use the ‘npm init -y’ command in the terminal to generate the ‘package.json’ file in our project. This file initializes the npm project and serves as a dependency management file, allowing us to run npm commands directly on the project.
- The project name, version, description, keywords, author, license, and script section are all included in the package.json file. The script section is used to run the test scripts from the terminal.
- Install Cypress by using the command to install the most recent version of Cypress as given below:
npm install cypress
or use the following command to install the specific version of Cypress that is needed
npm install cypress@version number
For example, use this command after creating the ‘package.json’ file.
npm install cypress@10.10
Run the “npx cypress open” command to launch Cypress.
Once Cypress has been launched, select E2E Testing, click Continue, pick a browser, and then click Start Cypress E2E Testing in that browser.
After selecting “Start E2E Testing,” a Cypress runner appears, allowing us to create spec files with the “.cy.js” extension. A copy of this file will also be created in Visual Studio Code, where we can write your test cases.
Creating a basic Test Suite in Cypress
An array of test cases is known as a test suite, and it is used to run tests and record their outcomes. You can have a test suite for any of a software application’s fundamental features or a specific sort, like smoke, security test suites, etc. The Cypress approach to organizing numerous connected tests is known as ‘describe’. Every describe block is part of a group of tests.
Writing Test Cases with Conditional statements
Assume that when you visit your website, the content will vary depending on the A/B campaign your server chooses to transmit. It could depend on a user’s geolocation, IP address, time of day, location, or other hard-to-control circumstances.
How is it possible to create tests in this way?
Regulate which campaign is sent or offer a trustworthy way to identify it.
// navigating to the site to obtain session cookies cy.visit('https://bstackdemo.com/') // executing a request to fetch // details related to the user's campaign cy.request('https://bstackdemo.com/userDetails') .its('body.userSpecificCampaign') .then((obtainedCampaign) => { // implementing specific cypress test code // dependent on the retrieved campaign type return executeCampaignTests(obtainedCampaign) })
You might now ask your server to inform you the campaign you are currently in if it saves the campaign along with a session.
A session cookie that you can read off from your server may be another way to test this:
// Visiting the specified URL cy.visit('https://bstackdemo.com/') // Retrieving the cookie named 'userCampaignData' cy.getCookie('userCampaignData').then((extractedCampaign) => { // Executing the relevant campaign tests using the extracted data return runCampaignTests(extractedCampaign) })
Another viable tactic would be to embed data into the DOM directly, but to do it in a way that makes the data constantly accessible and searchable.
This would not function unless it were present constantly:
// Navigating to the HTML element cy.get('html') // Ensuring the HTML has an attribute named 'data-userCampaign' .should('have.attr', 'data-userCampaign') // Extracting the campaign data and running the corresponding tests .then((campaignData) => { return executeCampaignTesting(campaignData) })
How to use if Statements with Cypress Commands
Cypress commands are asynchronous and chainable, so traditional JavaScript if statements don’t work directly with them. To apply conditional logic safely, you need to use methods like .then(), .should(), or .invoke() that handle resolved values.
Recommended Patterns:
1. Using .then() for DOM-based conditions
Access elements and apply logic inside the callback:
js
cy.get('body').then(($body) => { if ($body.find('.popup').length) { cy.get('.popup .close').click(); } });
2. Using .should() for assertions with fallback flows
Trigger logic based on an expected condition:
js
cy.get('.status').should(($el) => { if ($el.text().includes('Failed')) { // custom handling } });
3. Using .invoke() to extract values for logic
Extract text or attributes before applying logic:
js
cy.get('.price') .invoke('text') .then((price) => { if (parseFloat(price) > 100) { cy.log('Price is high'); } });
These patterns allow Cypress tests to behave conditionally based on the state of the app, without breaking its command queue and retry mechanism.
Using Conditional Statements in Cypress tests
Common use cases for conditional testing in Cypress
- Users get a “welcome wizard,” but existing users don’t. Can you always close the wizard in case it appears and ignore it when it doesn’t?
- Can you undo unsuccessful Cypress commands, such as when cy.get() fails to find an element?
- Attempting to develop dynamic tests that react differently depending on the text on the page.
- What should you do differently depending on whether an element exists?
- How can you account for the A/B testing that your application conducts?
- You want to locate every <a> element automatically, and depending on which ones you locate, you want to verify that each link operates.
The basic goal of Cypress conditional testing is to conduct tests on an element with multiple potential outcomes, each of which may require you to act on a different outcome.
Best Practices for Conditional Statements in Cypress Tests
The foundation of Cypress framework is writing trustworthy tests. The key to creating effective tests is to give Cypress as much “state” and “facts” as you can while “guarding” it from issuing new commands until your application has achieved the state you want it to be to continue.
Understanding how your application behaves is essential to avoid writing flaky tests. For example,
- You cannot perform conditional testing on the DOM without server-side rendering and no asynchronous JavaScript.
- Another strategy is to use client-side JavaScript that does synchronous rendering alone.
- The fact that the test writers are unsure of the provided state when conducting conditional testing adds a significant challenge.
- Under certain circumstances, embedding a dynamic state reliably and consistently is the only reliable approach to having accurate tests.
Working with Conditional Logic in Cypress
The following examples will help you understand conditional testing and how to use it in your test:
Case Study:
Step 1: Visit https://automationteststore.com/ as the first step.
Step 2: Select the Login button.
Step 3: If the option to “Register Account” is not checked, select it.
/// <reference types="cypress" /> // Describing the test suite describe('Initial Test Suite', function() { // Defining the test case it('User Account Creation Test', () => { // Navigating to the specified website cy.visit('https://bstackdemo.com/') // Clicking on the customer menu at the top of the page cy.get('#user_menu_top').click() // Checking the account registration option cy.get('#accountForm_accountregister').then(($inputElem) => { // Verifying if the account registration option is selected by default if ($inputElem.is(':checked')) { cy.log('Account registration option is selected by default') } else { // Selecting the account registration option if not selected cy.wrap($inputElem).click() } }) }) })
Here is a single test case in the test file mentioned above that will click on the registration option on the web page only if it is not already selected by default; otherwise, it will simply print a statement indicating that the option for account registration is already selected by default without carrying out any click action on the registration option.
To run the test file, you must first open the Cypress test runner using the ‘npx cypress open‘ command and then click the test file on the test runner. This will start the execution, and the test results will be displayed.
Using assertions with the conditional statement
The cypress-if plugin is where the child commands .if() and .else() originate. Any Cypress assertion can be used as the .if(assertion) condition; element existence is used by default. The test follows the “IF” path and bypasses the “ELSE” section of the command chain.
describe('Cypress Conditional Testing Demonstration', () => { // Common setup for each test beforeEach(() => { // Navigate to the designated website cy.visit('https://bstackdemo.com/') }) it('Navigate to ProductPage and Validate, if Present (If Path)', () => { // Assert the title of the page to be 'StackDemo' cy.title().should('eq', 'StackDemo') // Check the body of the page cy.get('body').then((bodyElement) => { // If ProductPage is found on the page, navigate to it if (bodyElement.find('[data-jsl10n="productPage.name"]').length > 0) { cy.get('[data-jsl10n="productPage.name"]').click() } // If ProductPage is not found, navigate to InfoPage else { cy.get('[data-jsl10n="infoPage.name"]').click() } }) // Validate the title of the navigated page cy.title().should('eq', 'ProductPage') }) it('Navigate to InfoPage and Validate, if ProductPage is Absent (Else Path)', () => { // Assert the title of the page to be 'StackDemo' cy.title().should('eq', 'StackDemo') // Check the body of the page cy.get('body').then((bodyElement) => { // If an incorrect locator is found, try to navigate to ProductPage (will not occur due to incorrect locator) if (bodyElement.find('nonExistentLocator').length > 0) { cy.get('[data-jsl10n="productPage.name"]').click() } // If the incorrect locator is not found, navigate to InfoPage else { cy.get('[data-jsl10n="infoPage.name"]').click() } }) // Validate the title of the navigated page cy.title().should('eq', 'InfoPage') }) })
Scenario: Conditional Testing in Cypress for Navigation and Validation
This section walks you through a practical scenario demonstrating how to use Cypress’s conditional logic to navigate pages and validate elements based on their presence or absence.
Test Suite: “Cypress Conditional Testing Demonstration”
Objective: The primary aim of this test suite is to validate the navigation and subsequent page title when interacting with different elements conditionally on the “https://bstackdemo.com/” website.
Test Setup: beforeEach Hook
- Purpose: To ensure that every test starts from the same initial state.
- Action: Navigate to “https://bstackdemo.com/” before executing each test case.
- Expected Outcome: The website should be loaded successfully before each test begins.
Test Case 1: “Navigate to ProductPage and Validate, if Present (If Path)”
Objective: To validate the navigation and page title when the element associated with “ProductPage” is present.
Steps:
- Title Validation: Ensure the initial page title is ‘StackDemo’. Element Check and Interaction:
- Condition Check: Determine if the element with data attribute [data-jsl10n=”productPage.name”] is present.
- Positive Path (If): If present, click on the element.
- Negative Path (Else): If absent, click on an alternative element with data attribute [data-jsl10n=”infoPage.name”].
- Post-Interaction Validation: Assert that the title of the navigated page should be ‘ProductPage’.
Test Case 2: “Navigate to InfoPage and Validate, if ProductPage is Absent (Else Path)”
Objective: To validate the navigation and page title when the element associated with “ProductPage” is absent, simulating a failure or negative path.
Steps:
- Title Validation: Confirm that the initial page title is ‘StackDemo’. Element Check and Interaction:
- Condition Check: Determine if an incorrect/non-existent locator is present to simulate the absence of the desired element.
- Positive Path (If): If the incorrect locator is found (unlikely), attempt to click on the element with [data-jsl10n=”productPage.name”].
- Negative Path (Else): If the incorrect locator is not found (likely), click on the element with [data-jsl10n=”infoPage.name”].
- Post-Interaction Validation: Assert that the title of the navigated page should be ‘InfoPage’.
Summary:
Through this test suite, we ensure that the application can handle dynamic navigation based on the presence or absence of elements, thereby validating the UI’s responsiveness and navigation logic under different scenarios. This is crucial for ensuring that users are directed correctly as per the available UI elements and that the corresponding pages are accurately represented by their titles, enhancing the reliability and user experience of the application.
cy.then
When the input box is not checked, you need a mechanism to click it.
it('Submits the Agreement Form', () => { // Navigating to the specified webpage cy.visit('https://bstackdemo.com/agreement.html') // Checking the agreement checkbox cy.get('#consent').then(($checkbox) => { // If the checkbox is already checked, log a message if ($checkbox.is(':checked')) { cy.log('User has already given consent') } // If not, click to check it else { cy.wrap($checkbox).click() } }) // Clicking the submit button to submit the form cy.get('button#submitForm').click() })
If the code is unclear to you, you must be familiar with the jQuery selectors and commands. You will also need to use the cy.wrap command to put the element back into a Cypress chain before using the .click() command.
Using loops and iterations in conditional testing
it('cy.each Halts Iteration Upon Returning false', () => { const veggies = ['carrots', 'potatoes', 'tomatoes', 'peppers'] cy.wrap(veggies) .each((veggie, index) => { console.log(index, veggie) if (index === 2) { return false // returning false should stop the iteration. // However, ensure to test and verify this behavior in your specific test environment. } cy.log('veggie', veggie) }) // cy.each yields the original subject // even if the iteration is stopped prematurely .should('equal', veggies) })
The snippet above will come to a stop when it determines that k == 2. You can manipulate and adjust the loop’s control per conditional logic.
Grouping test cases with conditional logic
With this.skip(), which can be applied conditionally based on, for example, an environment variable, you can dynamically skip a test through condition logic.
beforeEach(function() { // Retrieving the test filter from environment variables const filterCriteria = Cypress.env('FILTER_CRITERIA'); // If no filter is provided, proceed without filtering if (!filterCriteria) { return; } // Getting the full title of the current test const currentTestName = Cypress.mocha.getRunner().test.fullTitle(); // If the current test name does not include the filter criteria, skip the test if (!currentTestName.includes(filterCriteria)) { this.skip(); } })
Handling Exceptions and Errors in Conditional Testing
You should consider unsuccessful commands in Cypress to be similar to uncaught exceptions in server-side programming. In those circumstances, the system has changed to an unreliable state, making any attempt at recovery impossible. In contrast, you almost always choose to crash and log.
It is what Cypress is doing when it fails the test. Reporting the failure, bypassing any remaining commands in the test, and bailing out. But here, you need to assume for argument that Cypress did include error handling.
Enabling this would result in error recovery for every command, but only after the corresponding command timeout was reached. It would take a very long time to fail because timeouts begin at 4 seconds (and increase from there).
//! Note: Error handling in Cypress commands is not allowed. //! This code is purely for illustrative purposes function proceedWithoutWorries () { cy.get(...).should(...).click() } cy.get('#modal') .contains('Dismiss') .click().catch((error) => { // It's okay, perhaps the modal didn't exist // or something else... no big deal proceedWithoutWorries() }) .then(proceedWithoutWorries)
- In the best case, you had wasted at least 4 seconds waiting for the <#wizard> element to exist before we erred and moved on possibly.
- The <#wizard> was supposed to be rendered, but in the worst-case scenario, it didn’t render within the timeout you were allowed.
- Assume that this resulted from a timer in the queue, a WebSocket message, a waiting network request, or anything else.
- In this case, not only did you wait a long time for the< #wizard> element to appear, but it also probably led to an error farther down the line on other commands.
No matter what programming idioms are available to you, you cannot build 100% deterministic tests if you cannot determine the state of your application reliably.
Debugging and Troubleshooting Cypress Conditional Tests
When working with conditional logic in Cypress, unexpected behavior can arise due to timing issues or incorrect assumptions. Debugging these tests effectively is key to maintaining reliability.
1. Debugging conditional tests with Cypress’ debugger
A key consideration when selecting an automation framework is debugging. Let’s take the scenario when a tester has created ten lines of the test script, and it fails or throws an error. They must investigate the causes of its failure. Now you can easily create your first condition test with Cypress debugging successfully.
2. Using console logs and error messages for troubleshooting
On both the Cypress window console and the browser console, testers can print logs when using Cypress. Even printing the stack trace to the browser console is an option.
In Cypress, console logs can be used in one of two ways:
- cy.log() command
- console.log() by configuring cypress tasks
3. Analyzing test results and fixing failures
Debugging Cypress tests can be done in various ways, each with different levels of complexity. Each technique needs to undergo several testing rounds before testers can select one (or more) that best meets their skill set, available resources, and overall convenience.
By allowing test retries, Cypress Cloud can identify, report, and monitor flaky tests from your recorded Cypress test runs in your CI/CD workflow.
Organizing and methodically monitoring Cypress flaky tests can help you identify them as they happen, estimate their severity, and prioritize their fix.
Conclusion
Applications written in JavaScript today are highly dynamic and mutable. Over time, the state and DOM undergo constant change. Conditional testing has the drawback of only being applicable when the state has stabilized. However, it is frequently impossible to tell when a situation is stable.
A change that occurs every 10 or even 100 milliseconds could escape your notice. However, a computer will have the ability to monitor those changes. Most of the time, you cannot use the state of the DOM to guide your conditional behavior. This results in flaky testing, which Cypress API is built to address at every stage.
While leveraging a real device cloud like BrowserStack, teams may take advantage of various advantages. Without external emulators, they will inevitably achieve the highest test coverage. Additionally, teams save a lot of the time and expense needed to build device labs.
For automated testing in an Agile environment, BrowserStack uses a cloud-based grid comprising more than 3500+ device-browser-OS combinations.