Elysia Tools

Browse tools, examples, visual explainers, and topic guides from one clear workspace.

Top Categories

Hubs

Language
ZHDERUPTENFRES

Elysia Tools

Navigation

Testing

BDD with Cucumber - Behavior Driven Development

Comprehensive Cucumber BDD examples including feature files, step definitions, data tables, hooks, and advanced BDD patterns for collaborative development

Samples

Entries inside this sample collection

CodetextSimple

Cucumber BDD Basic Setup and Configuration

Complete Cucumber project setup with feature files, step definitions, configuration, and basic BDD patterns

Difficulty

3/10

Estimated time

45 min

Tags

cucumber, bdd, setup, configuration

Prerequisites

JavaScript basics, Testing concepts, Gherkin syntax

text
// Cucumber BDD - Basic Setup and Configuration

// 1. package.json - Dependencies and Scripts
{
  "name": "cucumber-bdd-example",
  "version": "1.0.0",
  "description": "Behavior Driven Development with Cucumber",
  "main": "index.js",
  "scripts": {
    "test": "cucumber-js",
    "test:parallel": "cucumber-js --parallel 4",
    "test:wip": "cucumber-js --tags @wip",
    "test:smoke": "cucumber-js --tags @smoke",
    "test:regression": "cucumber-js --tags @regression",
    "report:html": "cucumber-js --format html:reports/cucumber-report.html",
    "report:json": "cucumber-js --format json:reports/cucumber-report.json"
  },
  "dependencies": {
    "@cucumber/cucumber": "^10.3.1",
    "chai": "^4.3.10",
    "axios": "^1.6.2"
  },
  "devDependencies": {
    "@cucumber/cucumber": "^10.3.1",
    "@cucumber/pretty-formatter": "^1.0.0",
    "multiple-cucumber-html-reporter": "^3.6.0"
  }
}

// 2. cucumber.js - Configuration
module.exports = {
  default: {
    requireModule: ['@babel/register'],
    require: ['step-definitions/**/*.js', 'support/**/*.js'],
    format: [
      'progress-bar',
      'html:reports/cucumber-report.html',
      'json:reports/cucumber-report.json'
    ],
    formatOptions: {
      snippetInterface: 'async-await',
      snippetSyntax: 'typescript',
    },
    publishQuiet: true,
    dryRun: false,
    failFast: false,
    strict: true,
    worldParameters: {
      apiUrl: 'https://api.example.com',
      timeout: 10000
    }
  }
};

// 3. features/user-registration.feature - Gherkin Feature File
Feature: User Registration
  As a new user
  I want to register for an account
  So that I can access the application features

  Scenario: Successful user registration
    Given I am on the registration page
    When I enter valid registration details:
      | firstName | John    |
      | lastName  | Doe     |
      | email     | john@example.com |
      | password  | Secret123! |
    And I submit the registration form
    Then I should see a success message
    And I should receive a confirmation email
    And my account should be created in the system

  Scenario: Registration with invalid email
    Given I am on the registration page
    When I enter registration details with invalid email:
      | firstName | Jane    |
      | lastName  | Smith   |
      | email     | invalid-email |
      | password  | Secret123! |
    And I submit the registration form
    Then I should see an email validation error
    And my account should not be created

  @smoke
  Scenario Outline: Registration validation
    Given I am on the registration page
    When I enter registration details with "field" value "value"
    And I submit the registration form
    Then I should see "errorType" error message

    Examples:
      | field      | value          | errorType          |
      | email      | invalid-email  | email validation   |
      | password   | 123            | password strength  |
      | firstName  |                | required field     |
      | lastName   |                | required field     |

// 4. step-definitions/user-registration-steps.js - Step Definitions
const { Given, When, Then } = require('@cucumber/cucumber');
const { expect } = require('chai');
const RegistrationPage = require('../pages/registration-page');
const UserApiClient = require('../support/api-client');

let registrationPage;
let apiClient;
let userData;

