Best Practices for Writing Effective Test Cases

Best Practices for Writing Effective Test Cases

Writing effective test cases is crucial for ensuring software quality and reliability. A well-structured test case not only helps identify defects but also ensures that the software behaves as expected under various conditions. Below are best practices and guidelines for writing clear, concise, reusable, and comprehensive test cases. 

What is a Test Case?

A tester uses a specific set of conditions or variables to determine whether a system, software application, or one of its features works as intended.

Example: You are testing the Login pop-up of the leading E-commerce platforms. You’ll need several test cases to check if all features of this page are working smoothly.  

Writing Test Cases

Steps to ask yourself 3 questions Before You Write Effective Test Case: 

  1. Choose your approach to test case design: your approach influences your test case design. Are you doing black box testing (you don’t have access to the code source) or white box testing (you have access to the source code)? Are you doing manual testing or automation testing?  
  2. Choose your tool/framework for test case authoring: are you using frameworks or tools to test? What level of expertise do these tools/frameworks require?  
  3. Choose your execution environment: this ties up closely with your test strategy. Do you want to execute across browsers/OS/environments? How can you incorporate that into your test script? 

Once all those 3 questions have been answered, you can start the test case design and eventually test authoring. It’s safe to say that 80% of writing a test case belongs to the planning and designing part, and only 20% is actually scripting. Writing effective test case design is key to achieving good test coverage. 

How to Design a Effective Test Case? 

Write effective test cases – when we don’t need to understand the details of how the software works, we focus on checking if it meets user expectations. We explore the system to come up with test ideas. However, this approach can result in limited testing, as we might overlook features with unusual behaviour. 

In that case, here are some techniques for you to design your test cases: 

  • Equivalence Class Testing: In Equivalence Class Testing, you divide input data into groups and treat all values in each group the same way.

Example: For an age input field that accepts ages from 18 to 65, you can choose 3 values for 3 equivalence classes and test with one value from each group. That means you have 3 test cases. You can choose: 

17 (below 18-65 range) 
30 (within 18-65 range) 
70 (above 18-65 range) 

  • Boundary Value Analysis: this is a more granular version of equivalence class testing. Here you test values at the edges of input ranges to find errors at the boundaries. 

Example: For an age input that accepts values from 18 to 65, you choose up to 6 values to test (which means you have 6 test cases):  

17 (just below) 
18 (at the boundary) 
19 (just above) 
64 (just below) 
65 (at the boundary) 
66 (just above) 

  • Decision Table Testing: you use a table to test different combinations of input conditions and their corresponding actions or results.

Example: Here’s a decision table for a simple loan approval system. Specifically, the system approves or denies loans based on two conditions: the applicant’s credit score and the applicant’s income. From this table, you can write 6 test cases.

Rules of Test Cases

How to write effective Test Case 

Standard Test Case Format

We use a test case to check if a feature or function in an app works properly. It has details like conditions, inputs, steps, and expected results. A good test case makes testing easy to understand, repeat, and complete. 

Components of a Standard Effective Test Case 

Test Case ID: Give a unique ID like “TC001” or “LOGIN_001” to every test case. This helps in tracking. 

Test Case Description: Write a short description of what the test case tests. For example, “Test login with correct username and password.” 

Preconditions: Mention any setup needed before starting.  

Test Data: List the inputs for the test. Like, “Username: test_user, Password: Test@123.” 

Test Steps: Write step-by-step actions for the test. Keep it clear and simple. 

Expected Results: Describe what should happen if everything works. For example, “User logs in and sees the dashboard.” 

Actual Results: Note what happened during the test. This is written after running the test. 

Pass/Fail Status: Mark if the test passed or failed by comparing expected and actual results. 

Remarks/Comments: Add any extra info like problems faced, defect IDs, or special notes. 


Example of a Standard Test Case Format 

Test Case Components

How to write effective test cases: A step-by-step guide

If I explain to you in just a two-line summary of how to write an effective manual test case, it would be:

1. Identify the feature or functionality you wish to test.
2. Next, create a list of test cases that define specific actions to validate the functionality. Now, let’s explore the detailed steps for writing test cases. 

Step 1 – Test Case ID: 

Additionally, assign a unique identifier to the test case to help the tester easily recall and identify it in the future.

Example: TC-01: Verify Login Functionality for a User 

Step 2 – Test Case Description:

We will describe the test case, explaining its purpose and expected behaviour. For example: 

Test Case Description: Logging into the application 
Given: A valid username and password 
When: User enters credentials on the login page 
Then: User logs in successfully and is directed to the home page. 

Step 3 – Pre-Conditions: 

We will document any pre-conditions needed for the test, such as specific configuration settings. 

Step 4 – Test Steps: 

We will document the detailed steps necessary to execute the test case. This includes deciding which actions should be taken to perform the test and also possible data inputs. 

Example steps for our login test: 

  1. Launch the login application under test. 
  2. Enter a valid username and password in the appropriate fields. 
  3. Click the ‘Login’ button. 
  4. Verify that the user has been successfully logged in. 
  5. Log out and check if the user is logged out of the system. 

Step 5 – Test Data: 

We will define any necessary test data. For example, if the test case needs to test that login fails for incorrect credentials, then test data would be a set of incorrect usernames/passwords. 

Step 6 – Expected Result: 

Next, we will provide the expected result of the test, which the tester aims to verify. For example, here are ways to define expected results:

  1. A user should be able to enter a valid username and password and click the login button. 
  2. The application should authenticate the user’s credentials and grant access to the application. 
  3. The invalid user should not be able to enter the valid username and password; click the login button. 
  4. The application should reject the user’s credentials and display an appropriate error message. 

Step 7 – Post Condition:

The tester is responsible for any cleanup after the test, including reverting settings and removing files created during the test. For example: 

  1. Successful login with valid credentials. 
  2. Error message for invalid credentials. 
  3. Secure storage of user credentials. 
  4. Correct redirection after login. 
  5. Restricted access to pages without login. 
  6. Protection against unauthorized data access. 

Step 8 – Actual Result: 

We will document the actual result of the test. This is the result the tester observed when running the test. Example: After entering the correct username and password, the user is successfully logged in and is presented with the welcome page. 

Step 9 – Status: 

The tester will report the status of the test. If the expected and actual results match, the test is said to have passed. The tester marks the test as failed if the results do not match.

Manual and automated test cases share some common elements, but when using automation, include these 6 key elements. Those are: preconditions, test steps, sync and wait, comments, debugging statements, and output statements. 

Best Practice for writing effective Test Case 

Follow key best practices to write effective test cases.

First, identify the purpose of the test case and determine exactly what needs to be tested.

Write the test case clearly and concisely, providing step-by-step instructions. Also, it is important to consider all possible scenarios and edge cases to ensure thorough testing. 

It is always to review and refine your test cases occasionally to maintain their quality over time. 

By following these best practices for writing effective test cases, we can increase the chances of spotting defects early in the software development process, ensuring optimal performance for end use. 

Benefits of writing high-quality and effective Test cases 

Indeed, writing effective test cases is important because it ensures high-quality software. Moreover, well-written test cases provide multiple benefits.

Let me narrow down to some essential facts here: 

  1. Accurate Issue Identification: High-quality test cases ensure thorough testing and accurate identification of bugs. 
  2. Better Test Coverage: Test cases evaluate different aspects of the software, identifying bugs before release. 
  3. Improved Software Quality: Identifying issues early reduces repair costs and improves software reliability. 
  4. Better Collaboration: High-quality test cases help stakeholders work together, improving communication and resources. 
  5. Enhanced User Experience: Test cases improve the software’s usability, enhancing the end user’s experience. 

Conclusion

Writing effective test cases is a systematic process that requires attention to detail and clarity. By following these best practices—understanding requirements, structuring test cases properly, covering various scenarios, ensuring reusability, documenting results, and regularly reviewing your work—you will create a robust testing framework that enhances software quality. Implementing these guidelines will not only streamline your testing process but also contribute significantly to delivering high-quality software products that meet user expectations. 

Click here to read more blogs like this.

How Product Quality Builds Brand Loyalty in Marketing

How Product Quality Builds Brand Loyalty in Marketing

Introduction to Marketing and Product Quality

In today’s digital-first world, how a customer experiences your website, app, or product can make or break your brand. People expect smooth, fast, and problem-free interactions. Customers can quickly lose interest if an app crashes or a product doesn’t perform as expected. They might even switch to a competitor. That’s why companies must invest in product quality, not just for technical reasons, but also to improve their marketing outcomes and build brand loyalty.

Ensuring product quality means making sure everything works as it should. From small features to large-scale operations, quality assurance checks that the user’s journey is smooth and reliable. When customers see that a brand delivers consistent and high-quality experiences, they are more likely to stay loyal and recommend it to others. So, let’s understand how product quality and brand loyalty go hand-in-hand.

1. Better Product = Better Customer Experience

Let’s start with a simple question: Would you continue using a product that keeps crashing or fails to perform reliably? Most people won’t. Studies show that poor user experience is one of the top reasons people stop using digital products.

A smooth, bug-free app or website—or a well-functioning physical product—shows customers that a brand is professional, reliable, and cares about their experience. And how do brands ensure that? Through rigorous quality checks and validation.

Quality assurance helps identify issues like:

  • Pages are not loading properly
  • App buttons not working
  • Forms not submitting
  • Payment gateways failing
  • Features behaving differently on different devices

When these issues are resolved before launch, the user has a positive first impression. A good experience often means the user will come back, make a purchase, and even recommend it to others. That’s brand loyalty in action.

2. Quality Products Protect Brand Reputation

marketing and product quality

A brand’s image is more than just a logo or advertisement—it’s also how well the product performs. If users associate a brand with unreliable apps, slow websites, or confusing interfaces, the reputation takes a hit.

