Giter Site home page Giter Site logo

playwright-bdd's Introduction

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.