// Before and After hooks
Before(async function () {
  registrationPage = new RegistrationPage();
  apiClient = new UserApiClient(this.parameters.apiUrl);
  userData = {};
});

After(async function () {
  // Cleanup: Delete test users
  if (userData.email) {
    await apiClient.deleteUser(userData.email);
  }
});

Given('I am on the registration page', async function () {
  await registrationPage.navigateTo();
  expect(await registrationPage.isLoaded()).to.be.true;
});

When('I enter valid registration details:', async function (dataTable) {
  userData = dataTable.rowsHash();
  await registrationPage.fillForm(userData);
});

When('I enter registration details with invalid email:', async function (dataTable) {
  userData = dataTable.rowsHash();
  await registrationPage.fillForm(userData);
});

When('I enter registration details with {string} value {string}', async function (field, value) {
  userData[field] = value;
  await registrationPage.fillField(field, value);
});

When('I submit the registration form', async function () {
  await registrationPage.submitForm();
});

Then('I should see a success message', async function () {
  const successMessage = await registrationPage.getSuccessMessage();
  expect(successMessage).to.include('Registration successful');
});

Then('I should receive a confirmation email', async function () {
  // This would integrate with email service
  const emailReceived = await apiClient.checkConfirmationEmail(userData.email);
  expect(emailReceived).to.be.true;
});

Then('my account should be created in the system', async function () {
  const userExists = await apiClient.userExists(userData.email);
  expect(userExists).to.be.true;
});

Then('I should see an email validation error', async function () {
  const errorMessage = await registrationPage.getErrorMessage();
  expect(errorMessage).to.include('Invalid email format');
});

Then('my account should not be created', async function () {
  const userExists = await apiClient.userExists(userData.email);
  expect(userExists).to.be.false;
});

Then('I should see {string} error message', async function (errorType) {
  const errorMessage = await registrationPage.getErrorMessage();
  const errorMessages = {
    'email validation': 'Invalid email format',
    'password strength': 'Password must be at least 8 characters',
    'required field': 'This field is required'
  };

  expect(errorMessage).to.include(errorMessages[errorType]);
});

// 5. pages/registration-page.js - Page Object Model
class RegistrationPage {
  constructor() {
    this.url = '/register';
    this.firstNameInput = '#firstName';
    this.lastNameInput = '#lastName';
    this.emailInput = '#email';
    this.passwordInput = '#password';
    this.submitButton = '#registerButton';
    this.successMessage = '.success-message';
    this.errorMessage = '.error-message';
  }

  async navigateTo() {
    await page.goto(this.url);
  }

  async isLoaded() {
    await page.waitForSelector(this.firstNameInput);
    await page.waitForSelector(this.lastNameInput);
    await page.waitForSelector(this.emailInput);
    await page.waitForSelector(this.passwordInput);
    await page.waitForSelector(this.submitButton);
    return true;
  }

  async fillForm(userData) {
    await page.fill(this.firstNameInput, userData.firstName || '');
    await page.fill(this.lastNameInput, userData.lastName || '');
    await page.fill(this.emailInput, userData.email || '');
    await page.fill(this.passwordInput, userData.password || '');
  }

  async fillField(field, value) {
    const fieldSelectors = {
      firstName: this.firstNameInput,
      lastName: this.lastNameInput,
      email: this.emailInput,
      password: this.passwordInput
    };

    await page.fill(fieldSelectors[field], value);
  }

  async submitForm() {
    await page.click(this.submitButton);
  }

  async getSuccessMessage() {
    await page.waitForSelector(this.successMessage);
    return await page.textContent(this.successMessage);
  }

  async getErrorMessage() {
    await page.waitForSelector(this.errorMessage);
    return await page.textContent(this.errorMessage);
  }
}

module.exports = RegistrationPage;

// 6. support/api-client.js - API Support
const axios = require('axios');

class UserApiClient {
  constructor(baseUrl) {
    this.client = axios.create({
      baseURL: baseUrl,
      timeout: 10000,
      headers: {
        'Content-Type': 'application/json'
      }
    });
  }

