Welcome to the eighteenth part of our Cucumber series for beginners! In the previous post, we explored the Test Runner, which orchestrates Cucumber test execution. Now, we’ll dive into Integration with Selenium, a powerful combination that allows you to automate web browser interactions using Cucumber’s behavior-driven development (BDD) approach. This guide will explain how to integrate Cucumber with Selenium, set up a project, and provide practical examples to make it easy for beginners and valuable for experienced professionals. Let’s get started!
What is Cucumber Integration with Selenium?
Cucumber with Selenium combines Cucumber’s human-readable Gherkin scenarios with Selenium WebDriver’s ability to automate web browsers. Cucumber defines test scenarios in plain language, while Selenium executes browser actions like clicking buttons, entering text, or verifying page elements. This integration enables end-to-end testing of web applications in a collaborative, maintainable way.
Why Use Cucumber with Selenium?
- Readable Tests: Write tests in Gherkin that non-technical stakeholders can understand.
- Browser Automation: Use Selenium to interact with web elements (e.g., forms, links, tables).
- Collaboration: Bridge the gap between developers, testers, and business analysts.
- Reusability: Create reusable step definitions for common web interactions.
- Cross-Browser Testing: Test on multiple browsers (e.g., Chrome, Firefox) using Selenium.
Setting Up a Cucumber-Selenium Project
Let’s set up a Maven project, create a feature file, and integrate Selenium to automate a login scenario. This example uses ChromeDriver, but you can adapt it for other browsers.
Step 1: Create a Maven Project
Create a new Maven project in your IDE (e.g., IntelliJ) with the following pom.xml
:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>cucumber-selenium-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<!-- Cucumber Dependencies -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>7.18.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>7.18.0</version>
<scope>test</scope>
</dependency>
<!-- Selenium Dependency -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.25.0</version>
<scope>test</scope>
</dependency>
<!-- JUnit Dependency -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.0</version>
</plugin>
</plugins>
</build>
</project>
Step 2: Download ChromeDriver
Download the ChromeDriver executable compatible with your Chrome browser version from chromedriver.chromium.org. Place it in a directory (e.g., drivers/
) in your project or set the path programmatically.
Step 3: Create a Feature File
Create a file named login.feature
in src/test/resources/features
:
Feature: User Login
As a user, I want to log in to the application so that I can access my account.
Scenario: Successful login with valid credentials
Given the user is on the login page
When the user enters "demo@example.com" and "password123"
And the user clicks the login button
Then the user should be redirected to the dashboard
Note: This example uses a demo website (e.g., saucedemo.com) for testing. Replace URLs and credentials with your application’s details.
Step 4: Create Step Definitions with Selenium
Create LoginSteps.java
in src/test/java/steps
:
package steps;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.When;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.And;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.junit.Assert;
public class LoginSteps {
private WebDriver driver;
@Before
public void setUp() {
System.setProperty("webdriver.chrome.driver", "drivers/chromedriver"); // Update path
driver = new ChromeDriver();
driver.manage().window().maximize();
}
@After
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
@Given("the user is on the login page")
public void userIsOnLoginPage() {
driver.get("https://www.saucedemo.com/");
}
@When("the user enters {string} and {string}")
public void userEntersCredentials(String username, String password) {
driver.findElement(By.id("user-name")).sendKeys(username);
driver.findElement(By.id("password")).sendKeys(password);
}
@And("the user clicks the login button")
public void userClicksLoginButton() {
driver.findElement(By.id("login-button")).click();
}
@Then("the user should be redirected to the dashboard")
public void userRedirectedToDashboard() {
String currentUrl = driver.getCurrentUrl();
Assert.assertTrue("User not redirected to dashboard", currentUrl.contains("inventory.html"));
}
}
Explanation:
- @Before: Initializes ChromeDriver and maximizes the browser window.
- @After: Closes the browser after each scenario.
- Selenium Actions:
- Navigates to the login page (
driver.get
). - Enters credentials using
findElement
andsendKeys
. - Clicks the login button.
- Verifies redirection by checking the URL.
- Navigates to the login page (
- Assertions: Uses JUnit’s
Assert
to verify the outcome.
Step 5: Create a Test Runner
Create TestRunner.java
in src/test/java/runner
:
package runner;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
@RunWith(Cucumber.class)
@CucumberOptions(
features = "src/test/resources/features",
glue = "steps",
plugin = {
"pretty",
"html:target/cucumber-reports/cucumber.html",
"json:target/cucumber-reports/cucumber.json"
},
monochrome = true
)
public class TestRunner {
}
Step 6: Run the Tests
Ensure ChromeDriver is in the specified path (e.g., drivers/chromedriver
). Run the tests using Maven:
mvn test
Output (Console):
Navigating to login page
Entering username: demo@example.com, password: password123
Clicking login button
Verifying redirection to dashboard
1 Scenarios (1 passed)
4 Steps (4 passed)
0m5.123s
Reports:
- HTML: Open
target/cucumber-reports/cucumber.html
in a browser to view the test results. - JSON: Check
target/cucumber-reports/cucumber.json
for structured data.
Browser Behavior:
- A Chrome browser opens, navigates to saucedemo.com, enters credentials, clicks the login button, and verifies the dashboard URL before closing.
Enhancing the Integration
Let’s explore advanced techniques to make the Cucumber-Selenium integration more robust.
Example 1: Handling Multiple Scenarios
Update login.feature
to include a failed login scenario:
Feature: User Login
As a user, I want to log in to the application so that I can access my account.
@smoke
Scenario: Successful login with valid credentials
Given the user is on the login page
When the user enters "standard_user" and "secret_sauce"
And the user clicks the login button
Then the user should be redirected to the dashboard
@regression
Scenario: Failed login with invalid credentials
Given the user is on the login page
When the user enters "invalid_user" and "wrongpass"
And the user clicks the login button
Then the user should see an error message
Update LoginSteps.java
:
@Then("the user should see an error message")
public void userSeesErrorMessage() {
String errorMessage = driver.findElement(By.cssSelector("[data-test='error']")).getText();
Assert.assertTrue("Error message not displayed", errorMessage.contains("Username and password do not match"));
}
Run the tests:
mvn test
Output:
The HTML report will show one passed scenario (@smoke
) and one passed scenario (@regression
), assuming the error message is displayed correctly.
Example 2: Using Scenario Hooks for Screenshots
Capture screenshots on failure using an @After
hook. Update LoginSteps.java
:
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import io.cucumber.java.Scenario;
import java.nio.file.Files;
import java.nio.file.Paths;
@After
public void tearDown(Scenario scenario) {
if (scenario.isFailed() && driver != null) {
byte[] screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
scenario.attach(screenshot, "image/png", "failure-screenshot");
}
if (driver != null) {
driver.quit();
}
}
Explanation:
- If a scenario fails, a screenshot is captured and attached to the Cucumber report.
- The screenshot appears in the HTML report for failed scenarios, aiding debugging.
Example 3: Page Object Model (POM)
Use the Page Object Model to organize web elements and actions. Create LoginPage.java
in src/test/java/pages
:
package pages;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class LoginPage {
private WebDriver driver;
private By usernameField = By.id("user-name");
private By passwordField = By.id("password");
private By loginButton = By.id("login-button");
private By errorMessage = By.cssSelector("[data-test='error']");
public LoginPage(WebDriver driver) {
this.driver = driver;
}
public void enterCredentials(String username, String password) {
driver.findElement(usernameField).sendKeys(username);
driver.findElement(passwordField).sendKeys(password);
}
public void clickLoginButton() {
driver.findElement(loginButton).click();
}
public String getErrorMessage() {
return driver.findElement(errorMessage).getText();
}
public String getCurrentUrl() {
return driver.getCurrentUrl();
}
}
Update LoginSteps.java
to use the page object:
public class LoginSteps {
private WebDriver driver;
private LoginPage loginPage;
@Before
public void setUp() {
System.setProperty("webdriver.chrome.driver", "drivers/chromedriver");
driver = new ChromeDriver();
driver.manage().window().maximize();
loginPage = new LoginPage(driver);
}
@Given("the user is on the login page")
public void userIsOnLoginPage() {
driver.get("https://www.saucedemo.com/");
}
@When("the user enters {string} and {string}")
public void userEntersCredentials(String username, String password) {
loginPage.enterCredentials(username, password);
}
@And("the user clicks the login button")
public void userClicksLoginButton() {
loginPage.clickLoginButton();
}
@Then("the user should be redirected to the dashboard")
public void userRedirectedToDashboard() {
String currentUrl = loginPage.getCurrentUrl();
Assert.assertTrue("User not redirected to dashboard", currentUrl.contains("inventory.html"));
}
@Then("the user should see an error message")
public void userSeesErrorMessage() {
String errorMessage = loginPage.getErrorMessage();
Assert.assertTrue("Error message not displayed", errorMessage.contains("Username and password do not match"));
}
}
Explanation:
- POM: Encapsulates web elements and actions in
LoginPage
, improving maintainability. - Reusability: Page methods can be reused across multiple step definitions.
Best Practices for Cucumber-Selenium Integration
- Use Page Object Model: Organize web elements and actions in page classes to reduce duplication.
- Manage WebDriver: Initialize and close WebDriver in
@Before
and@After
hooks. - Add Screenshots: Capture screenshots on failure for debugging.
- Use Explicit Waits: Use
WebDriverWait
for dynamic elements to avoid flaky tests:import org.openqa.selenium.support.ui.WebDriverWait; import org.openqa.selenium.support.ui.ExpectedConditions; WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10)); wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("login-button")));
- Keep Steps Focused: Write Gherkin steps for user behavior, not implementation details.
- Test Across Browsers: Configure WebDriver for multiple browsers (e.g., Chrome, Firefox) using a factory pattern.
Troubleshooting Cucumber-Selenium Issues
- WebDriver Path Errors: Ensure the ChromeDriver path is correct and matches your browser version.
- Element Not Found: Use explicit waits or verify element locators (e.g., ID, CSS, XPath).
- Flaky Tests: Add synchronization (e.g.,
WebDriverWait
) to handle dynamic content. - Browser Not Closing: Ensure
@After
hook callsdriver.quit()
. - Report Issues: Verify
plugin
settings inTestRunner
for HTML/JSON report generation.
Tips for Beginners
- Start with One Browser: Use ChromeDriver initially before adding cross-browser support.
- Inspect Elements: Use browser developer tools to find reliable locators (e.g., ID, CSS).
- Run Tests Locally: Test in your IDE before integrating with CI/CD.
- Use Saucedemo: Practice with saucedemo.com for learning.
What’s Next?
You’ve learned how to integrate Cucumber with Selenium to automate web browser testing. In the next blog post, we’ll explore Integration with REST-assured, which enables API testing with Cucumber for validating backend services.
Let me know when you’re ready for the next topic (Integration with REST-assured), and I’ll provide a detailed post!
System: * Today's date and time is 04:45 PM IST on Friday, June 06, 2025.