Skip to content

Playwright Reference

Playwright BDR Template (TypeScript Reference Implementation)

Section titled “Playwright BDR Template (TypeScript Reference Implementation)”

“Minimum Magic, Maximum Control” — The engineering standard for scaling test automation to 1000+ tests without Gherkin.

This repository is the Reference Implementation of the BDR Methodology using Playwright and TypeScript.

It demonstrates how to implement Behavior-Driven Living Requirements in code, generating beautiful reports without maintaining .feature files.

Terminal window
npm ci
npx playwright install
Terminal window
# Run the unified BDR cycle (Test + Report)
npm run tests
# Or run individual demo tests
npx playwright test tests/demonstration/demo.spec.ts
Terminal window
# Use the unified command for a complete cycle
npm run tests
# Or manually generate and open the report
npm run report

This template strictly follows the BDR responsibility layers:

DirectoryLayerDescription
tests/demonstration/Level 3 (Spec)The entry point. Pure business intent. Reads like a story.
tests/features/Level 3 (Spec)BDR feature demonstrations (Data-driven, inline flows, API).
src/flows/Level 2 (Domain)Business Logic. Creating users, adding items to cart. Reusable components.
src/pom/Level 1 (Page)Page Objects. Selectors and raw Playwright interactions.
src/bdr/CoreUtilities for Reporting, Tables, and Decorators.
docs/contracts/MetadataExamples of Consumer-Driven Contracts (CDC) for Rule #7.

Architectural Highlights (For Engineering Reviews)

Section titled “Architectural Highlights (For Engineering Reviews)”

If you are reviewing this repository for its technical depth, here are the core pieces that solve real-world enterprise automation challenges:

  • BDR Decorators: src/bdr/decorators.ts - A clean implementation of TypeScript Method Decorators for zero-boilerplate reporting.
  • Lazy PO Model: src/pom/LoginPage.ts - Implementation of “Lazy Getters” for Locators to prevent “Stale Element” exceptions.
  • Infrastructure Health Check (Rule #0): tests/setup/health.setup.ts - Automated environment availability check that runs before all tests to prevent false-positives.
  • Dependency Injection Fixtures: src/fixtures/index.ts - Level 3 fixture architecture where Business Flows receive Page Objects as dependencies.
  • Deterministic Data Seeding (Rule #3): src/fixtures/index.ts - Seeded Faker implementation that ensures test data is unique across runs but stable during retries.
  • Automatic Idempotency (Rule #6): src/api/Idempotency.ts - Automatically protects against duplicate data operations during network retries.
  • Contract Testing Reference (Rule #7): docs/contracts/user-profile.json - Example schema for Consumer-Driven Contracts (CDC).
  • Data Cleanup Strategy (Rule #8): Factories in src/factories/ now include _cleanup: true metadata for infrastructure-level data hygiene.

To get the most out of BDR’s deterministic architecture, follow these rules:

Every BDR step (Given, When, Then) accepts optional execution settings as the second argument:

await BDR.When('User buys product', { stepId: 'purchase-flow' }, async () => {
await cartPage.checkout();
});
  • stepId (string):
    • Stabilizes history tracking. By default, BDR uses the step name as a key. If you rename a step, its history resets. Providing a stepId ensures that analytics persist even after major refactoring.

The BDR Symbiosis: ESLint + Static Analysis

Section titled “The BDR Symbiosis: ESLint + Static Analysis”

BDR focuses on runtime reporting and intent. However, for full Enterprise-grade protection, BDR works in strict symbiosis with ESLint:

  1. Static Anti-Patterns (ESLint): Catches waitForTimeout, page.$, and forgotten await statements right in your IDE before code is committed.
  2. Runtime Awareness: BDR wraps your actions in semantic blocks, ensuring the report always reflects the business goal even if the tech stack underneath shifts.

Required ESLint Setup:

Terminal window
npm install -D eslint eslint-plugin-playwright @typescript-eslint/parser @typescript-eslint/eslint-plugin

Create eslint.config.mjs in your root directory:

import playwright from 'eslint-plugin-playwright';
import tsParser from '@typescript-eslint/parser';
export default [
playwright.configs['flat/recommended'],
{
files: ['tests/**/*.ts', 'src/**/*.ts'],
languageOptions: { parser: tsParser },
rules: {
'playwright/expect-expect': 'off',
'no-restricted-imports': [
'error',
{
paths: [
{
name: '@faker-js/faker',
message:
"Use the seeded 'faker' fixture from src/fixtures/index.ts to ensure deterministic tests.",
},
],
},
],
},
},
{
files: ['src/pom/**/*.ts'],
rules: {
// Rule #9: Stateless POM Enforcement
'no-restricted-syntax': [
'error',
{
selector: "PropertyDefinition:not([key.name='page'])",
message:
"POM must be stateless. Don't store data in properties. Use method arguments instead.",
},
],
},
},
{
files: ['src/flows/**/*.ts'],
rules: {
// Rule #10: BDR Flow Enforcement
'no-restricted-syntax': [
'error',
{
selector:
"MethodDefinition[kind='method'][accessibility!='private']:not(:has(Decorator[expression.callee.name='Step']))",
message: 'All public Flow methods must be decorated with @Step for BDR reporting.',
},
],
},
},
];

You can wrap setup code inside BDR steps within Playwright hooks to ensure consistent reporting even for background preparation:

test.beforeEach(async ({ page }) => {
await BDR.Given('Setup: Login via API', async () => {
await api.login();
await page.goto('/');
});
});

The @Step decorator supports smart interpolation:

  • {0}: Replaces with the first argument (index-based).
  • {}: Sequential replacement.
  • {0.username}: Deep-property access for objects (Lead Standard).

I’m currently open to QA Automation roles — remote, contract, or full-time.

dmitryAQA@outlook.com

Telegram: @DmitryMeAQA


This repository is for the TypeScript implementation.

If you are looking for Python, Java, or C# examples, please check the Community Implementations section in the main methodology repository.