  async userExists(email) {
    try {
      const response = await this.client.get(`/users?email=${email}`);
      return response.data.length > 0;
    } catch (error) {
      return false;
    }
  }

  async deleteUser(email) {
    try {
      await this.client.delete(`/users/${email}`);
      return true;
    } catch (error) {
      return false;
    }
  }

  async checkConfirmationEmail(email) {
    // Mock implementation - would integrate with email service
    return true;
  }
}

module.exports = UserApiClient;

// 7. support/hooks.js - Custom Hooks
const { Before, After, BeforeAll, AfterAll } = require('@cucumber/cucumber');
const { chromium } = require('playwright');

let browser;
let page;

BeforeAll(async function () {
  browser = await chromium.launch({ headless: true });
});

AfterAll(async function () {
  await browser.close();
});

Before(async function () {
  page = await browser.newPage();
  global.page = page;
});

After(async function () {
  await page.close();
});

// Tag-based hooks
Before({ tags: '@smoke' }, async function () {
  console.log('Running smoke test...');
});

Before({ tags: '@api' }, async function () {
  // Setup API test environment
});

After({ tags: '@cleanup' }, async function () {
  // Perform cleanup operations
});
CodetextIntermediate

Advanced Cucumber Patterns and Best Practices

Complex BDD patterns including data tables, scenario outlines, hooks, tags, and enterprise-level Cucumber implementation

Difficulty

6/10

Estimated time

75 min

Tags

cucumber, bdd, advanced, patterns

Prerequisites

Cucumber basics, BDD concepts, JavaScript advanced, Page Object Model

text
// Cucumber Advanced Patterns and Best Practices

// 1. features/e-commerce-shopping.feature - Complex Feature File
Feature: E-commerce Shopping Cart
  As a customer
  I want to add products to my cart and complete purchases
  So that I can buy products online

  Background:
    Given I am logged in as a customer
    And the following products exist in the catalog:
      | id  | name               | price  | category    | stock |
      | 1   | Laptop Pro         | 999.99 | Electronics | 10    |
      | 2   | Wireless Mouse     | 29.99  | Electronics | 50    |
      | 3   | Coffee Maker       | 79.99  | Home        | 25    |
      | 4   | Bluetooth Headphones | 149.99 | Electronics | 30 |

  @shopping @regression
  Scenario: Add single product to cart
    When I add product "Laptop Pro" to cart
    Then my cart should contain 1 item
    And the cart total should be $999.99
    And the product stock should be updated to 9

  @shopping @regression
  Scenario: Add multiple products to cart
    When I add the following products to cart:
      | product name         | quantity |
      | Wireless Mouse       | 2        |
      | Bluetooth Headphones | 1        |
      | Coffee Maker         | 1        |
    Then my cart should contain 4 items
    And the cart total should be $289.96
    And each product stock should be updated accordingly

  @checkout @critical
  Scenario Outline: Complete purchase with different payment methods
    Given I have the following products in my cart:
      | product name    | quantity |
      | Laptop Pro      | 1        |
    When I proceed to checkout
    And I select payment method
    And I enter payment details
    Then I should see order confirmation
    And I should receive order confirmation email
    And the order should be created in the system
    And my cart should be empty

    Examples:
      | payment method    |
      | Credit Card       |
      | PayPal            |
      | Bank Transfer     |

  @inventory @edge-case
  Scenario: Attempt to add out-of-stock product
    When the product "Laptop Pro" stock is 0
    And I attempt to add "Laptop Pro" to cart
    Then I should see "out of stock" error message
    And the product should not be added to my cart

  @discount @promotion
  Scenario: Apply discount code to cart
    Given I have the following products in my cart:
      | product name    | quantity |
      | Laptop Pro      | 1        |
      | Wireless Mouse  | 1        |
    When I apply discount code "SAVE10"
    Then a 10% discount should be applied
    And the cart total should be $923.98