Example: Sonos App Redesign Backlash (2024)
In May 2024, Sonos, a premium audio brand, launched a major update to its mobile app, aiming to enhance performance and customization. However, the redesign was met with widespread criticism due to missing features and numerous bugs. Users reported issues like broken local music library management, missing sleep timers, and unresponsive controls. The backlash was significant, leading to a decline in customer trust and a drop in stock prices.
Sonos acknowledged the problems and committed to regular updates to fix the issues.

🔗 Read the full story on The Verge – The Sonos app fiasco: how a great audio brand nearly ruined its reputation | The Verge

This incident underscores the critical importance of thorough product testing and quality assurance before releasing updates. A well-validated product not only ensures a smooth user experience but also protects the brand’s reputation and customer loyalty.

3. Great Marketing Campaigns Need Flawless Quality 

Marketers spend time and money creating exciting campaigns—ads, social media posts, emails, and offers. But what happens when customers click through, and the landing page doesn’t load? Or does the sign-up form crash?

All that effort is wasted.

marketing and product quality

This is where product quality and marketing go hand-in-hand. Before launching any campaign, the end-to-end user experience must be validated:

  • Can the customer access the link?
  • Does the mobile version work correctly?
  • Can they complete a transaction?
  • Does the thank-you message show up?

High product quality ensures the campaign works as planned and gives customers a seamless experience, increasing conversions and trust.

4. Builds Trust Through Consistency

Trust is built when customers consistently receive what they expect. If a brand’s app works great one day and crashes the next, people will feel uncertain about using it again. But if the experience is reliable every time, they’ll feel comfortable sticking around.

marketing and product quality

Ongoing quality assurance efforts make this possible. Even after launch, brands must validate updates, new features, and changes to ensure nothing breaks. This shows users that the brand:

  • Cares about their experience
  • Takes feedback seriously
  • Works to continuously improve

Over time, this consistent performance builds strong customer loyalty.

5. Improves Retention Rates

Acquiring new customers is more expensive than keeping existing ones. One major reason customers leave is a poor user experience. If they struggle to log in, make a purchase, or navigate a product, they’ll quit—and maybe never return.

With high product quality, retention rates improve. Features work as expected. Apps load quickly. Users can complete tasks without stress. Happy users = returning users.

Ensuring product quality also means catching issues early, saving money and effort in fixing problems later, and preventing customer churn.

6. Encourages Word-of-Mouth & Reviews

Loyal customers are often your best marketers. When they have a great experience with your product, they tell others. They leave positive reviews, share on social media, and recommend your brand.

marketing and product quality

On the flip side, one bad product experience can lead to:

  • 1-star reviews on app stores
  • Negative posts on social platforms
  • Bad word-of-mouth, which can hurt new customer growth

High product quality acts as a shield. It reduces the chances of negative feedback and increases the likelihood of glowing reviews, which is gold for marketing teams.

Conclusion

Product quality is more than a technical concern—it’s a powerful asset for marketing. When quality is prioritized, it leads to:

  • Fewer issues
  • Happier users
  • Positive reviews
  • Stronger brand image
  • Higher customer retention
  • Better ROI on marketing campaigns

In a crowded market where customers have endless choices, the brands that stand out are the ones that consistently deliver quality. And that quality comes from testing, validating, and refining your product before customers see it.

Marketers who work closely with product and quality teams can ensure every campaign, product, and user journey is optimized for success. That’s how brands earn trust, create loyalty, and grow over the long term.

Click here to read more blogs.

Visual Testing: How to Verify Toggle Colors on Real Devices with Appium and Python

Visual Testing: How to Verify Toggle Colors on Real Devices with Appium and Python

In this blog, we’ll explore how to verify toggle colors on real Android and iOS devices using Appium and Python—for visual testing, a practical guide for mobile automation testers who want to ensure their apps don’t just work, but look right too.

We’ll dive into:

  • Why is color detection essential in domains like e-commerce, healthcare, gaming, and automotive?
  • Three powerful techniques for verifying toggle states:
    • Accessibility Identifiers
    • Image Comparison
    • Pixel-Level RGB Color Extraction

Step-by-step examples for both Android and iOS devices.

Importance of Color Detection in Visual Testing

Color detection plays a crucial role in image verification across various domains, where visual accuracy directly impacts user experience, brand integrity, and functionality. Below are some key applications:

So, let’s dive into verifying toggle colors on Android and iOS app step by step

Set your system for Appium and Python Visual Testing for real Android and IOS testing

For Android testing configuration, use the blog below for reference
How to configure Windows Desktop for Android App Automation using Appium

For IOS testing configuration, use the blog below for reference
How to configure macOS for iOS Mobile App Automation using Appium

Using the Accessibility Identifiers: Utilizing accessibility identifiers (e.g., accessibility_id, content-desc, checked attribute from XPath) to determine the toggle’s state. These identifiers provide semantic information about the element, which is more reliable than relying solely on visual appearance.

Using Image Comparison: Capture a screenshot of the toggle in its “On” state and another in its “Off” state. Then, compare the screenshot of the actual toggle with the stored “On” and “Off” images.

img1 = imageio.imread(ideal_image_path)
img2 = imageio.imread(actual_image_path_repo_root)
if img1.shape != img2.shape:
  	 print("Both images should have the same dimensions")
  	 raise selenium.common.NoSuchElementException('No such element present')
diff = np.sum(np.abs(img1 - img2))
avg = diff / (img1.shape[0] * img1.shape[1] * img1.shape[2])
percentage = (avg / 255) * 100
	
if percentage == 0:
  	 return True
else:
 	  return False

In the above snippet, using opencv library from Python we are comparing the images first using the size of both the images, then calculating the average difference per Pixel for both the images.

Using Pixel Color Extraction:

The RGB (Red, Green, Blue) color model is one of the most widely used systems in digital image processing and display technologies. It is an additive color model, meaning it combines the intensity of these three primary colors(RGB) to create a broad spectrum of colors. Each color in this model is represented as a combination of Red, Green, and Blue values, ranging from 0 to 255 for 8-bit images.

  • For example:
    • (255, 0, 0) represents pure red.
    • (0, 255, 0) represents pure green.
    • (0, 0, 255) represents pure blue.
    • (255, 255, 255) represents white.
    • (0, 0, 0) represents black.

How RGB Detection Works:

RGB detection involves extracting the Red (R), Green (G), and Blue (B) intensity values of individual pixels from digital media such as images or videos. Each pixel acts as a building block of the media, storing its color as a combination of these three values.

  1. For image comparison in Python install pillow package using – from PIL import Image
  2. Load the image – image = Image.open(‘example.jpg’)
  3. Access the pixel at any location – rgb = image.getpixel((50, 50))

This will return the RGB value for that particular point. Open this website https://www.rapidtables.com/web/color/RGB_Color.html. Here you can find the color type according to RGB values, like if this method is returning the (255,215,0), which means it’s GOLD color.

Visual Testing

By entering these values, you can find the color. Also like by entering 0,0,0 you can find the black color.

Visual Testing

For demo purposes, let’s open the settings of android→connections→wifi toggle and check whether it’s turned ON or OFF.

Appium and Python Visual Testing

Use code below for reference of color detection on a real Android device (Python Visual Testing)

Pre-setup for Android Device

  1. Start Appium server using the below command, or you can use Appium GUI as well
    • appium -a 127.0.0.1 -p 4723
  2. Check connected adb devices using the below command, and you should be able to see a  connected device with the  device UDID
    • adb devices
  3. pip install Pillow
import time
from PIL import Image
import io

def app_init_for_android():
   from appium import webdriver
   from appium.webdriver.common.appiumby import AppiumBy

   desired_caps = {
       "appium:deviceName": "my_samsung",
       "appium:udid": "R9ZRskddjk0CHT",
       "platformName": "Android",
       "appium:platformVersion": "13",
       "appium:appPackage": "com.android.settings",  # Settings app package
       "appium:appActivity": "com.android.settings.Settings",  # Main Settings activity
       "automationName": "UiAutomator2"
   }

   # Initialize the Appium driver for the real iOS device
   driver = webdriver.Remote('http://127.0.0.1:4723', desired_caps)
   time.sleep(5)

   driver.find_element(
       AppiumBy.XPATH,
       "//androidx.recyclerview.widget.RecyclerView[@resource-id='com.android.settings:id/recycler_view']/android.widget.LinearLayout[2]"
   ).click()
   time.sleep(5)

   # To install pillow package use: pip install pillow
   element_1 = driver.find_element(AppiumBy.XPATH, "//android.widget.Switch[@content-desc='Wi-Fi']")
   time.sleep(5)
get_rgb_colors(element_1)
def get_rgb_colors(locator):
   element_location = locator.location
   element_size = locator.size

   screenshot = driver.get_screenshot_as_png()
   screenshot_image = Image.open(io.BytesIO(screenshot))
   width, height = screenshot_image.size
   center_x = width // 2
   center_y = height // 2 
   background_color = screenshot_image.getpixel((center_x , center_y))
   return background_color

Let’s break down the code

  • Install the required packages image, io, and time
  • Initialize the Android driver using the correct capability JASON
  • Inspect the locators to navigate to the wi-fi toggle present page
  • Find the center coordinates of the toggle using the locators method
  • Passing those coordinates to the getpixel method will give us the RGB value of that particular pixel
  • Open the website https://www.rapidtables.com/web/color/RGB_Color.html
  • Here you can find the color type according to RGB values

Use the code below for reference of colour detection on a real iOS device (Appium Visual Testing)

Pre-setup for iOS Device

  1. Start Appium server using the below command, or you can use Appium GUI as well
    • appium -a 127.0.0.1 -p 4723
  2. pip install Pillow

We have to use build command to build our project and start our testing on real iOS. For IOS id→xcode→Window→device and simulators→Identifier
(e.g. –xcodebuild -project (path_for_WebDriverAgent.xcodeproj) -scheme WebDriverAgentRunner -destination ‘platform=iOS,id=(id_of_connected_ios) test)

