|
A collection of reusable Playwright step definitions for Cucumber in TypeScript, designed to streamline end-to-end testing across web, API, and mobile applications.
Note: This package is designed for advanced Cucumber+Playwright+TypeScript setups. For basic Playwright usage, see the official Playwright docs.
The "Low-Code" BDD Framework for Playwright.
Write powerful end-to-end tests in plain English using Gherkin syntax, without managing complex glue code. playwright-cucumber-ts-steps provides a pre-built library of robust steps for UI, API, and Authentication testing, running natively inside Playwright.
.feature files immediately.@smoke or @regression easily.npm install playwright-cucumber-ts-steps @playwright/test
or
yarn add playwright-cucumber-ts-steps @playwright/test
npx playwright install
👉 View Steps Documentation and examples.
Update playwright.config.ts to use the built-in reporting helper.
import { defineConfig } from "@playwright/test";
import { getReporters, setFixtureConfig } from "playwright-cucumber-ts-steps";
// Optional: Configure custom fixture directory and file names
setFixtureConfig({
fixturesDir: "fixtures", // Default: "fixtures"
selectorsFile: "selectors.json", // Custom selectors file name
textsFile: "texts.json", // Custom texts file name
valuesFile: "values.json", // Custom values file name
// ... other fixture files
});
export default defineConfig({
testDir: "./tests",
// Sets up HTML report + Console list automatically
reporter: getReporters({ on: ["html"] }),
use: {
// We handle screenshots manually in the runner,
// but this is good as a backup
screenshot: "only-on-failure",
},
});
Configurable Fixture Files:
fixturesDir - Base directory for all fixtures (default: "fixtures")selectorsFile - UI selectors fixture filetextsFile - Text content fixture filevaluesFile - Test values fixture fileoptionsFile - Dropdown options fixture fileendpointsFile - API endpoints fixture filefilesFile - File paths fixture filepathsFile - JSON paths fixture fileresponsesFile - API responses fixture filequeriesFile - Database queries fixture filecolumnsFile - Database columns fixture filetypesFile - Data types fixture filetitlesFile - Page titles fixture fileurlsFile - URLs fixture fileattributesFile - HTML attributes fixture filepromptsFile - Dialog prompts fixture fileCreate a file at tests/bdd.spec.ts. This is the entry point.
import { runTests } from "playwright-cucumber-ts-steps";
// Runs all feature files in the 'features' folder
runTests("features/*.feature");
Create features/login.feature:
Feature: User Authentication
@smoke
Scenario: Successful Login
Given I pw visit "[https://the-internet.herokuapp.com/login](https://the-internet.herokuapp.com/login)"
When I pw fill "#username" with "tomsmith"
And I pw fill "#password" with "SuperSecretPassword!"
And I pw click "button[type='submit']"
Then I pw expect "#flash" to contain text "You logged into a secure area!"
npx playwright test
We support a Friendly Syntax for filtering tests via the TAGS environment variable.
| Logic | Symbol | Example | Description |
|---|---|---|---|
| AND | , |
@login,@signup |
Run tests that have @login AND @signup. |
| MIX | , |
@a,@b, @c |
Run tests with (@a AND @b) OR just @c. |
Usage:
# Run only smoke tests
TAGS='@smoke' npx playwright test
OR
npx playwright test -g "@smoke"
# Run smoke tests that are also critical
TAGS='@smoke,@critical' npx playwright test
OR
npx playwright test -g "@smoke|@critical"
(On Windows PowerShell, use $env:TAGS="@smoke"; npx playwright test)
In your Test Runner (tests/bdd.spec.ts):
import { runTests } from "playwright-cucumber-ts-steps";
// OPTION 1: Run Everything
// runTests('features/*.feature');
// OPTION 2: Run only Smoke tests
runTests("features/*.feature", { tags: "@smoke" });
You can validate your backend directly without opening a browser, or mix it with UI tests.
Feature: User API
@api
Scenario: Create and Verify User
When I pw make a POST request to "[https://reqres.in/api/users](https://reqres.in/api/users)" with body '{"name": "Morpheus", "job": "Leader"}'
Then I pw expect the response status to be 201
And I pw expect the response property "name" to be "Morpheus"
Handling complex HTML elements is built-in.
Feature: File Upload and Iframes
Scenario: Upload Document inside Iframe
Given I pw visit "[https://example.com/upload](https://example.com/upload)"
# Switch context to the iframe
When I pw upload file "data/resume.pdf" to "#file-input" inside frame "#upload-iframe"
And I pw click "#submit-btn" inside frame "#upload-iframe"
Then I pw expect "div.success" inside frame "#upload-iframe" to be visible
Speed up your suite by 10x. Login once, save the cookies, and reuse them.
Step 1: Create a Setup Feature (features/setup.feature)
Feature: Setup
@setup
Scenario: Admin Login
Given I pw visit "/login"
When I pw fill "#user" with "admin"
And I pw fill "#pass" with "1234"
And I pw click "#login-btn"
And I pw expect "#dashboard" to be visible
# Saves session to ./auth/admin.json
And I pw save the browser state to "admin.json"
Step 2: Use in Daily Tests (features/admin.feature)
Feature: Admin Panel
Scenario: Check Reports
# Loads cookies instantly - No login UI needed!
Given I pw load the browser state from "admin.json"
When I pw visit "/admin/reports"
Then I pw expect "h1" to have text "Weekly Reports"
Fill out entire forms in a single step using a Data Table. You can type, click, check, or assert visibility in one go.
Scenario: Registration
When I pw fill the following "Registration" form data:
| #first-name | John |
| #last-name | Doe |
| #email | john@test.com |
| #newsletter | check |
| #submit-btn | click |
| .success | assert:visible |
Validate your backend directly. You can send payloads via Tables or JSON Files.
Scenario: Create User (Table)
When I pw make a POST request to "[https://reqres.in/api/users](https://reqres.in/api/users)" with data:
| name | Neo |
| job | The Chosen |
Then I pw expect the response status to be 201
And I pw expect the response property "name" to be "Neo"
Scenario: Create User (File)
# Reads from 'data/user.json' in your project root
When I pw make a POST request to "/api/users" with payload from "data/user.json"
Then I pw expect the response status to be 201
Simulate backend responses to test UI behavior without relying on real APIs.
Scenario: Mocking User Profile
# Intercept calls to /api/user/1 and return fake data
Given I pw mock the API endpoint "*/**/api/user/1" with body '{"name": "Mocked User"}'
# When the UI calls the API, it gets our fake data
When I pw visit "/profile"
Then I pw expect "#username-display" to have text "Mocked User"
You can validate database states by injecting your own DB driver into the runner.
1. In your bdd.spec.ts:
import { runTests } from "playwright-cucumber-ts-steps";
import pg from "pg"; // Your driver (pg, mysql, mongo, etc)
// wrapper function
const queryDb = async (query: string) => {
const client = new pg.Client(process.env.DB_URL);
await client.connect();
const res = await client.query(query);
await client.end();
return res.rows; // Must return an array of objects
};
runTests("features/*.feature", { dbQuery: queryDb });
2. In your Feature file:
Scenario: Create User
When I pw run the database query "INSERT INTO users (name) VALUES ('Bob')"
Then I pw expect the database to return 1 record
And I pw expect the first database record to contain:
| name | Bob |
| Step | Usage Example |
|---|---|
| Visit | I pw visit "https://google.com" |
| Click | I pw click "#submit-btn" |
| Force Click | I pw force click "#hidden-btn" |
| Double Click | I pw double click ".icon" |
| Fill Input | I pw fill "#email" with "user@test.com" |
| Press Key | I pw press "Enter" (or "Tab", "Escape") |
| Wait | I pw wait for 2000 milliseconds |
| Reload | I pw reload the page |
| Go Back | I pw go back |
| Step | Usage Example |
|---|---|
| Visibility | I pw expect "#modal" to be visible |
| Hidden | I pw expect "#loader" to be hidden |
| Exact Text | I pw expect "#header" to have text "Welcome" |
| Partial Text | I pw expect ".error" to contain text "Failed" |
| Input Value | I pw expect "#username" to have value "admin" |
| Exact URL | I pw expect the url to be "https://site.com/home" |
| Partial URL | I pw expect the url to contain "/dashboard" |
| Title | I pw expect the title to contain "Home Page" |
| Attribute | I pw expect "img" to have attribute "src" with value "logo.png" |
| Screenshot | I pw expect the page screenshot to match "home.png" |
| Step | Usage Example |
|---|---|
| Select (Dropdown) | I pw select option "Canada" from "#country" |
| Check Box | I pw check "#terms-checkbox" |
| Uncheck | I pw uncheck "#newsletter" |
| Upload File | I pw upload file "data.csv" to "#upload" |
| Handle Alert | I pw accept the next dialog |
| Frame Click | I pw click "#btn" inside frame "#payment-frame" |
| Step | Usage Example |
|---|---|
| GET | I pw make a GET request to "/api/users" |
| DELETE | I pw make a DELETE request to "/api/users/1" |
| POST | I pw make a POST request to "/api/login" with body '{"u":"1"}' |
| Status Check | I pw expect the response status to be 200 |
| JSON Check | I pw expect the response property "data.id" to be "99" |
Need a step that isn't included? You can easily register your own in your spec file.
// tests/bdd.spec.ts
import { runTests, Step } from "playwright-cucumber-ts-steps";
// 1. Define custom step
Step("I pw scroll to the bottom of the page", async (page) => {
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
});
// 2. Run tests
runTests("features/*.feature");
Then use it in your feature:
Scenario: Scroll Test
Given I pw visit "[https://infinite-scroll.com](https://infinite-scroll.com)"
When I pw scroll to the bottom of the page
When I pw click
When I pw click on element {string}
When I pw click on button {string}
When I pw click on link {string}
When I pw click on label {string}
When I pw click on text {string}
When I pw click on exact text {string}
When I pw click on selector ([^]+)
When I pw click all
When I pw double click
When I pw double click on text {string}
When I pw double click position {int} {int}
When I pw right click
When I pw right click on text {string}
When I pw right click position {int} {int}
When I pw click on ({int})(?:st|nd|rd|th) element ([^]+)
When I pw click on ({int})(?:st|nd|rd|th) selector ([^]+)
When I pw find element by selector {string}
When I pw find element by text {string}
When I pw find element by title {string}
When I pw find element by testid {string}
When I pw find element by role {string}
When I pw find element by placeholder text {string}
When I pw find element by label text {string}
When I pw find element by alt text {string}
When I pw find link by text {string}
When I pw find heading by text {string}
When I pw find element by name {string}
When I pw find elements by selector {string}
When I pw find headings by text {string}
When I pw find buttons by text {string}
When I pw get first element
When I pw get last element
When I pw get ({int})(?:st|nd|rd|th) element
When I pw get focused element
When I pw find input by ID {string}
When I pw find input by name {string}
When I pw find input by placeholder text {string}
When I pw find input by display value {string}
When I pw find textarea by label text {string}
When I pw store element text as {string}
When I pw fill the following {string} form data
When I pw fill the following {string} test form data
When I pw switch to frame {string}
When I pw find element {string} in frame {string}
When I pw switch to new tab
When I pw type {string}
When I pw type stored {string}
When I pw slowly type {string}
When I pw set value {string}
When I pw clear
When I pw press {string}
When I pw check
When I pw uncheck
When I pw check input
When I pw uncheck input
When I pw (check|uncheck) ({int})(?:st|nd|rd|th) selector ([^]+)
When I pw select option {string}
When I pw submit
When I pw select file {string}
When I pw upload file {string}
When I pw click {string}
When I pw force click {string}
When I pw fill {string} with {string}
When I pw press {string}
When I pw wait for {int} milliseconds
When I pw press key {string}
When I pw press key {string} on element
When I pw press keys {string}
When I pw press shortcut {string}
When I pw hold down key {string}
When I pw release key {string}
When I pw wait for {int} milliseconds
When I pw wait for {int} seconds
When I pw pause
When I pw debug
When I pw log {string}
When I pw focus
When I pw blur
When I pw set cookie {string} to {string}
When I pw clear all cookies
When I pw set local storage item {string} to {string}
When I pw get local storage item {string}
When I pw clear local storage
When I pw set session storage item {string} to {string}
When I pw clear session storage
When I pw tap
When I pw tap element {string}
When I pw tap coordinates x:{int} y:{int}
When I pw resize window to width {int} and height {int}
When I pw simulate device {string}
When I pw set geolocation to lat: {float} long: {float}
When I pw grant permission {string}
When I pw scroll {string} into view
When I pw scroll {string} to position x:{int} y:{int}
When I pw scroll to coordinates x:{int} y:{int}
When I pw scroll mouse window to position top:{int} left:{int}
When I pw scroll to {string}
When I pw hover over the element {string}
When I pw move mouse to coordinates {int}, {int}
When I pw hover on ({int})(?:st|nd|rd|th) element ([^]+)
When I pw hover on ({int})(?:st|nd|rd|th) selector ([^]+)
When I pw visit {string}
When I pw reload the page
When I pw go back
When I pw go forward
When I pw navigate to {string}
When I pw wait for network idle
When I pw wait for load state {string}
When I pw wait for element to be visible
When I pw wait for element to be hidden
When I pw wait for URL to contain {string}
When I pw expect the response status to be {int}
When I pw expect the response body to contain {string}
When I pw expect the response property {string} to be {string}
When I pw mock the API endpoint {string} with body {string}
When I pw mock the API endpoint {string} with response from {string}
When I pw mock the API endpoint {string} with status {int}
When I pw intercept URL ([^]+) and stub body:?
When I pw intercept URL {string} and stub body {string}
When I pw intercept URL {string}
When I pw make request to {string}
When I pw make a POST request to ([^]+) with JSON body:?
When I pw make a {word} request to {string}
When I pw make a GET request to {string}
When I pw make a DELETE request to {string}
When I pw make a POST request to {string} with data
When I pw make a POST request to {string} with payload from {string}
When I pw expect the url to contain {string}
When I pw expect the url to be {string}
When I pw expect the title to contain {string}
When I pw expect the title to be {string}
When I pw expect {string} to have text {string}
When I pw expect {string} to contain text {string}
When I pw expect {string} to have value {string}
When I pw expect {string} to have attribute {string} with value {string}
When I pw expect element to be visible
When I pw expect {string} to be visible
When I pw expect element to be hidden
When I pw expect element to be enabled
When I pw expect element to be disabled
When I pw expect element to have text {string}
When I pw expect element to contain text {string}
When I pw expect element to have value {string}
When I pw expect element to have attribute {string}
When I pw expect element to have attribute {string} with value {string}
When I pw expect the page screenshot to match {string}
When I pw expect the element screenshot to match {string}
When I pw save the browser state to {string}
When I pw load the browser state from {string}
When I pw run the database query {string}
When I pw expect the database to return {int} record(s)
When I pw expect the database to return no records
When I pw expect the first database record to contain
When I pw expect database row {int} to contain
When I pw expect all database records to contain
When I pw expect database column {string} to exist
When I pw expect database column {string} to contain {string}
When I pw expect database column {string} to be of type {string}
When I pw accept the next dialog
When I pw dismiss the next dialog
When I pw type {string} into the next prompt and accept
When I pw select option {string} from {string}
When I pw check {string}
When I pw uncheck {string}
When I pw upload file {string} to {string}
When I pw click {string} inside frame {string}
When I pw fill {string} inside frame {string} with {string}
When I pw expect {string} inside frame {string} to have text {string}
MIT © 2024