// 2. step-definitions/shopping-cart-steps.js - Advanced Step Definitions
const { Given, When, Then, defineParameterType } = require('@cucumber/cucumber');
const { expect } = require('chai');
const ShoppingCart = require('../support/shopping-cart');
const ProductCatalog = require('../support/product-catalog');
const PaymentProcessor = require('../support/payment-processor');

// Custom parameter type for product identification
defineParameterType({
  name: 'product',
  regexp: /"([^"]+)"/,
  transformer(name) {
    return ProductCatalog.findByName(name);
  }
});

// Custom parameter type for currency amounts
defineParameterType({
  name: 'amount',
  regexp: /$([0-9.]+)/,
  transformer(amount) {
    return parseFloat(amount);
  }
});

let shoppingCart;
let productCatalog;
let paymentProcessor;
let currentUser;

Before(async function () {
  shoppingCart = new ShoppingCart();
  productCatalog = new ProductCatalog();
  paymentProcessor = new PaymentProcessor();
  currentUser = null;
});

Given('I am logged in as a customer', async function () {
  currentUser = await this.createUser({
    email: 'customer@example.com',
    role: 'customer'
  });
});

Given('the following products exist in the catalog:', async function (dataTable) {
  for (const row of dataTable.hashes()) {
    await productCatalog.addProduct({
      id: parseInt(row.id),
      name: row.name,
      price: parseFloat(row.price),
      category: row.category,
      stock: parseInt(row.stock)
    });
  }
});

When('I add product {product} to cart', async function (product) {
  await shoppingCart.addItem({
    productId: product.id,
    quantity: 1,
    userId: currentUser.id
  });
});

When('I add the following products to cart:', async function (dataTable) {
  for (const row of dataTable.hashes()) {
    const product = await productCatalog.findByName(row['product name']);
    await shoppingCart.addItem({
      productId: product.id,
      quantity: parseInt(row.quantity),
      userId: currentUser.id
    });
  }
});

Then('my cart should contain {int} item(s)', async function (expectedCount) {
  const cart = await shoppingCart.getCart(currentUser.id);
  expect(cart.items.length).to.equal(expectedCount);
});

Then('the cart total should be {amount}', async function (expectedTotal) {
  const cart = await shoppingCart.getCart(currentUser.id);
  expect(cart.total).to.equal(expectedTotal);
});

Then('the product stock should be updated to {int}', async function (expectedStock) {
  const product = await productCatalog.findByName('Laptop Pro');
  expect(product.stock).to.equal(expectedStock);
});

Then('each product stock should be updated accordingly', async function () {
  const cart = await shoppingCart.getCart(currentUser.id);
  for (const item of cart.items) {
    const product = await productCatalog.findById(item.productId);
    const originalStock = 10; // From background setup
    expect(product.stock).to.equal(originalStock - item.quantity);
  }
});

// 3. support/data-tables.js - Data Table Utilities
class DataTableHelper {
  static toMap(dataTable, keyColumn, valueColumn) {
    const result = {};
    for (const row of dataTable.hashes()) {
      result[row[keyColumn]] = row[valueColumn];
    }
    return result;
  }

  static toArrayOfMaps(dataTable) {
    return dataTable.rows().map(row => {
      const headers = dataTable.raw()[0];
      return headers.reduce((obj, header, index) => {
        obj[header] = row[index];
        return obj;
      }, {});
    });
  }

  static toList(dataTable, column) {
    return dataTable.rows().map(row => row[column]);
  }

  static validateRequiredColumns(dataTable, requiredColumns) {
    const headers = dataTable.raw()[0];
    for (const column of requiredColumns) {
      if (!headers.includes(column)) {
        throw new Error(`Required column '${column}' not found in data table`);
      }
    }
  }
}

module.exports = DataTableHelper;

// 4. support/world-parameters.js - Custom World
const { setWorldConstructor } = require('@cucumber/cucumber');