Appium and Python

Consider the code below for color detection on iOS automation

import time
from PIL import Image
import io

def app_init_for_ios():
   from appium import webdriver
   from appium.webdriver.common.appiumby import AppiumBy

desired_caps =
{
   "platformName": "iOS",
   "platformVersion": "ios_devie_version",
   "deviceName": "ios_device_name",
   "udid": "ios_device_udid",
   "bundleId": "com.apple.Preferences",
   "automationName": "XCUITest",
   "xcodeSigningId": "iPhone Developer",
   "xcodeOrgId": "your_xcode_id",
   "autoAcceptAlerts": true,
   "newCommandTimeout": 10000
}

   # Initialize the Appium driver for the real iOS device
   driver = webdriver.Remote('http://127.0.0.1:4723', desired_caps)
   time.sleep(5)
driver.find_element(
       AppiumBy.XPATH,
       "//XCUIElementTypeStaticText[@name="WIFI"]"
   ).click()
   time.sleep(5)

   # To install pillow package use: pip install pillow
   element_1 = driver.find_element(AppiumBy.XPATH, "//XCUIElementTypeSwitch[@name="Wi‑Fi"]")
   time.sleep(5)
get_rgb_colors(element_1)
def get_rgb_colors(locator):
   element_location = locator.location
   element_size = locator.size

   screenshot = driver.get_screenshot_as_png()
   screenshot_image = Image.open(io.BytesIO(screenshot))
   width, height = screenshot_image.size
   center_x = width // 2
   center_y = height // 2 
   background_color = screenshot_image.getpixel((center_x , center_y))
   return background_color

Let’s break down the code – If you see the code, it’s similar to the Android color verification code The two key differences are like first one is the capabilities are different for iOS, and the locator finding strategy is different.

Conclusion

1. Accessibility Identifiers:

This is the most straightforward and reliable approach. Mobile apps often include labels or attributes (like accessibility_id or content-desc) that indicate the current state of a toggle. This method requires no image processing, as it leverages metadata provided by developers—making it both efficient and robust.

2. Image Comparison:

This technique involves capturing screenshots of the toggle in both “on” and “off” states and comparing them to reference images. Tools like OpenCV or scikit-image help analyze visual similarity, accounting for minor differences due to lighting or device variations. It’s especially useful when you need to validate the UI’s visual accuracy.

3. Pixel Color Extraction:

By extracting specific RGB values from toggle regions using libraries like Pillow, this method offers precision at the pixel level. It’s ideal for verifying exact color codes, and the extracted values can be cross-referenced with tools like RapidTables for further validation.
While Android and iOS may differ slightly in setup and element location, the core strategies remain consistent. Depending on your testing needs, you can use these methods individually or in combination to ensure your app displays the correct colors—ultimately contributing to a seamless and visually consistent user experience.

Click here to read more blogs like this.

A Beginner’s Guide to Fast, Reliable Web Testing with CodeceptJS & Puppeteer 

A Beginner’s Guide to Fast, Reliable Web Testing with CodeceptJS & Puppeteer 

CodeceptJS Puppeteer Guide

Looking to simplify your UI test automation without compromising on speed or reliability? 

Welcome to CodeceptJS + Puppeteer — a powerful combination that makes browser automation intuitive, maintainable, and lightning-fast. Whether you’re just stepping into test automation or shifting from clunky Selenium scripts, this CodeceptJS Puppeteer Guide will walk you through the essentials to get started with modern JavaScript-based web UI testing

Why CodeceptJS + Puppeteer? 

CodeceptJS Puppeteer Guide
  • Beginner-Friendly: Clean, high-level syntax that’s easy to read—even for non-coders. 
  • Super-Fast Execution: Puppeteer runs headless Chrome directly, skipping WebDriver overhead. 
  • Stable Tests: Auto-waiting eliminates the need for flaky manual waits. 
  • Built-in Helpers & Smart Locators: Interact with web elements effortlessly. 
  • CI/CD Friendly: Easily integrates into DevOps pipelines. 
  • Rich Debugging Tools: Screenshots, videos, and console logs at your fingertips. 

In this blog, you’ll learn: 

  • How to install and configure CodeceptJS with Puppeteer 
  • Writing your first test using Page Object Model (POM) and Behavior-Driven Development (BDD) 
  • Generating Allure Reports for beautiful test results 
  • Tips to run, debug, and manage tests like a pro 

Whether you’re testing login pages or building a complete automation framework, this guide has you covered. 

Ready to build your first CodeceptJS-Puppeteer test? Let’s dive in! 

1. Initial Setup 

  • Prerequisites 
    • Node.js installed on your system. (Follow below link to Download and Install Node.) 
      • https://nodejs.org/ 
    • Basic knowledge of JavaScript. 
  • Installing CodeceptJS 
    Run the following command to install CodeceptJS and its configuration tool: 
    npm install codeceptjs @codeceptjs/configure –save-dev 

2. Initialize CodeceptJS 

  • Create a New Project 
    • Initialize a new npm project using following commend: 
    • npm init –y 
  • Install Puppeteer 
    Install Puppeteer as the default helper: 
    npm install codeceptjs puppeteer –save-dev 
  • Setup CodeceptJS
    Run the following command to set up CodeceptJS: 
    npx codeceptjs init 

As shown below, follow the steps as they are; they will help you build the framework. You can choose Puppeteer, Playwright, or WebDriver—whichever you prefer. Here, I have used Puppeteer to create the framework 

codeceptjs puppeteer
codeceptjs puppeteer
codeceptjs puppeteer

This will guide you through the setup process, including selecting a test directory and a helper (e.g., Puppeteer). 

3. Writing Your First Test  

Example Test Case 

The following example demonstrates a simple test to search “codeceptjs” on Google: 

Dependencies 

Ensure the following dependencies are included in your package.json: 

"devDependencies": { 
    "codeceptjs": "^3.6.10", 
    "puppeteer": "^24.1.0" 
} 

Configuration File 

Update your codecept.conf.js file to specify the base URL and browser settings: 

helpers: { 
    Puppeteer: { 
        url: 'https://www.google.com', 
        show: true, 
        windowSize: '1200x900' 
    } 
} 

A simple test case to perform a Google search is shown below: 

Feature('google_search'); 

Scenario('TC-1 Google Search', ({ I }) => { 
    I.amOnPage('/'); 
    I.seeElement("//textarea[@name='q']"); 
    I.fillField("//textarea[@name='q']", "codeceptjs"); 
    I.click("btnK"); 
    I.wait(5); 
}); 

4. As we have seen how to create a simple test, we will now explore how to create a test in BDD using the POM approach. 

Using Page Object Model (POM) and BDD 

CodeceptJS supports BDD through Gherkin syntax and POM for test modularity. If you want to create a feature file configuration, use this command.  
npx codeceptjs gherkin:init” 

The setup will be created; however, some configurations still need to be modified, as explained below. You can refer to the details provided. 

After this, the following changes will be displayed in the CodeceptJS configuration file. Ensure that these changes are also reflected in your configuration file. 

gherkin: { 
    features: './features/*.feature', 
    steps: ['./step_definitions/steps.js'] 
  }, 

Creating a Feature File 

A Feature file in BDD is a plain-text file written in Gherkin syntax that describes application behavior through scenarios using Given-When-Then steps. 
Example: Orange HRM Login Test 
Feature: Orange HRM 

Scenario: Verify user is able to login with valid credentials 
Given User is on login page 
When User enters username “Admin” and password “admin123” 
When User clicks on login button 
Then User verifies “Dashboard” is displayed on page
 

Step Definitions 

A Step Definitions file in BDD maps Gherkin step definitions to executable code, linking test scenarios to automation logic. 
Define test steps in step_definitions/steps.js: 

Page Object Model 

A Page File represents a web page or UI component, encapsulating locators and actions to support maintainable test automation. 
Create a LoginPage class to encapsulate page interactions: 

5. Adding Reports with Allure 

Install Allure Plugin

Install the Allure plugin for CodeceptJS:
npm install @codeceptjs/allure-legacy –save-dev

Update Configuration 

Enable the Allure plugin in codecept.conf.js: 

Generate Reports 

Run tests and generate reports: 
npx codeceptjs run 
npx allure generate –clean 
npx allure open 

6. Running Tests 

To execute tests, use the following command: 
npx codeceptjs run 

To log the steps of a feature file on the console, use the command below: 

npx codeceptjs run –steps 

The — verbose flag provides comprehensive information about the test execution process, including step-by-step execution logs, detailed error information, configuration details, debugging assistance, and more. 

npx codeceptjs run –verbose 

To target specific tests: 

npx codeceptjs run <test_file> 

npx codeceptjs run –grep @yourTag 

Conclusion: From Clicks to Confidence with CodeceptJS & Puppeteer 

In this guide, we walked through the essentials of setting up and using CodeceptJS with Puppeteer—from writing simple tests to building a modular framework using Page Object Model (POM) and Behavior-Driven Development (BDD). We also explored how to integrate Allure Reports for insightful test reporting and saw how to run and debug tests effectively. 

By leveraging CodeceptJS’s high-level syntax and Puppeteer’s powerful headless automation capabilities, you can build faster, more reliable, and easier-to-maintain test suites that scale well in modern development workflows. 

Whether you’re just starting your test automation journey or refining an existing framework, this stack is a fantastic choice for UI automation in JavaScript—especially when aiming for stability, readability, and speed. 

💡 Want to dig deeper or fork the full framework? 
🔗 Explore the complete CodeceptJS + Puppeteer BDD framework on GitHub 

Happy testing!


Click here to read more blogs like this.

Cypress and TypeScript: A Dynamic Duo for Web Application & API Automation

Cypress and TypeScript: A Dynamic Duo for Web Application & API Automation

Introduction to Cypress and TypeScript Automation:

Nowadays, the TypeScript programming language is becoming popular in the field of testing and test automation. Testers should know how to automate web applications using this new, trending programming language. Cypress and TypeScript automation can be integrated with Playwright and Cypress to enhance testing efficiency. In this blog, we are going to see how we can play with TypeScript and Cypress along with Cucumber for a BDD approach.

TypeScript’s strong typing and enhanced code quality address the issues of brittle tests and improve overall code maintainability. Cypress, with its real-time feedback, developer-friendly API, and robust testing capabilities, helps in creating reliable and efficient test suites for web applications.

Additionally, adopting a BDD approach with tools like Cucumber enhances collaboration between development, testing, and business teams by providing a common language for writing tests in a natural language format, making test scenarios more accessible and understandable by non-technical stakeholders.

In this blog, we will build a test automation framework from scratch, so even if you have never used Cypress, Typescript, or Cucumber, there are no issues. Together, we will learn from scratch, and in the end, I am sure you will be able to build your test automation framework. 

Before we start building the framework and start with our discussion on the technology stack we are going to use, let’s first complete the environment setup we need for this project. Follow the steps below sequentially and let me know in the comments if you face any issues. Additionally, I am sharing the official website links just in case you want to take a look at the information on the tools we are using. Check here,

Setting up the environment:

The first thing we need to make this framework work is Node.js, so ensure you have a node installed on the system. The very next thing to do is to have all the packages mentioned above installed on the system. How can you install them? Don’t worry; use the below commands.

  • Ts-Node: npm i typescript
  • Cypress: npm install cypress –save-dev
  • Cucumber: npm i @cucumber/cucumber -D
  • Allure Command Line: npm i allure-commandline
  • Cucumber per-processor: npm install –save-dev cypress-cucumber-preprocessor
  • Tsify: npm install tsify
  • Allure Combine: npm i allure-combined

So far, we have covered and installed all we need to make this automation work for us. Now, let’s move to the next step and understand the framework structure.

Framework Structure:

Let’s now understand some of the main players of this framework. As we are using the BDD approach assisted by the cucumber tool, the two most important players are the feature file and the step definition file. To make this more robust, flexible and reliable, we will include the page object model (POM). Let’s look at each file and its importance in the framework.

Feature File: 

Feature files are an essential part of Behavior-Driven Development (BDD) frameworks like Cucumber. They describe the application’s expected behavior using a simple, human-readable format. These files serve as a bridge between business requirements and automation scripts, ensuring clear communication among developers, testers, and stakeholders.

Key Components of Feature Files

  1. Feature Description:
    • A high-level summary of the functionality being tested.
    • Helps in understanding the purpose of the test.
  2. Scenarios:
    • Each scenario represents a specific test case.
    • Follows a structured Given-When-Then format for clarity.
  3. Scenario Outlines (Parameterized Tests):
    • Used when multiple test cases follow the same pattern but with different inputs.
    • Allows for better test coverage with minimal duplication.
  4. Tags for Organization:
    • Tags like @smoke, @regression, or @critical help in organizing and running selective tests.
    • Makes it easier to filter and execute relevant scenarios.

Web App Automation Feature File: 

Feature: Perform basic calculator operations

    Background:
        Given I visit calculator web page

    @smoke
    Scenario Outline: Verify the calculator operations for scientific calculator
        When I click on number "<num1>"
        And I click on operator "<Op>"
        And I click on number "<num2>"
        Then I see the result as "<res>"
        Examples:
            | num1 | Op | num2 | res |
            | 6    | /  | 2    | 3   |
            | 3    | *  | 2    | 6   |

    @smoke1
    Scenario: Verify the basic calculator operations with parameter
        When I click on number "7"
        And I click on operator "+"
        And I click on number "5"
        Then I see the result as "12"

API Automation Feature File:

Feature: API Feature

    @api
    Scenario: Verify the GET call for dummy website
        When I send a 'GET' request to 'api/users?page=2' endpoint
        Then I Verify that a 'GET' request to 'api/users?page=2' endpoint returns status

    @api
    Scenario: Verify the DELETE call for dummy website
        When I send 'POST' request to endpoint 'api/users/2'
            | name     | job    |
            | morpheus | leader |
        Then I verify the POST call
            | req  | endpoint  | name     | job           | status |
            | POST | api/users | morpheus | zion resident | 200    |

    @api
    Scenario: I send POST Request call and Verify the POST call Using Step Reusablity
         When I send 'POST' request to endpoint 'api/users/2'
            | req  | endpoint  | name     | job           |
            | POST | api/users | morpheus | zion resident |
        Then I verify the POST call
            | req  | endpoint  | name     | job           | status |
            | POST | api/users | morpheus | zion resident | 200    |

Step Definition File: 

Step definition files act as the implementation layer for feature files. They contain the actual automation logic that executes each step in a scenario. These files ensure that feature files remain human-readable while the automation logic is managed separately.

Key Components of Step Definition Files

  1. Mapping Steps to Code:
    • Each Given, When, and Then step in a feature file is linked to a function in the step definition file.
    • Ensures test steps execute the corresponding automation actions.
  2. Reusability and Modularity:
    • Common steps can be reused across multiple scenarios.
    • Avoid duplication and improve maintainability.
  3. Data Handling:
    • Step definitions can take parameters from feature files to execute dynamic tests.
    • Enhances flexibility and test coverage.
  4. Error Handling & Assertions:
    • Verifies expected outcomes and reports failures accurately.
    • Helps in debugging test failures efficiently.

Web App Step Definition File:

import { When, Then, Given } from '@badeball/cypress-cucumber-preprocessor'
import { CalPage } from '../../../page-objects/CalPage'
const calPage = new CalPage()

Given('I visit calculator web page', () => {
  calPage.visitCalPage()
  cy.wait(6000)
})

Then('I see the result as {string}', (result) => {
  calPage.getCalculationResult(result)
  calPage.scrollToHeader()
})

When('I click on number {string}', (num1) => {
  calPage.clickOnNumber(num1)
  calPage.scrollToHeader()
})

When('I click on operator {string}', (Op) => {
  calPage.clickOnOperator(Op)
  calPage.scrollToHeader()
})

API Step Definition File:

import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
import { APIUtility } from '../../../../Utility/APIUtility'

const apiPage = new APIUtility()

When('I send a {string} request to {string} endpoint', (req, endpoint) => {
  apiPage.getQuery(req, endpoint)
})

Then(
  'I Verify that a {string} request to {string} endpoint returns status',
  (req, endpoint) => {
    apiPage.iVerifyGETRequest(req, endpoint)
  },
)

Then('I verify that {string} request to {string} endpoint', (datatable) => 
  apiPage.postQueryCreate(datatable)
})

Then('I verify the POST call', (datatable) => {
  apiPage.postQueryCreate(datatable)
})

When('I send {string} request to endpoint {string}', (req, endpoint) => {
  apiPage.delQueryReq(req, endpoint)
})

Then(
  'I verify {string} request to endpoint {string} returns status',
  (req, endpoint) => {
    apiPage.delQueryReq(req, endpoint)
  },
)

Page File:

Page files in test automation frameworks serve as a structured way to interact with web pages while keeping test scripts clean and maintainable. These files typically encapsulate locators and actions related to a specific page or component within the application under test.

Key Components of Page Files in Test Automation Frameworks

  1. Navigation Methods:
    • Functions to visit the required page using a URL or base configuration.
    • Ensures tests always start from the correct application state.
  2. Element Interaction Methods:
    • Functions to interact with buttons, input fields, dropdowns, and other UI elements.
    • Encapsulates actions like clicking, typing, or selecting options to maintain reusability.
  3. Assertions and Validations:
    • Methods to verify expected outcomes, such as checking if an element is visible or a value is displayed correctly.
    • Helps in ensuring the application behaves as expected.
  4. Reusability and Modularity:
    • Each function is designed to be reusable across multiple test cases.
    • Keeps automation scripts clean by avoiding redundant code.
  5. Handling Dynamic Elements:
    • Includes waits, scrolling, or retries to ensure elements are available before interaction.
    • Reduces flakiness in tests.
  6. Test Data Handling:
    • Functions to pass dynamic test data and execute actions accordingly.
    • Enhances flexibility and improves test coverage.
/// <reference types="cypress" />

import cypress = require('cypress')

export class CalPage {
  visitCalPage() {
    cy.visit(Cypress.config('baseUrl'))
  }

  scrollToHeader() {
    return cy
      .get(
        'img[src="//d26tpo4cm8sb6k.cloudfront.net/img/svg/calculator-white.svg"]',
      )
      .scrollIntoView()
  }

  clickOnNumber(number) {
    return cy.get('span[onclick="r(' + number + ')"]').click()
  }

  clickOnOperator(operator) {
    return cy.get(`span[onclick="r('` + operator + `')"]`).click()
  }

  getCalculationResult(result) {
    cy.get('span[onclick="r(\'=\')"]').click()
    cy.get('#sciOutPut').should('contain', result)
  }

  clickOnNumberSeven() {
    cy.get('span[onclick="r(7)"]').click()
  }

  clickOnMinusOperator() {
    cy.get('span[onclick="r(\'-\')"]').click()
  }

  clickOnNumberFive() {
    cy.get('span[onclick="r(5)"]').click()
  }

  getResult() {
    cy.get('span[onclick="r(\'=\')"]').click()
    cy.get('#sciOutPut').should('contain', '2')
  }

  EnterNumberOnCalculatorPage(datatable) {
    datatable.hashes().forEach((element) => {
      cy.get('span[onclick="r(' + element.num1 + ')"]').click()
      cy.get('span[onclick="r(\'' + element.Op + '\')"]').click()
      cy.get('span[onclick="r(' + element.num2 + ')"]').click()
      cy.get('#sciOutPut').should('contain', '' + element.res + '')
      cy.get('span[onclick="r(\'C\')"]').click()
    })
  }

