NashTech Blog

Getting Started With Gherkin Language and Playwright-BDD for End-to-End Testing

Table of Contents

End-to-end (E2E) testing has become an essential part of modern web development. As applications grow more complex, teams need a testing approach that is understandable to both developers and non-technical stakeholders. This is where Gherkin and Playwright-BDD shine: Gherkin provides human-readable test scenarios, while Playwright offers a fast, reliable browser automation engine.

In this blog, we’ll explore what Gherkin is, how Playwright-BDD works, and finally how to set up a new project combining both.

1. What Is Gherkin Language?

Gherkin is a domain-specific language (DSL) used for writing behavior-driven development (BDD) scenarios.
Its strength lies in clarity — Gherkin documents describe software behavior in plain English using a strict but readable structure.

Key features of Gherkin
  • Readable by anyone (QA, dev, BA, product owner)
  • Executable when paired with a BDD framework like Cucumber or Playwright-BDD
  • Structured using keywords like Feature, Scenario, Given, When, Then

Gherkin Scenario (search.feature)

Feature: Search Bar

Scenario: Search for a product
Given I am on the homepage
When I search for "laptop"
Then I should see search results related to "laptop"

This scenario reads like a conversation — and that’s the whole point.

2. What Is Playwright-BDD?

Playwright-BDD is a library that integrates Gherkin-style BDD tests with Microsoft Playwright, enabling you to write .feature files and implement steps that interact with browsers.

Why use Playwright-BDD?
  • You get Playwright’s speed and robustness
  • You keep Gherkin readability
  • You structure tests the BDD way
  • Easy to scale test suites for large teams

It works similarly to Cucumber, but powered by Playwright under the hood

3. Setting Up a New Project With Playwright-BDD

Below is a clean, step-by-step setup guide.

Step 1 — Create a New Project
mkdir playwright-bdd-project
cd playwright-bdd-project
npm init -y
Step 2 — Install Required Dependencies
npm install -D @playwright/test playwright-bdd

Install the browsers needed for testing

npx playwright install

This downloads Chromium, Firefox, and WebKit browsers.

Step 3 — Project Structure

Create the following directory structure:

playwright-bdd-project/
├── features/
│ ├── steps/
│ └── checkbox.feature
├── playwright.config.ts
└── package.json
Step 4: Configure Playwright

Create `playwright.config.ts`

import { defineConfig } from '@playwright/test';
import { defineBddConfig } from 'playwright-bdd';

const testDir = defineBddConfig({
  paths: ['features/**/*.feature'],
  steps: ['features/steps/**/*.ts'],
});

export default defineConfig({
  testDir,
  reporter: 'html',
  use: {
    baseURL: 'https://practice.expandtesting.com',
  },
});
Step 5: Update package.json Scripts

Add these scripts to your `package.json`:

{
  "scripts": {
    "test": "playwright test",
    "test:ui": "playwright test --ui",
    "test:headed": "playwright test --headed",
    "test:debug": "playwright test --debug",
    "bdd:generate": "bddgen",
    "bdd:watch": "bddgen --watch"
  }
}

Script explanations:

– test – Run tests in headless mode

– test:ui – Run tests with Playwright UI mode

– test:headed – Run tests with visible browser

– test:debug – Run tests in debug mode

– bdd:generate – Generate test files from feature files

– bdd:watch – Watch for changes and regenerate automatically

Step 6 — Create a Feature File

Create: features/checkbox.feature

Feature: Checkboxes
As a user
I want to interact with checkboxes
So that I can test checkbox functionality

Background:
Given I navigate to the checkboxes page

Scenario: Happy Case - Check and uncheck checkboxes
When I check "Checkbox 1"
Then "Checkbox 1" should be checked
Step 7 — Create Step Definitions

Create `features/steps/checkbox.steps.ts`:

import { createBdd, test } from 'playwright-bdd';
import { expect } from '@playwright/test';

const { Given, When, Then } = createBdd(test);