class CustomWorld {
  constructor({ attach, parameters }) {
    this.attach = attach;
    this.parameters = parameters;
    this.testData = new Map();
    this.apiClient = null;
    this.database = null;
  }

  // Test data management
  setTestData(key, value) {
    this.testData.set(key, value);
  }

  getTestData(key) {
    return this.testData.get(key);
  }

  // API client management
  async createApiClient(options = {}) {
    this.apiClient = new ApiClient({
      baseURL: this.parameters.apiUrl,
      ...options
    });
    return this.apiClient;
  }

  // Database helpers
  async createDatabaseConnection() {
    this.database = new DatabaseClient(this.parameters.databaseUrl);
    await this.database.connect();
    return this.database;
  }

  // Screenshot attachment
  async attachScreenshot(name) {
    if (this.page) {
      const screenshot = await this.page.screenshot({
        encoding: 'base64',
        fullPage: true
      });
      await this.attach(screenshot, `image/png`);
      await this.attach(`Screenshot: ${name}`, 'text/plain');
    }
  }

  // Response attachment
  attachApiResponse(response) {
    const responseBody = JSON.stringify(response.data, null, 2);
    this.attach(`API Response (${response.status}):`, 'text/plain');
    this.attach(responseBody, 'application/json');
  }
}

setWorldConstructor(CustomWorld);

// 5. support/hooks.js - Advanced Hook Management
const { Before, After, BeforeAll, AfterAll } = require('@cucumber/cucumber');
const DatabaseClient = require('./database-client');

// Global hooks
BeforeAll(async function () {
  console.log('Setting up test environment...');
  await setupTestEnvironment();
});

AfterAll(async function () {
  console.log('Cleaning up test environment...');
  await cleanupTestEnvironment();
});

// Tag-based hooks
Before({ tags: '@api' }, async function (world) {
  await world.createApiClient({
    timeout: 30000,
    retries: 3
  });
});

Before({ tags: '@database' }, async function (world) {
  await world.createDatabaseConnection();
});

After({ tags: '@database' }, async function (world) {
  if (world.database) {
    await world.database.close();
  }
});

// Conditional hooks based on scenario name
Before(async function (scenario) {
  if (scenario.pickle.name.includes('performance')) {
    this.testType = 'performance';
    this.startTime = Date.now();
  }
});

After(async function (scenario) {
  // Attach screenshot if scenario failed
  if (scenario.result.status === 'FAILED') {
    await this.attachScreenshot(`failed-${scenario.pickle.name}`);
  }

  // Log performance metrics
  if (this.testType === 'performance') {
    const duration = Date.now() - this.startTime;
    console.log(`Scenario '${scenario.pickle.name}' completed in ${duration}ms`);
  }
});

// 6. support/reporting.js - Custom Reporting
const { Before, After } = require('@cucumber/cucumber');

Before(async function (scenario) {
  this.scenarioData = {
    name: scenario.pickle.name,
    tags: scenario.pickle.tags.map(tag => tag.name),
    startTime: new Date()
  };
});

After(async function (scenario) {
  const endTime = new Date();
  const duration = endTime - this.scenarioData.startTime;

  // Generate custom report data
  const reportData = {
    scenario: this.scenarioData.name,
    status: scenario.result.status,
    duration: duration,
    tags: this.scenarioData.tags,
    timestamp: endTime.toISOString()
  };

  // Store for custom reporting
  if (!global.customReports) {
    global.customReports = [];
  }
  global.customReports.push(reportData);
});

// 7. support/custom-matchers.js - Custom Chai Matchers
const { expect } = require('chai');

// Custom matcher for price validation
expect.addMethod('toCost', function (expectedAmount) {
  const actual = this._obj;
  const tolerance = 0.01; // Allow for floating point precision

  this.assert(
    Math.abs(actual - expectedAmount) <= tolerance,
    `expected #{this} to cost ${expectedAmount}, but it costs ${actual}`,
    `expected #{this} to not cost ${expectedAmount}, but it does`
  );
});