  IVerifyResult(res) {
    cy.get('#sciOutPut').should('contain', '' + res + '')
    cy.get('span[onclick="r(\'C\')"]').click()
  }
}

API Utility File:

API utility files are essential in automated testing as they provide reusable methods to interact with APIs. These files help testers perform API requests, validate responses, and maintain structured automation scripts.

By centralizing API interactions in a dedicated utility, we can improve test maintainability, reduce duplication, and ensure consistent validation of API responses.

Key Components of an API Utility File:

  1. Making API Requests Efficiently:
    • Functions for sending GET, POST, PUT, and DELETE requests.
    • Uses dynamic parameters to handle different endpoints and request types.
  2. Response Validation & Assertions:
    • Ensures correct HTTP status codes are returned.
    • Validates response bodies for expected data formats.
  3. Logging & Debugging:
    • Captures API request and response details for debugging.
    • Provides meaningful logs to assist in troubleshooting failures.
  4. Handling Dynamic Data:
    • Supports dynamic payloads using external test data sources.
    • Allows testing multiple scenarios without modifying the core test script.
  5. Error Handling & Retry Mechanism:
    • Implements error handling to manage unexpected API failures.
    • Can include automatic retries for transient errors (e.g., 429 rate limiting).
  6. Security & Authentication Handling:
    • Supports authentication headers (e.g., tokens, API keys).
    • Ensures tests adhere to security best practices like encrypting sensitive data.
/// <reference types="cypress" />

export class APIUtility {
  getQuery(req, endpoint) {
    cy.request(req, Cypress.env('api_URL') + endpoint)
  }

  iVerifyGETRequest(req, endpoint) {
    cy.request(req, Cypress.env('api_URL') + endpoint).then((response) => {
      expect(response).to.have.property('status', 200)
    })
  }

  postQueryCreate(datatable) {
    datatable.hashes().forEach((element) => {
      const body = { name: element.name, job: element.job }
      cy.log(JSON.stringify(body))
      cy.request(element.req, Cypress.env('api_URL') + 'api/users', body).then(
        (response) => {
          expect(response).to.have.property('status', 201)
          cy.log(JSON.stringify(response.body.name))
          expect(response.body.name).to.eql(element.name)
        },
      )
    })
  }

  putQueryReq(req, job) {
    cy.request(req, Cypress.env('api_URL') + 'api/users/2', job).then(
      (response) => {
        expect(response).to.have.property('status', 200)
        expect({ name: 'morpheus', job: job }).to.eql({
          name: 'morpheus',
          job: job,
        })
      },
    )
  }

  delQueryReq(req, endpoint) {
    cy.request(req, Cypress.env('api_URL') + endpoint).then((response) => {
      expect(response).to.have.property('status', 201)
    })
  }
}

Possible Improvements in the API Utility File:

  1. Add Environment-Based Configuration:
    • Currently, the base URL is fetched from Cypress.env(‘api_URL’), but we can extend it to support multiple environments (e.g., dev, staging, prod).
  2. Enhance Error Handling & Retry Logic:
    • Implement a retry mechanism for APIs that occasionally fail due to network issues.
    • Improve error messages by logging API response details when failures occur.
  3. Support Query Parameters & Headers:
    • Modify functions to accept optional query parameters and custom headers for better flexibility.
  4. Improve Response Validation:
    • Extend validation beyond just checking the status code (e.g., validating response schema using JSON schema validation).
  5. Use Utility Functions for Reusability:
    • Extract common assertions (e.g., checking response status, verifying keys in the response) into separate utility functions to avoid redundancy.
  6. Implement Rate Limiting Controls:
    • Introduce a delay between API requests in case of rate-limited endpoints to prevent hitting request limits.
  7. Better Logging & Reporting:
    • Enhance logging to provide detailed information about API requests and responses.
    • Integrate with test reporting tools to generate detailed API test reports.

Configuration Files:

Cypress.config.ts:

The Cypress configuration file (cypress.config.ts) is essential for defining the setup, plugins, and global settings for test execution. It helps in configuring test execution parameters, setting up plugins, and customizing Cypress behavior to suit the project’s needs.

This file ensures that Cypress is properly integrated with necessary preprocessor plugins (like Cucumber and Allure) while defining critical environment variables and paths.

Key Components of the Configuration File:

  1. Importing Required Modules & Plugins:
    • Cypress needs additional plugins for Cucumber support and reporting.
    • @badeball/cypress-cucumber-preprocessor is used for running .feature files with Gherkin syntax.
    • @shelex/cypress-allure-plugin/writer helps in generating test execution reports using Allure.
    • @esbuild-plugins/node-modules-polyfill ensures compatibility with Node.js modules.
  2. Setting Up Event Listeners & Preprocessors:
    • The setupNodeEvents function is responsible for handling plugins and configuring Cypress behavior dynamically.
    • The Cucumber preprocessor generates JSON reports and processes Gherkin-based test cases.
    • Browserify is used as the file preprocessor, allowing TypeScript support in tests.
  3. Environment Variables & Custom Configurations:
    • api_URL: Stores the base API URL used for API testing.
    • screenshotsFolder: Defines the folder where Cypress will save screenshots in case of failures.
  4. Defining E2E Testing Behavior:
    • setupNodeEvents: Attaches the preprocessor and other event listeners.
    • excludeSpecPattern: Ensures Cypress does not pick unwanted file types (*.js, *.md, *.ts).
    • specPattern: Specifies that Cypress should look for .feature files in cypress/e2e/.
    • baseUrl: Defines the website URL where tests will be executed (https://www.calculator.net/).
import { defineConfig } from 'cypress'
import { addCucumberPreprocessorPlugin } from '@badeball/cypress-cucumber-preprocessor'
import browserify from '@badeball/cypress-cucumber-preprocessor/browserify'

import allureWriter from '@shelex/cypress-allure-plugin/writer'
const {
  NodeModulesPolyfillPlugin,
} = require('@esbuild-plugins/node-modules-polyfill')

async function setupNodeEvents(
  on: Cypress.PluginEvents,
  config: Cypress.PluginConfigOptions,
): Promise<Cypress.PluginConfigOptions> {
  // This is required for the preprocessor to be able to generate JSON reports after each run, and more,
  await addCucumberPreprocessorPlugin(on, config)
  allureWriter(on, config),
    on(
      'file:preprocessor',
      browserify(config, {
        typescript: require.resolve('typescript'),
      }),
    )

  // Make sure to return the config object as it might have been modified by the plugin.
  return config
}
export default defineConfig({
  env: {
    api_URL: 'https://reqres.in/',
    screenshotsFolder: 'cypress/screenshots',
  },

  e2e: {
    // We've imported your old cypress plugins here.
    // You may want to clean this up later by importing these.

    setupNodeEvents,

    excludeSpecPattern: ['*.js', '*.md', '*.ts'],
    specPattern: 'cypress/e2e/**/*.feature',
    baseUrl: 'https://www.calculator.net/',
  },
})

Tsconfig.json:

The tsconfig.json file is a TypeScript configuration file that defines how TypeScript code is compiled and interpreted in a Cypress test automation framework. It ensures that Cypress and Node.js types are correctly recognized, allowing TypeScript-based test scripts to function smoothly.

Key Components of tsconfig.json:

  1. compilerOptions (Compiler Settings)
    • “esModuleInterop”: true
      • Allows interoperability between ES6 modules and CommonJS modules, enabling seamless imports.
    • “target”: “es5”
      • Specifies that the compiled JavaScript should be compatible with ECMAScript 5 (older browsers and environments).
    • “lib”: [“es5”, “dom”]
      • Includes support for ES5 and browser-specific APIs (DOM), ensuring compatibility with Cypress test scripts.
    • “types”: [“cypress”, “node”]
      • Adds TypeScript definitions for Cypress and Node.js, preventing type errors in test scripts.
  2. include (Files Included for Compilation)
    • **/*.ts
      • Ensures that all TypeScript files in the project directory are included in compilation.
    • “cypress/e2e/Features/step_definitions/Reports.js”
      • Explicitly includes a JavaScript step definition file related to reports.
    • “cypress/support/commands.ts”
      • Ensures that custom Cypress commands (written in TypeScript) are compiled and recognized.
    • “cypress/e2e/Features/step_definitions/*.ts”
      • Includes all step definition TypeScript files to be processed for test execution.
{
  "compilerOptions": {
    "esModuleInterop": true,
    "target": "es5",
    "lib": ["es5", "dom"],
    "types": ["cypress", "node"]
  },
  "include": [
    "**/*.ts",
    "cypress/e2e/Features/step_definitions/Reports.js",
    "cypress/support/commands.ts",
    "cypress/e2e/Features/step_definitions/*.ts"
  ]
}

Package.json

The package.json file is a key component of a Cypress-based test automation framework that defines project metadata, dependencies, scripts, and configurations. It helps manage all the required libraries and tools needed for running, reporting, and processing test cases efficiently.

