Skip to content

BDD Testing with Playwright runner and CucumberJS

Notifications You must be signed in to change notification settings

ron-myers/playwright-bdd

 
 

Repository files navigation

playwright-bdd

lint test npm version

This package allows to run CucumberJS BDD tests with Playwright test runner.

Inspired by issue in Playwright repo microsoft/playwright#11975

Contents

Why Playwright runner

Both Playwright and Cucumber have their own test runners. You can use Cucumber runner with Playwright included as a library. Alternative way (provided by this package) is to convert BDD scenarios into Playwright tests and run them using Playwright runner. It gives the following benefits:

How it works

There are 2 phases:

Phase 1: Generate Playwright tests from feature files

CLI command bddgen reads Cucumber config and converts features into Playwright test files in .features-gen directory

Example of generated test

From

Feature: Playwright site

    Scenario: Check title
        Given I open url "https://playwright.dev"
        When I click link "Get started"
        Then I see in title "Playwright"

To

import { test } from 'playwright-bdd';

test.describe('Playwright site', () => {

  test('Check title', async ({ Given, When, Then }) => {
    await Given('I open url "https://playwright.dev"');
    await When('I click link "Get started"');
    await Then('I see in title "Playwright"');
  });

});    

Phase 2: Run generated test files with Playwright runner

Playwright runner takes generated test files and runs them as usual. For each test playwright-bdd creates isolated Cucumber World with injected Playwright fixtures (page, browser, etc). It allows to write step definitions using Playwright API:

Example of step definition
import { expect } from '@playwright/test';
import { Given, When, Then } from '@cucumber/cucumber';
import { World } from 'playwright-bdd';

Given('I open url {string}', async function (this: World, url: string) {
  await this.page.goto(url);
});

When('I click link {string}', async function (this: World, name: string) {
  await this.page.getByRole('link', { name }).click();
});

Then('I see in title {string}', async function (this: World, text: string) {
  await expect(this.page).toHaveTitle(new RegExp(text));
});  

Run BDD tests in one command:

npx bddgen && npx playwright test

Installation

Install from npm:

npm i -D playwright-bdd

This package uses @playwright/test and @cucumber/cucumber as peer dependencies, so you may need to install them as well:

npm i -D @playwright/test @cucumber/cucumber

After installing Playwright you may need to install browsers:

npx playwright install

Usage

  1. Create Cucumber config file cucumber.cjs:

    module.exports = {
      default: {
        paths: [ 'features/**/*.feature' ],       
        require: [ 'features/steps/**/*.{ts,js}' ],
        // uncomment if using TypeScript
        // requireModule: ['ts-node/register'],
        publishQuiet: true,
      },
    };

    Or in ESM format cucumber.mjs:

    export default {
      paths: [ 'features/**/*.feature' ], 
      import: [ 'features/steps/**/*.{ts,js}' ],
      // uncomment if using TypeScript
      // requireModule: ['ts-node/register'],
      publishQuiet: true,
    };
  2. Create Playwright config file playwright.config.ts. Set testDir pointing to .features-gen directory. That directory does not exist yet but will be created during tests generation:

    import { defineConfig } from '@playwright/test';
    
    export default defineConfig({
      testDir: '.features-gen', // <- generated BDD tests
      projects: [{ name: 'e2e' }],
    });
  3. Create feature descriptions in features/*.feature files:

    Feature: Playwright site
    
        Scenario: Check title
            Given I open url "https://playwright.dev"
            When I click link "Get started"
            Then I see in title "Playwright"
  4. Create step definitions in features/steps/*.{ts,js} files. Use World from playwright-bdd:

    import { expect } from '@playwright/test';
    import { Given, When, Then } from '@cucumber/cucumber';
    import { World } from 'playwright-bdd';
    
    Given('I open url {string}', async function (this: World, url: string) {
      await this.page.goto(url);
    });
    
    When('I click link {string}', async function (this: World, name: string) {
      await this.page.getByRole('link', { name }).click();
    });
    
    Then('I see in title {string}', async function (this: World, keyword: string) {
      await expect(this.page).toHaveTitle(new RegExp(keyword));
    });
  5. Run command to generate and execute tests:

    npx bddgen && npx playwright test
    

    Output:

    Running 1 test using 1 worker
    1 passed (2.0s)
    
    To open last HTML report run:
    
    npx playwright show-report
    

World

Playwright-bdd extends Cucumber World with Playwright built-in fixtures and testInfo. Just use this.page or this.testInfo in step definitions:

import { Given, When, Then } from '@cucumber/cucumber';

Given('I open url {string}', async function (url) {
  await this.page.goto(url);
});

In TypeScript you should import World from playwright-bdd for propper typing:

import { Given, When, Then } from '@cucumber/cucumber';
import { World } from 'playwright-bdd';

Given('I open url {string}', async function (this: World, url: string) {
  await this.page.goto(url);
});

Check out all available props of World.

Custom World

To use Custom World you should inherit it from playwright-bdd World and pass to Cucumber's setWorldConstructor:

import { setWorldConstructor } from '@cucumber/cucumber';
import { World, WorldOptions } from 'playwright-bdd';

export class CustomWorld extends World {
  myBaseUrl: string;
  constructor(options: WorldOptions) {
    super(options);
    this.myBaseUrl = 'https://playwright.dev';
  }

  async init() {
    await this.page.goto(this.myBaseUrl);
  }
}

setWorldConstructor(CustomWorld);

Perform asynchronous setup and teardown before each test with init() / destroy() methods.

Examples

There several working examples depending on your project setup (ESM/CJS and TS/JS):

Debugging

You can debug tests as usual with --debug flag:

npx bddgen && npx playwright test --debug

VS Code Integration

Limitations

Currently there are some limitations:

  • Cucumber tags not supported yet (wip, #8)
  • Cucumber hooks do not run. (use Playwright hooks instead?)

Changelog

2.1.0

  • Support Gherkin i18n #13

2.0.0

  • Support "Rule" keyword #7
  • Generate test files close to Gherkin document structure #10

1.3.0

  • Print parsing errors to the console while generating #2

1.2.0

  • Initial public release

Feedback

Feel free to share your feedback in issues.

License

MIT

About

BDD Testing with Playwright runner and CucumberJS

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 75.8%
  • Gherkin 12.3%
  • JavaScript 8.5%
  • Shell 3.4%