// Custom matcher for product stock validation
expect.addMethod('toHaveStock', function (expectedStock) {
  const product = this._obj;
  this.assert(
    product.stock === expectedStock,
    `expected product #{product.name} to have stock ${expectedStock}, but has ${product.stock}`,
    `expected product #{product.name} to not have stock ${expectedStock}, but it does`
  );
});

// Usage examples:
// expect(cart.total).toCost(99.99);
// expect(product).toHaveStock(10);

Tools

Tools frequently paired with this sample

Related

Related sample collections

Related

Related workflows

Hub

UI Screenshot Structure Review and Development Handoff

Turn one authorized UI screenshot into a manually reviewed component tree, validated JSON and development notes, with source coordinates, uncertainty and revision evidence preserved.

Hub

cURL API Request Conversion and Testing

Convert a cURL request into code or HAR, test it safely, and explain the HTTP status without losing headers, body, or auth context.

Hub

Authorized JWT, OTP, TOTP, and Session Test Workflow

Build sanitized auth fixtures, separate token generation from decoding and verification, test OTP/TOTP timing, and audit JWT and session evidence without exposing real secrets.

Hub

Deliberate Text Corruption and Mutation for Testing

Break clean text on purpose — filter, duplicate, and reverse sentences and words, inject random letters and symbols, shuffle lines and words, and prove every mutation stays controlled for parser stress tests, OCR rehearsal, and language experiments.

Home
Tools3212
Workbench
Samples593
Visualizations471
Viewers103
Hubs239
Tags333
Images, Audio & Video657

Image, audio, and video processing, conversion, and optimization tools

Math, Date & Finance647

Calculators, numerics, date logic, statistics, and finance tools

Design & Color298

Color, layout, graphics, visual styling, and design helper tools

Text & Writing209

Writing, cleanup, formatting, extraction, and text analysis tools

Developer & Web193

Developer utilities, networking, web debugging, and automation helpers

Conversion & Encoding175

Format, file, archive, unit, and encoding conversion tools

Lead Generation Quiz Launch and Contact Handoff
Memorial Drafts: Family Review and Print Handoff
Private Habit Records: Backup, Restore and Sharing Review
Article to X and LinkedIn Drafts: Fact Review and Handoff
Markdown Interactive Deck Review and Offline Handoff

© 2026 Elysia Tools. All rights reserved.

DocsPricingAboutTerms of ServicePrivacy PolicyCookiesContact

Media

AVI to MP4 Converter

Convert AVI video files to MP4 format

Media

MP4 to AVI Converter

Convert MP4 video files to AVI format

Media

Batch Video Converter

Convert multiple video files between different formats like MP4, WebM, MKV, AVI, MOV with quality settings and batch processing

Media

Video to GIF Optimized

Convert videos to optimized GIF format with advanced compression settings

Media

Video Cutter

Cut and trim video clips with precision, supporting multiple formats and quality settings

Media

Video to APNG

Convert video clips to APNG (Animated PNG) format with transparency support and better quality than GIF

Media

Video to Image Sequence

Extract video frames as an image sequence with customizable frame rate, quality, and output format

Media

Video Trim

Quickly trim video clips - extract segments from videos with fast, lossless processing

Media

SVG Samples

Scalable Vector Graphics (SVG) samples demonstrating various SVG features and techniques

Web Frameworks

Preact Samples

Preact framework examples including components, hooks, routing, and modern Preact patterns

Media

QR Code Samples

Sample QR code images for testing QR code reading and generation tools

CSS Frameworks

Bootstrap 5 Samples

Bootstrap 5 CSS framework examples including components, utilities, layout system, and responsive design patterns

CSS Frameworks

Bulma CSS Framework Samples

Bulma CSS framework examples including columns, components, form controls, layout system, and modern CSS-based design patterns

Reference

Length Unit Samples

Practical length unit references you can copy when you want to compare common units directly with meters (m)