Key Components of package.json:

  1. Project Metadata
    • “name”: “spurtype” → Defines the project name.
    • “version”: “1.0.0” → Specifies the current project version.
    • “description”: “Cypress With TypeScript” → Describes the purpose of the project.
  2. Scripts (Commands for Running Tests & Reports)
    • “scr”: “node cucumber-html-report.js”
      • Runs a script to generate a Cucumber HTML report.
    • “coms”: “cucumber-json-formatter –help”
      • Displays help information for Cucumber JSON formatter.
    • “api”: “./node_modules/.bin/cypress-tags run -e TAGS=@api”
      • Executes Cypress tests tagged as API tests (@api).
    • “smoke”: “./node_modules/.bin/cypress-tags run -e TAGS=@smoke”
      • Executes smoke tests (@smoke) using Cypress.
    • “smoke4”: “cypress run –env allure=true,TAGS=@smoke1”
      • Runs a specific set of smoke tests (@smoke1) while enabling Allure reporting.
    • “allure:report”: “allure generate allure-results –clean -o allure-report”
      • Generates a test execution report using Allure and stores it in allure-report.
  3. Report Configuration
    • “json” → Enables JSON logging and sets the output file location.
    • “messages” → Enables message logging in NDJSON format.
    • “html” → Enables HTML report generation.
    • “stepDefinitions” → Specifies the location of Cucumber step definition files (.ts).
  4. Development Dependencies (devDependencies)
    • @shelex/cypress-allure-plugin → Integrates Allure for test reporting.
    • @types/cypress-cucumber-preprocessor → Provides TypeScript definitions for Cucumber preprocessor.
    • cucumber-html-reporter, multiple-cucumber-html-reporter → Used for generating detailed Cucumber test reports.
    • cypress-cucumber-preprocessor → Enables running Cucumber feature files with Cypress.
  5. Dependencies (dependencies)
    • @badeball/cypress-cucumber-preprocessorOfficial Cucumber preprocessor for Cypress.
    • @cypress/code-coverage → Enables code coverage analysis for tests.
    • allure-commandline → Provides command-line tools to generate Allure reports.
    • typescript → Ensures TypeScript support in the test framework.
  6. Cypress Cucumber Preprocessor Configuration
    • “filterSpecs”: true → Runs only test files that match the specified tags.
    • “omitFiltered”: true → Excludes test cases that do not match the filter criteria.
    • “stepDefinitions”: “./cypress/e2e/**/*.{js,ts}” → Specifies the path for step definition files.
    • “cucumberJson”
      • “generate”: true → Enables generation of Cucumber JSON reports.
      • “outputFolder”: “cypress/cucumber-json” → Stores JSON reports in the specified folder.
{
  "name": "spurtype",
  "version": "1.0.0",
  "description": "Cypress With TypeScript",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "scr": "node cucumber-html-report.js",
    "coms": "cucumber-json-formatter --help",
    "api": "./node_modules/.bin/cypress-tags run -e TAGS=@api",
    "smoke": "./node_modules/.bin/cypress-tags run -e TAGS=@smoke",
    "smoke4": "cypress run --env allure=true,TAGS=@smoke1",
    "allure:report": "allure generate allure-results --clean -o allure-report"
  },
  "json": {
    "enabled": true,
    "output": "jsonlogs/log.json",
    "formatter": "cucumber-json-formatter.exe"
  },
  "messages": {
    "enabled": true,
    "output": "jsonlogs/messages.ndjson"
  },
  "html": {
    "enabled": true
  },
  "stepDefinitions": [
    "cypress/e2e/Features/step_definitions/*.ts"
  ],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@shelex/cypress-allure-plugin": "^2.34.0",
    "@types/cypress-cucumber-preprocessor": "^4.0.1",
    "cucumber-html-reporter": "^5.5.0",
    "cypress": "^12.14.0",
    "cypress-cucumber-preprocessor": "^4.3.0",
    "multiple-cucumber-html-reporter": "^1.21.6"
  },
  "dependencies": {
    "@badeball/cypress-cucumber-preprocessor": "^15.1.0",
    "@bahmutov/cypress-esbuild-preprocessor": "^2.1.5",
    "@cucumber/pretty-formatter": "^1.0.0",
    "@cypress/browserify-preprocessor": "^3.0.2",
    "@cypress/code-coverage": "^3.10.0",
    "@esbuild-plugins/node-modules-polyfill": "^0.1.4",
    "allure-commandline": "^2.20.1",
    "cypress-esbuild-preprocessor": "^1.0.2",
    "esbuild": "^0.15.11",
    "json-combiner": "^2.1.0",
    "tsify": "^5.0.4",
    "typescript": "^4.4.4"
  },
  "cypress-cucumber-preprocessor": {
    "filterSpecs": true,
    "omitFiltered": true,
    "stepDefinitions": "./cypress/e2e/**/*.{js,ts}",
    "cucumberJson": {
      "generate": true,
      "outputFolder": "cypress/cucumber-json",
      "filePrefix": "",
      "fileSuffix": ""
    }
  }
}

Report Configuration Files:

Cucumber-html-report.js:

This script generates a Cucumber HTML report from JSON test results using the multiple-cucumber-html-reporter package. It extracts test execution details, including browser, platform, and environment metadata, and saves the output as an HTML file for easy visualization of test results in Cypress and TypeScript Automation.

const report = require('multiple-cucumber-html-reporter');

report.generate({
    jsonDir: "./GenerateReports",  // ** Path of .json file **//
    reportPath: "./Output", // ** Path of .html file **//
    metadata: {
        browser: {
            name: "chrome",
            version: "92",
        },
        device: "Local test machine",
        platform: {
            name: "windows",
            version: "10",
        },
    },
});

Explanation of Key Components

  1. Importing multiple-cucumber-html-reporter
    • The script requires the package to process JSON reports and generate an interactive HTML report.
  2. Configuration Options
    • jsonDir → Specifies the location of Cucumber-generated JSON reports.
    • reportPath → Sets the directory where the HTML report will be saved.
    • reportName → Defines a custom name for the report file.
    • pageTitle → Sets the title of the generated HTML report page.
    • displayDuration → Enables duration display for each test case execution.
    • openReportInBrowser → Automatically opens the HTML report after generation.
  3. Metadata Section
    • Browser: Specifies the test execution browser and version.
    • Device: Identifies the test execution machine.
    • Platform: Defines the operating system used for testing.
  4. Custom Data Section
    • Provides additional test details such as Project Name, Test Environment, Execution Time, and Tester Information.

Cypress-cucumber-preprocessor.json

This JSON configuration file is primarily used to manage the Cypress Cucumber preprocessor settings. It enables JSON logging, message output, and HTML report generation, and it specifies the location of step definition files.

{
  "json": {
    "enabled": true,
    "output": "jsonlogs/log.json",
    "formatter": "cucumber-json-formatter.exe"
  },
  "messages": {
    "enabled": true,
    "output": "jsonlogs/messages.ndjson"
  },
  "html": {
    "enabled": true
  },

  "stepDefinitions": ["cypress/e2e/Features/step_definitions/*.ts"]
}

