Use when configuring Playwright BDD projects, setting up defineBddConfig(), configuring feature and step file paths, and integrating with Playwright config.
Expert knowledge of Playwright BDD configuration, project setup, and integration with Playwright's testing framework for behavior-driven development.
Playwright BDD enables running Gherkin-syntax BDD tests with Playwright Test. Configuration is done through the playwright.config.ts file using the defineBddConfig() function, which generates Playwright test files from your .feature files.
# Install playwright-bdd
pnpm add -D playwright-bdd
# Or with specific Playwright version
pnpm add -D playwright-bdd @playwright/test
// playwright.config.ts
import { defineConfig } from "@playwright/test";
import { defineBddConfig } from "playwright-bdd";
const testDir = defineBddConfig({
features: "features/**/*.feature",
steps: "steps/**/*.ts",
});
export default defineConfig({
testDir,
});
The defineBddConfig() function returns a path to the generated test directory. By default, this is .features-gen in your project root:
const testDir = defineBddConfig({
features: "features/**/*.feature",
steps: "steps/**/*.ts",
});
// testDir = '.features-gen/features'
const testDir = defineBddConfig({
features: "features/**/*.feature",
steps: "steps/**/*.ts",
outputDir: ".generated-tests", // Custom output directory
});
Configure where to find feature files:
defineBddConfig({
// Single pattern
features: "features/**/*.feature",
// Multiple patterns
features: ["features/**/*.feature", "specs/**/*.feature"],
// Exclude patterns
features: {
include: "features/**/*.feature",
exclude: "features/**/skip-*.feature",
},
});
Configure step definition locations:
defineBddConfig({
// Single pattern
steps: "steps/**/*.ts",
// Multiple patterns
steps: ["steps/**/*.ts", "features/**/*.steps.ts"],
// Mixed JavaScript and TypeScript
steps: ["steps/**/*.ts", "steps/**/*.js"],
});
When using custom fixtures, import the test instance:
defineBddConfig({
features: "features/**/*.feature",
steps: "steps/**/*.ts",
importTestFrom: "steps/fixtures.ts", // Path to your custom test instance
});
The fixtures file should export the test instance:
// steps/fixtures.ts
import { test as base, createBdd } from "playwright-bdd";
export const test = base.extend<{
todoPage: TodoPage;
}>({
todoPage: async ({ page }, use) => {
const todoPage = new TodoPage(page);
await use(todoPage);
},
});
export const { Given, When, Then } = createBdd(test);
Configure different feature sets for different test projects:
import { defineConfig } from "@playwright/test";
import { defineBddConfig } from "playwright-bdd";
const coreTestDir = defineBddConfig({
features: "features/core/**/*.feature",
steps: "steps/core/**/*.ts",
outputDir: ".features-gen/core",
});
const adminTestDir = defineBddConfig({
features: "features/admin/**/*.feature",
steps: "steps/admin/**/*.ts",
outputDir: ".features-gen/admin",
});
export default defineConfig({
projects: [
{
name: "core",
testDir: coreTestDir,
},
{
name: "admin",
testDir: adminTestDir,
},
],
});
Configure the Gherkin language:
defineBddConfig({
features: "features/**/*.feature",
steps: "steps/**/*.ts",
language: "de", // German keywords (Gegeben, Wenn, Dann)
});
Supported languages follow the Gherkin specification:
en (English - default)de (German)fr (French)es (Spanish)ru (Russian)Configure quote style in generated test files:
defineBddConfig({
features: "features/**/*.feature",
steps: "steps/**/*.ts",
quotes: "single", // 'single' | 'double' | 'backtick'
});
Enable verbose output during generation:
defineBddConfig({
features: "features/**/*.feature",
steps: "steps/**/*.ts",
verbose: true,
});
// playwright.config.ts
import { defineConfig, devices } from "@playwright/test";
import { defineBddConfig } from "playwright-bdd";
const testDir = defineBddConfig({
features: "features/**/*.feature",
steps: "steps/**/*.ts",
importTestFrom: "steps/fixtures.ts",
});
export default defineConfig({
testDir,
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: [["html"], ["json", { outputFile: "test-results/results.json" }]],
use: {
baseURL: "http://localhost:3000",
trace: "on-first-retry",
screenshot: "only-on-failure",
},
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
{
name: "firefox",
use: { ...devices["Desktop Firefox"] },
},
{
name: "webkit",
use: { ...devices["Desktop Safari"] },
},
],
webServer: {
command: "pnpm run start",
url: "http://localhost:3000",
reuseExistingServer: !process.env.CI,
},
});
import { defineConfig } from "@playwright/test";
import { defineBddConfig } from "playwright-bdd";
const isCI = !!process.env.CI;
const testDir = defineBddConfig({
features: "features/**/*.feature",
steps: "steps/**/*.ts",
verbose: !isCI,
});
export default defineConfig({
testDir,
timeout: isCI ? 60000 : 30000,
retries: isCI ? 2 : 0,
workers: isCI ? 4 : undefined,
});
# Generate test files from features
npx bddgen
# Run Playwright tests
npx playwright test
# Or combine both
npx bddgen && npx playwright test
For development, regenerate on file changes:
# Watch feature and step files
npx bddgen --watch
# In another terminal, run tests
npx playwright test --watch
Export all step definitions for documentation:
npx bddgen export
Recommended project structure:
project/
├── playwright.config.ts
├── features/
│ ├── auth/
│ │ ├── login.feature
│ │ └── logout.feature
│ └── products/
│ └── catalog.feature
├── steps/
│ ├── auth/
│ │ ├── login.steps.ts
│ │ └── logout.steps.ts
│ ├── products/
│ │ └── catalog.steps.ts
│ └── fixtures.ts
└── .features-gen/ # Generated (gitignore this)
└── features/
├── auth/
│ ├── login.feature.spec.js
│ └── logout.feature.spec.js
└── products/
└── catalog.feature.spec.js
Add to .gitignore:
# Playwright BDD generated files
.features-gen/
// packages/e2e/playwright.config.ts
import { defineConfig } from "@playwright/test";
import { defineBddConfig } from "playwright-bdd";
const testDir = defineBddConfig({
features: "features/**/*.feature",
steps: "steps/**/*.ts",
importTestFrom: "steps/fixtures.ts",
});
export default defineConfig({
testDir,
use: {
baseURL: process.env.BASE_URL || "http://localhost:3000",
},
});
import { defineConfig } from "@playwright/test";
import { defineBddConfig } from "playwright-bdd";
const testDir = defineBddConfig({
features: "features/components/**/*.feature",
steps: "steps/components/**/*.ts",
});
export default defineConfig({
testDir,
use: {
ctPort: 3100,
},
});
import { defineConfig } from "@playwright/test";
import { defineBddConfig } from "playwright-bdd";
const testDir = defineBddConfig({
features: "features/api/**/*.feature",
steps: "steps/api/**/*.ts",
});
export default defineConfig({
testDir,
use: {
baseURL: "https://api.example.com",
},
});
If steps are not being matched:
steps confignpx bddgen export to see all registered stepsIf imports fail in generated files:
importTestFrom path is correcttest and step functionsIf bddgen fails:
verbose: true for detailsbddgen before tests in CI