Advanced Chapter 18 · 10 min read

Reusable Step Libraries

Build a library of generic, reusable step definitions — navigation steps, form steps, verification steps, and wait steps.

Building Reusable Step Libraries

As your BDD suite grows, you'll notice repeated patterns — navigating, clicking, verifying text. Instead of writing bespoke steps for every page, build a library of generic, composable steps.

CommonWebSteps.java
package com.bdd.course.stepdefinitions;

import io.cucumber.java.en.*;
import com.bdd.course.context.TestContext;
import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.*;
import org.testng.Assert;
import java.time.Duration;

public class CommonWebSteps {

    private final TestContext ctx;

    public CommonWebSteps(TestContext ctx) { this.ctx = ctx; }

    // --- Navigation ---
    @Given("the user navigates to {string}")
    public void navigateTo(String url) {
        ctx.getDriver().get(url);
    }

    @Given("the user is on the {string} page")
    public void onPage(String pageName) {
        // Map page names to URLs
        String url = switch (pageName.toLowerCase()) {
            case "login" -> "https://example.com/login";
            case "home" -> "https://example.com/";
            case "dashboard" -> "https://example.com/dashboard";
            default -> throw new IllegalArgumentException("Unknown: " + pageName);
        };
        ctx.getDriver().get(url);
    }

    // --- Form interaction ---
    @When("the user types {string} into the {string} field")
    public void typeIntoField(String text, String fieldName) {
        WebElement field = ctx.getDriver().findElement(By.name(fieldName));
        field.clear();
        field.sendKeys(text);
    }

    @When("the user clicks the {string} button")
    public void clickButton(String buttonText) {
        ctx.getDriver().findElement(
            By.xpath("//button[contains(text(),'" + buttonText + "')]"))
            .click();
    }

    @When("the user clicks the element with id {string}")
    public void clickById(String id) {
        ctx.getDriver().findElement(By.id(id)).click();
    }

    // --- Verification ---
    @Then("the page title should be {string}")
    public void verifyTitle(String expected) {
        Assert.assertEquals(ctx.getDriver().getTitle(), expected);
    }

    @Then("the URL should contain {string}")
    public void urlContains(String text) {
        Assert.assertTrue(ctx.getDriver().getCurrentUrl().contains(text));
    }

    @Then("the element {string} should be visible")
    public void elementVisible(String cssSelector) {
        WebElement el = ctx.getDriver().findElement(By.cssSelector(cssSelector));
        Assert.assertTrue(el.isDisplayed());
    }

    @Then("the text {string} should be visible on the page")
    public void textVisible(String text) {
        Assert.assertTrue(ctx.getDriver().getPageSource().contains(text));
    }

    // --- Waits ---
    @When("the user waits for the element {string} to be visible")
    public void waitForVisible(String css) {
        new WebDriverWait(ctx.getDriver(), Duration.ofSeconds(10))
            .until(ExpectedConditions.visibilityOfElementLocated(
                By.cssSelector(css)));
    }
}
common_web_steps.py
# features/steps/common_web_steps.py
from behave import given, when, then
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

PAGE_MAP = {
    'login': 'https://example.com/login',
    'home': 'https://example.com/',
    'dashboard': 'https://example.com/dashboard',
}

# --- Navigation ---
@given('the user navigates to "{url}"')
def step_navigate(context, url):
    context.driver.get(url)

@given('the user is on the "{page_name}" page')
def step_on_page(context, page_name):
    url = PAGE_MAP.get(page_name.lower())
    if not url:
        raise ValueError(f"Unknown page: {page_name}")
    context.driver.get(url)

# --- Form ---
@when('the user types "{text}" into the "{field_name}" field')
def step_type(context, text, field_name):
    el = context.driver.find_element(By.NAME, field_name)
    el.clear()
    el.send_keys(text)

@when('the user clicks the "{button_text}" button')
def step_click_button(context, button_text):
    context.driver.find_element(
        By.XPATH, f"//button[contains(text(),'{button_text}')]").click()

@when('the user clicks the element with id "{el_id}"')
def step_click_id(context, el_id):
    context.driver.find_element(By.ID, el_id).click()

# --- Verification ---
@then('the page title should be "{expected}"')
def step_title(context, expected):
    assert context.driver.title == expected

@then('the URL should contain "{text}"')
def step_url_contains(context, text):
    assert text in context.driver.current_url

@then('the element "{css}" should be visible')
def step_element_visible(context, css):
    el = context.driver.find_element(By.CSS_SELECTOR, css)
    assert el.is_displayed()

@then('the text "{text}" should be visible on the page')
def step_text_visible(context, text):
    assert text in context.driver.page_source

# --- Waits ---
@when('the user waits for the element "{css}" to be visible')
def step_wait_visible(context, css):
    WebDriverWait(context.driver, 10).until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, css)))

Cucumber BDD Advanced Reusable Step Libraries

Written by PV

© 2026 All Rights Reserved