Explanation of Configuration Parameters

  1. JSON Report Configuration (json)
    • enabled: true → Ensures JSON report generation is active.
    • output: “jsonlogs/log.json” → Specifies the path where the JSON log file will be stored.
    • formatter: “cucumber-json-formatter.exe” → Defines the formatter used for generating Cucumber JSON reports.
  2. Messages Configuration (messages)
    • enabled: true → Enables the logging of execution messages.
    • output: “jsonlogs/messages.ndjson” → Specifies the path where test execution messages will be stored in NDJSON format.
  3. HTML Report Configuration (html)
    • enabled: true → Enables HTML report generation, allowing better visualization of test results.
  4. Step Definitions Configuration (stepDefinitions)
    • “stepDefinitions”: [“cypress/e2e/Features/step_definitions/*.ts”]
    • Specifies the directory where step definition files are located. These files contain the implementation for Gherkin feature file steps.

Conclusion:

Cypress and TypeScript together create a powerful and efficient framework for both web applications and API automation. By leveraging Cypress’s fast execution and robust automation capabilities alongside TypeScript’s strong typing and code scalability, we can build reliable, maintainable, and scalable test suites.

With features like Cucumber BDD integration, JSON reporting, HTML test reports, and API automation utilities, Cypress enables seamless test execution, while TypeScript enhances code quality, error handling, and developer productivity. The structured approach of defining page objects, API utilities, and configuration files ensures a well-organized framework that is both flexible and efficient.

As automation testing continues to evolve, integrating Cypress with TypeScript proves to be a future-ready solution for modern software testing needs. Whether it’s UI automation, API validation, or end-to-end testing, this dynamic combination offers speed, accuracy, and maintainability, making it an essential choice for testing high-quality web applications.

Github Link:

https://github.com/spurqlabs/SpurCypressTS

Click here to read more blogs like this.

Cypress Cucumber Framework: A Complete Guide to BDD Automation for Efficient Testing using JavaScript

Cypress Cucumber Framework: A Complete Guide to BDD Automation for Efficient Testing using JavaScript

Tired of spending hours writing and maintaining complex test scripts? We get it. That’s why we’re excited to introduce the Cypress Cucumber Framework (Cypress BDD Automation) — a game changer for software testing. This combination makes testing more efficient, collaborative, and accessible.  

Imagine a framework that speaks everyone’s language, from developers to product managers. With Cypress, Cucumber, and Behavior-Driven Development (BDD), you can therefore achieve tests that are robust, reliable, and easily understood. No more cryptic code or miscommunication!  

In this post, we will first cover the fundamentals of Cypress and Cucumber BDD, then guide you through the setup process, and finally share best practices for automation. Get ready to boost productivity and streamline your testing!

Index

  • About Cypress  
  • About Cucumber (BDD)  
  • Installation Cucumber  
  • Create Feature and Spec File   
  • Configure feature file and step definition path   
  • Execute Script   
  • How to run Cypress Cucumber tests using Tags  

In our last blog post, JavaScript and Cypress Framework for Modern UI Automation, we explored essential aspects of UI automation with Cypress. Here’s a recap of what we covered: 

  • Introduction to Cypress 
  • Setting Up Cypress 
  • Writing Effective Tests 
  • Debugging with Cypress 
  • Best Practices 
  • Real-World Examples

By the end, readers will have gained a strong foundation in Cypress for UI automation, making them ready to implement effective automated testing in their projects.

In the current blog on the Cypress Cucumber Framework: A Complete Guide to BDD Automation for Efficient Testing, we will build upon this knowledge by integrating Cucumber for Behavior-Driven Development, enhancing test readability and collaboration among team members. 

What is Behavior Driven Development (BDD)? 

Behavior Driven Development (BDD) is an agile software development practice that enhances communication between stakeholders. It, in turn, encourages collaboration among developers, testers, and non-technical team members to define how an application should behave, all based on user requirements. The core philosophy is to define behavior in plain language, making it easily understandable for all parties involved.

What is Cucumber?

Cucumber is an open-source tool that supports BDD by allowing users to write tests in plain language. It, moreover, uses a domain-specific language (DSL) called Gherkin, which is designed to be human-readable. As a result, this means that even non-technical stakeholders can participate in the testing process, enhancing collaboration and ensuring that everyone is on the same page.

Key Features of Cucumber BDD 

  • Readable Syntax: Cucumber uses Gherkin syntax, enabling test scenarios to be written in natural language. Each scenario follows the structure: 
    • Given: Sets pre-conditions or context. 
    • When: Specifies the user’s action. 
    • Then: Defines the expected outcome. 
  • Collaboration: Cucumber promotes teamwork by providing a common language, and reducing miscommunications between developers and stakeholders. 
  • Automation Support: Integrates well with tools like Selenium, making it easier to automate tests based on defined behaviors. 
  • CI/CD Integration: Cucumber can be seamlessly added to CI/CD pipelines, supporting automated testing and ensuring code quality throughout development.

Benefits of Using Cucumber BDD 

  • Improved Communication: Encourages collaboration among all stakeholders, reducing misunderstandings. 
  • Higher Test Coverage: Ensures that all user scenarios are considered by involving non-technical team members. 
  • Living Documentation: Keeps documentation relevant and up to date with evolving application features. 
  • Faster Feedback Loop: Automated tests provide quick feedback, accelerating development and iterations. 

How to Get Started with Cucumber BDD 

  1. Set Up Your Environment 
  2. Define Features and Scenarios 
  3. Map Step Definitions 
  4. Write Script 
  5. Run Tests 

Benefits of combining Cypress with Cucumber (Cypress Cucumber Framework)

While Cypress is powerful on its own, combining it with Cucumber takes our testing to a whole new level. Cucumber is a tool that supports Behavior-Driven Development (BDD), allowing us to write tests in a natural language that both technical and non-technical team members can understand. 

Here are some key benefits of this combination: 

  • Improved collaboration: By using Cucumber’s Gherkin syntax, we create a common language between developers, QA, and business stakeholders. 
  • Enhanced test readability: Cucumber scenarios are written in plain English, making it easier for everyone to understand what’s being tested. 
  • Reusable step definitions: We can create step definitions in Cypress that map to Cucumber scenarios, promoting code reuse and maintainability. 
  • Living documentation: Our Cucumber features serve as both tests and documentation, ensuring our documentation stays up to date with the actual product behavior. 
  • Scenario-driven development: We can focus on describing the desired behavior first, then implement the necessary code to make it work.

Here’s a comparison of traditional testing approaches versus BDD: 

Aspect Traditional Testing Behavior-Driven Development (BDD) 
Focus Verifying functionality Describing user behavior 
Language Technical jargon Natural language 
Collaboration Limited to developers and testers Extensive involvement of all stakeholders 
Documentation Separate from tests Tests double as documentation 
Test Creation After development Before or during development 
User Involvement Minimal Continuous involvement 
Feedback Cycle Slower feedback Rapid feedback loops 

In the next phase of our exploration of the Cypress Cucumber Framework, we’ll learn the practicalities of setup and implementation. We’ll cover how to structure projects, write effective scenarios, and harness the strengths of both Cypress and Cucumber to build a comprehensive, maintainable test suite.

Cypress Cucumber Framework Folder Structure 

When building a robust test automation framework with Cypress and Cucumber, the project structure plays a critical role in maintainability, scalability, and team collaboration. A well-organized project allows testers and developers to easily locate files, add new features, and scale the framework as the project grows. Here’s a suggested structure for setting up your Cypress Cucumber framework:

Breakdown of the Structure:

cypress/ – This is the main directory where all Cypress-related files are stored. It houses everything from test data to plugins and supporting scripts. 

e2e/features/ – This is where our .feature files, written in Gherkin syntax are stored. Each .feature file describes test scenarios in a human-readable format, enabling BDD-style testing. 
For example: – Login.feature 

e2e/step_definitions/ – This subfolder holds our JavaScript files where we define the actual step definitions corresponding to the steps in our .feature files. 
For example: – Login_steps.js 

e2e/page_objects/ – This is a new folder for Page Object Model (POM) files. Page objects abstract the logic of interacting with different pages in our application. This separation keeps your tests clean, readable, and easier to maintain. 

cypress.config.js – This configuration file allows us to manage and configure our Cypress environment. Here, we can set environment-specific configurations, manage base URLs, and define other test-related settings. 

package.json – This is the standard Node.js configuration file. It lists the dependencies, scripts, and other essential settings needed for your Cypress Cucumber project. Here, we’ll define the testing dependencies like cypress, cypress-cucumber-preprocessor, and any other required libraries. 

Based on the folder structure outlined above, let’s now proceed to create the structure in our project. 

Setting Up the Automation Framework 

Now we’ve covered the basics of Cypress and Cucumber BDD, let’s dive into setting up our automation framework. This crucial step will lay the foundation for our entire testing process, ensuring we have a robust and efficient system in place. 

Install VS Code and create new project 

Install & configure Cypress Automation Framework 

To set up the Cypress Cucumber framework, the first step is to install Visual Studio Code (VS Code) and set up a basic Cypress JavaScript framework. I’ve outlined the detailed procedure for installing Cypress and creating the initial Cypress framework in my previous blog, JavaScript and Cypress Framework for Modern UI Automation. You can follow the steps from that guide to get your Cypress framework up and running. Once that’s done, we’ll move forward with installing and integrating Cucumber BDD in our project. We can also clone cypress framework from “JavaScript-Cypress-WebAutomation” repository. 

By following the steps outlined in the JavaScript and Cypress Framework for Modern UI Automation blog, we’ll now have a complete Cypress framework set up, including the package.json, cypress.config.js, and a cypress folder containing your tests, test data, and hooks. The next step is to upgrade this existing Cypress framework to a Cypress Cucumber framework for BDD integration.

Install Cucumber 

To install Cucumber, we have to install @badeball/cypress-cucumber-preprocessor dependency version 13.0.2. 

@badeball/cypress-cucumber-preprocessor is a plugin that enables the use of Cucumber’s Behavior Driven Development (BDD) approach in Cypress testing. It allows you to write tests in Gherkin syntax (using feature files), making it easier to define scenarios in plain language that non-technical stakeholders can understand. This preprocessor translates Gherkin steps into Cypress commands, allowing smooth integration of BDD into your Cypress test suite. 

Open the terminal in VS Code, verify the project path, and run the following command to install @badeball/cypress-cucumber-preprocessor.

npm install @badeball/cypress-cucumber-preprocessor@13.0.2

Now we must install @cypress/browserify-preprocessor dependency.

@cypress/browserify-preprocessor is a plugin for Cypress that bundles JavaScript files using Browserify. It processes the files before Cypress executes them, allowing you to use CommonJS modules and other advanced JavaScript features in your test files. This preprocessor helps Cypress understand and run tests that include modern JavaScript or require module bundling, ensuring smooth execution of your test suite. 

Command to install @cypress/browserify-preprocessor 

npm install –save-dev @cypress/browserify-preprocessor 

Configuring Installed Dependencies in cypress.config.js 

When we install Cypress, the cypress.config.js file is automatically created at the root of our project. To configure Cypress with Cucumber, we need to add the following code to this file: 

This configuration in the cypress.config.js file is required to enable the Cypress Cucumber Preprocessor and handle feature files written in Gherkin syntax. 

  • const preprocessor = require(“@badeball/cypress-cucumber-preprocessor”); 
    const browserify = require(“@badeball/cypress-cucumber-preprocessor/browserify”);
     
  • These imports load the necessary preprocessor libraries to translate Gherkin syntax into Cypress test commands. 
  • preprocessor.addCucumberPreprocessorPlugin: Adds Cucumber-specific functionalities, such as generating JSON reports after test runs. 
  • on(“file:preprocessor”, browserify.default(config)): Uses Browserify to bundle the test files, ensuring the feature files and JavaScript modules are correctly processed before execution. 

In summary, this configuration integrates the Cucumber framework with Cypress and ensures that feature files are preprocessed and executed correctly.

Hooks 

Hooks are functions that allow you to run specific code before or after a scenario or feature in your Cucumber tests. These hooks help manage setup and teardown tasks, such as navigating to a webpage or resetting application state, before or after each test is executed. 

Types of Hooks:  
Before: Runs before each scenario.
After: Runs after each scenario. 
BeforeAll: Runs once before all scenarios in a feature. 
AfterAll: Runs once after all scenarios in a feature. 

Before HookThis code runs before each scenario in the feature file. It navigates to the https://www.calculator.net website using the cy.visit() command. This ensures that every test starts from the calculator page. 

After Hook This code runs after each scenario. It clicks on the cancel button (specified in the Selectors.json file) to potentially reset any changes made during the test, ensuring a clean state for subsequent tests. 

These hooks help ensure consistency and better test management by handling common setup and cleanup tasks efficiently. 

Automating Scenario 

Creating  .Feature File 

Before we begin creating the .feature file, let’s outline the functionalities we’ll be automating. We’ll be working with the Calculator.net web application, focusing on automating basic arithmetic operations: addition, subtraction, multiplication, and division. 

Test Scenarios: 

  1. Verify user can perform addition 
  2. Verify user can perform subtraction 
  3. Verify user can perform multiplication 
  4. Verify user can perform division 

Now we will follow below steps and create feature file 

  • Launch Visual Studio Code and open your project folder. 
  • Navigate to cypress/e2e create feature directory. 
  • Right-click on the feature folder and select New File.  
    – Name the file with the .feature extension, e.g., calculator.feature
  • Write below code in calculator.feature with the Gherkin Syntax

What is a Feature File?

A feature file is a document written in plain language that outlines the behavior of a software feature or a set of related features. It is primarily used in Behavior Driven Development (BDD) frameworks like Cucumber to describe application behavior in a way that both technical and non-technical stakeholders can understand. 

The structure of a feature file includes: 

  1. Feature 
  2. Scenario 
  3. Given-When-Then format 

Feature files use the Gherkin language to describe these behaviors. 

What is Gherkin?

Gherkin is a structured language used to write feature files in BDD. It uses simple syntax and plain English, making it easy for anyone, including non-developers, to understand the application’s expected behavior. Gherkin uses a specific set of keywords to define the structure of a feature file, including: 

  • Feature: A high-level description of the functionality being tested. 
  • Scenario: Individual test cases written to validate specific aspects of the feature. 
  • Given: Describes the initial context or prerequisites (e.g., navigating to a webpage). 
  • When: Specifies the action taken by the user or system (e.g., clicking a button). 
  • Then: Describes the expected outcome (e.g., the result should be displayed). 
  • And / But: Used to add additional steps to the scenario.

Gherkin’s key advantage is its readability and collaboration, as it helps bridge the communication gap between technical teams and non-technical stakeholders by providing a shared language for defining requirements. 

Creating Step Definition file

In a Cypress project using @badeball/cypress-cucumber-preprocessor, feature file steps written in plain English are mapped to corresponding code in the step definition file. This mapping is crucial because it connects the behavioral steps defined in the feature file to the automation code that performs the actual actions and validations. 

Now we will create step file and map with feature file 

  • Open project in VS code. 
  • Navigate to cypress/e2e. Right click on e2e and select New Folder and give name as “step_definition“. 
  • Right-click on the step_definition  folder and select New File.  
    – Name the file with the .js extension, e.g. CalculatorStep.js

Let’s now break down how this mapping works using the provided example: 

The step_definition file contains JavaScript functions that implement the logic for each feature file step. These functions are mapped to the feature file steps based on matching text patterns

Mapping Example: 

  • Feature Step: When User clicks on number “2” 
  • Step Definition:
  • The text “User clicks on number {string}” matches the feature step text, where {string} is a placeholder for the number (“2” in this case). 
    • The value “2” is passed as the number parameter to the function calculatorPage.clickNumber(number). 
  • Feature Step: Then The result should be “3” 
  • Step Definition: 
  • The text “The result should be {string}” matches the step, and “3” is passed as the expectedResult parameter to verifyResult. 

Dynamic Parameter Handling

The placeholders in the step definition {string} allow dynamic values from the feature file to be passed as parameters. This approach ensures that the same step definition can handle multiple scenarios with different inputs, making your tests more reusable. 

Behind the Scenes: Automatic Mapping

The @badeball/cypress-cucumber-preprocessor automatically matches feature file steps to step definitions based on the matching text. As long as: 

  • The text pattern in the step definition matches the feature file step. 
  • The corresponding file is in the correct folder structure (e.g., step_definition)

We don’t need to do any additional configuration. 

Why This Mapping is Useful 

  • Readability: The feature file is easy to understand for non-technical stakeholders. 
  • Reusability: A single step definition can be reused across multiple scenarios with different inputs. 
  • Separation of Concerns: Keeps business logic (feature file) separate from automation code (step definitions). 

Creating Page file 

What is a Page Object Model (POM) File? 

The Page Object Model (POM) is a design pattern in test automation that promotes the separation of test logic from the UI elements. It creates an object repository for web UI elements, making tests more maintainable, readable, and reusable. Each page of the application is represented by a corresponding class, which contains methods to interact with the elements on that page. 

Benefits of Using POM: 

  • Maintainability: Changes in UI require updates in only one place (the POM). 
  • Readability: Tests are cleaner and more understandable. 
  • Reusability: Common methods can be reused across different test cases. 

Now let’s create Page Object Model (POM) file, 

  • Open project in VS code. 
  • Navigate to cypress/e2e Right click on e2e and select New Folder and give name as “page“. 
  • Right-click on the page folder and select New File.  
    – Name the file with the .js extension, e.g., CalculatorPage.js

The CalculatorPage class uses the Page Object Model (POM) to manage interactions with a calculator’s UI. 

  1. Selectors Import
    • Fetches locators from Selectors.json  for buttons and result display. 
  2. Methods
    • clickNumber(number): Clicks a number button (e.g., “2” clicks selectors.twoNumberButton). 
    • clickOperator(operator): Clicks an operator button (+, -, *, /). 
    • clickEquals(): Clicks the “=” button. 
    • verifyResult(expectedResult): Validates the displayed result matches with the expected value. 

Configuring Feature and Step Definition Paths 

To seamlessly integrate feature files and step definitions in our Cypress project using the Cucumber preprocessor, we need to configure their paths. Here’s how we can set them up effectively: 

Defining the Feature File Path and additional configuration 

Start by defining where your feature files are located: 

  1. Open cypress.config.js
  2. Under the e2e section in module.exports, specify the path to your feature files and additional configuration. 

Final cypress.config.js file look as below 

breakdown of the configurations in our cypress.config.js file: 

  • specPattern: Specifies the location and format of test files .feature in the cypress/e2e directory, supporting Gherkin syntax. 
  • downloadsFolder: Custom folder path cypress/downloads for files downloaded during tests. 
  • screenshotsFolder: Specifies the folder cypress/screenshots where screenshots will be saved. 
  • viewportWidth and viewportHeight: Sets the browser’s default viewport size to 1920×1080 pixels
  • Timeouts
    • execTimeout: Maximum time (10 seconds) allowed for the execution of Cypress commands. 
    • pageLoadTimeout: Maximum time (18 seconds) to wait for page load events. 
    • defaultCommandTimeout: Maximum time (10 seconds) for Cypress commands to complete. 
  • screenshotOnRunFailure: Takes a screenshot automatically if a test fails true
  • chromeWebSecurity: Disables Chrome’s web security to allow testing across different origins (false). 
  • trashAssetsBeforeRuns: Cleans up previous test assets (like screenshots and videos) before each test runs (true). 
  • experimentalModifyObstructiveThirdPartyCode: Enables experimental support for modifying third-party scripts to improve compatibility (true). 

By configuring these paths, Cypress knows where to find and execute your feature files during test runs. 

Setting Up the Step Definition Path 

Next, configure the path to your step_definition files in the package.json file: 

  1. Open the package.json file in your Cypress project. 
  2. Add or edit the cypress-cucumber-preprocessor section to include the path for step definitions. 

Final package.js looks as below 

package.json defines the setup for a Cypress framework with Cucumber integration for Behavior-Driven Development (BDD). Let’s breakdown: 

  1. Metadata
    • name: “cypresscucumberframework” – The name of the project. 
    • version: Version of the framework. 
    • description: Describes the purpose of the project as a Cypress BDD framework using Cucumber. 
    • author: The author of the project. 
    • license: The license type. 
    • keywords: A list of relevant keywords to describe the project. 
  2. Dependencies: 
    • @badeball/cypress-cucumber-preprocessor: Used for integrating Cucumber feature files with Cypress. 
    • cypress: Core Cypress testing library. 
  3. Dev Dependencies: 
    • @cypress/browserify-preprocessor: Required to handle JavaScript files with Cucumber preprocessor. 
  4. Cypress Cucumber Preprocessor Configuration: 
    • stepDefinitions: Specifies the path for step definition files (cypress/e2e/step-definition/*.js)
    • filterSpecs: Ensures only filtered specs (by tags) are run. 
    • omitFiltered: Omits filtered tests from output results. 

This ensures the Cucumber preprocessor can locate and execute the step definitions during testing.

Execute Test Cases in Cypress 

Running Cypress Tests via Cypress Runner 

  1. Open VS Code terminal and type: 
    • npx cypress open 
  2. The Cypress Runner will launch. 
  3. Select E2E Testing, then choose your desired browser. 
  4. A dashboard will appear with all feature files listed. Select a feature file to start execution.
Cypress Cucumber Framewrok

Pro Tip: To run all test suites in one go instead of selecting them individually: 

  • Edit package.json file under the “scripts” section as shown: 

“scripts”: { 
  “script”: “cypress run –browser chrome”, 
  “test”: “npm run script” 

  • Now, execute the tests with: 

npm run test 

This command runs all tests in headless mode using Chrome. You can switch browsers if needed and even add pre-test or post-test configurations, like cleaning reports or screenshots. 

Running Cypress Cucumber Tests with Tags 

We can filter tests by tagging scenarios, such as @smoke, @sanity, or @regression. Here’s how: 

  1. Run specific tests by tag 

npx cypress run –env tags=”@regression” 

Ensure these settings are added under “cypress-cucumber-preprocessor” in package.json: 

“filterSpecs”: true, 
“omitFiltered”: true 

  1. Run tests with either of two tags 

npx cypress run –env tags=”@Smoke or @regression” 

  1. Run tests with both tags 

npx cypress run –env tags=”@Smoke and @regression” 

Test Execution Results 

Cypress Cucumber Framework result

After execution, you’ll see a summary with details like total tests, passed, failed, and skipped. This makes it easy to analyze the run and debug issues efficiently. 

By leveraging tags and custom scripts, Cypress lets us streamline test execution and manage complex scenarios with ease! 

Conclusion

The Cypress Cucumber Framework is a powerful combination that brings together the efficiency of Cypress and the collaboration-driven approach of Cucumber’s Behavior-Driven Development (BDD). By leveraging this framework, teams can write tests in plain language, improving communication and collaboration between technical and non-technical stakeholders. 

This approach ensures enhanced test readability, maintainability, and scalability through features like reusable step definitions, documentation, and integration with CI/CD pipelines. Additionally, its ability to manage complex scenarios using tags and a well-organized project structure makes it an excellent choice for modern automated testing. Adopting this framework enables faster feedback loops, higher test coverage, and user-focused application development. 

https://github.com/spurqlabs/Javascript-Cypress-BDD

Click here to read more blog like this.