// Export test instance for playwright-bdd
export { test };

Given('I navigate to the checkboxes page', async ({ page }) => {
  await page.goto('/checkboxes');
  await expect(page).toHaveTitle(/Check Boxes Page/i);
});

When('I check {string}', async ({ page }, checkboxLabel) => {
  await page.getByRole('checkbox', { name: checkboxLabel }).check();
});

Then('{string} should be checked', async ({ page }, checkboxLabel) => {
  await expect(page.getByRole('checkbox', { name: checkboxLabel })).toBeChecked();
});

Step Definition Breakdown:
1. Import statements:

   – `createBdd, test` from `playwright-bdd` – Creates BDD test context

   – `expect` from `@playwright/test` – Assertions

2. Given step:

   – Navigates to the checkboxes page

   – Verifies the page title

3. When step:

   – Uses `getByRole(‘checkbox’, { name: … })` – Playwright’s recommended semantic locator

   – `{string}` is a parameter that captures text from the feature file

   – `.check()` – Checks the checkbox

4. Then step:

   – Uses the same locator to find the checkbox

   – `.toBeChecked()` – Asserts the checkbox is checked

Why `getByRole`?

– More reliable than CSS selectors

– Follows accessibility best practices

– Easier to read and maintain

– Less brittle when UI changes

Step 8: Generate Test Files

Generate the Playwright test files from your feature files:

npm run bdd:generate

This creates test files in `.features-gen/` directory. These are auto-generated and shouldn’t be edited manually.

Step 9: Run Your Tests

Run the tests:

npm test

Or run with UI mode for a better experience:

npm run test:ui

4. Best Practices

Use Semantic Locators

page.getByRole('checkbox', { name: 'Checkbox 1' }) // good

page.locator('input[type="checkbox"]').first() // avoid

Keep Steps Reusable
Write step definitions that can be reused across multiple scenarios:

When('I check {string}', async ({ page }, checkboxLabel) => {
  await page.getByRole('checkbox', { name: checkboxLabel }).check();
});

Use Background for Common Setup
If multiple scenarios need the same setup, use `Background`:

Background:
  Given I navigate to the checkboxes page

Write Clear Feature Descriptions
Make your feature files readable for non-technical stakeholders:

Feature: Checkboxes
  As a user
  I want to interact with checkboxes
  So that I can test checkbox functionality

Keep Step Definitions Simple
Each step should do one thing. If a step is too complex, break it into smaller steps.

5. Advanced Topics

Parameter Types
You can use different parameter types in your steps:

When('I check checkbox number {int}', async ({ page }, checkboxNumber) => {
  // checkboxNumber is a number
});

When('I check {string} at {date}', async ({ page }, label, date) => {
  // date is a Date object
});

Data Tables
Use tables for multiple test data:

Scenario: Check multiple checkboxes
  When I check the following checkboxes:
    | Checkbox 1 |
    | Checkbox 2 |
    | Checkbox 3 |

Scenario Outlines
Run the same scenario with different data:

Scenario Outline: Check different checkboxes
  When I check "<checkbox>"
  Then "<checkbox>" should be checked

  Examples:
    | checkbox    |
    | Checkbox 1  |
    | Checkbox 2  |

6. Conclusion

Both Playwright and Playwright-BDD have proven to be powerful tools for building a clean and maintainable testing workflow. After working with them extensively on a real project, I’ve seen firsthand how much they can improve test reliability, readability, and speed. I hope that sharing my practical experience gives you a clearer idea of what to expect and helps you decide whether these tools are the right fit for your own project.

Resources
– Playwright Documentation: https://playwright.dev/
– playwright-bdd GitHub: https://github.com/vitalets/playwright-bdd
– Gherkin Syntax Reference: https://cucumber.io/docs/gherkin/reference/
– Blog: https://willholmes.hashnode.dev/executing-bdd-tests-with-playwright

Picture of Dung Do Minh

Dung Do Minh

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

Scroll to Top