Introduction:

In this Blog will learn How to create a BDD automation framework using Cucumber in JavaScript and Playwright.
The playwright is an open-source automation tool. Playwright offers several features that make it stand out are Multi-browser support, Automatic waiting Headless and headful mode, etc.
Cucumber is a popular open-source BDD(Behavior Driven Development) testing framework, Which helps build a framework that can be easily understood by both technical and non-technical stakeholders.

Prerequisite:

To get started with Cucumber BDD with playwright-js we need to have the following things installed.

1)VS Code: We will use VS Code as IDE to write our test cases, to get this you can visit ‘https://code.visualstudio.com/download’.

2)Node.js: It is a cross-platform JavaScript runtime environment that allows developers to run JavaScript code outside of a web browser.
To get Node.js you can visit: https://nodejs.org/en/download
To check Node.js is installed on your system you can use the command ‘node –version’ on CMD or VS Code Terminal.

3)Cucumber (Gherkin) Full Support Extention: This extension provides support for the Cucumber (Gherkin) language to VS Code.
To get the extension click on the extension icon on the left side panel of VS Code, search for the extension and install it.

Project setup:

Before starting with framework development we need to create a folder structure.

Create a folder structure with the following steps:
1) Create a folder as ‘Playwright-JS-Demo’,
2) In VS Code open the Playwright-JS-Demo folder
3) Install Playwright and Cucumber by executing the following commands in terminal
a. npm init playwright@latest

b.npm i @cucumber/cucumber
After execution of these commands, you can see package.json, node_modules, and playwright.config.js is created in the folder structure.

4) once you open the project, create a folder structure as below.

As our project structure is ready, we can start with the framework.

1. TestHooks.js:

  • Test Hooks mainly contain methods to execute Before and After every execution.
  • The Before hook gets executed before each Scenario in a cucumber test suite.
  • In this hook, a new Chrome browser instance is launched for every Test Case.
  • A new page is created in context with ‘await context.newPage()‘ and assigned to the global variable ‘page‘, which is accessible for any Test Case. This ensures that the browser page is available for each scenario in the test suite. 
  • Once execution is done After the method gets executed It closes the current browser instance.
const { Before, AfterAll } = require('@cucumber/cucumber')
const page = require('@playwright/test')
Before(async () => {
  let browser = await page.chromium.launch({ headless: false })
  global.browser = browser
  const context = await browser.newContext()
  global.page = await context.newPage()
})
AfterAll(async () => {
  await global. browser.close()
})

2. Login.feature:

  • With Cucumber-BDD we can write scenarios in understandable language.
    Here I have created a Scenario for OrangeHRM Login.
  • We can create a separate scenario for each functionality.
  • Every step in a Feature File describes the action we are going to perform on UI.
  • In the feature file, we can add specific tags for scenarios or complete feature file ex. @login, @smoke.
  • If you add a tag for a specific scenario then it will only execute the particular scenario. But if you add tags for the Feature It will execute all the Scenarios from the Feature File.
  • It will make test execution easy if you want to execute test cases for specific functionality.
Feature: Login Feature
@login
Scenario: Login to OrangeHRM
 When I Visit the OrangeHRM login page
 And I enter username
 And I enter Password
 And I click on Login button
Then I verify dashboard URL

3. LoginSteps.js:

Essentially, the purpose of the step file is to attach steps from the feature file to the page file, where actual implementation is available.

We use the “Given-When-Then” (BDD) format to write step definitions.
The required statement imports the necessary modules like:

  • Cucumber library that contains definitions for When Then etc.
  • A custom LoginPage module that likely contains functions for interaction with the login page.

The steps with ‘When’ are related to the user actions like navigation, clicking on the button, and filling in the information in input boxes, etc.
The steps with ‘Then’ are related to the verifications or Assertions, just like in this case I have verified if the Login is successful.

const { When, Then } = require('@cucumber/cucumber')
const { LoginPage } = require('../page/LoginPage')
let loginPage = new LoginPage()
When('I Visit the OrangeHRM login page', async () => {
    await loginPage.navigate()
})
When('I enter username', async () => {
    await loginPage.enterUsername()
})
When('I enter Password', async () => {
    await loginPage.enterPassword()
})

When('I click on Login button', async () => {
   await loginPage.clickOnLoginButton()
})
Then('I verify dashboard URL', async () => {
    await loginPage.verifyDashboardURL()
})

4. LoginPage.js:

The page file contains the actual implementation of the scenario, We also defined all the functions needed for test execution.
Additionally, the LoginPage class contains functions that interact with the login page elements, like navigation to the Login page, entering the username and password, clicking the login button, and verifying the dashboard URL. Moreover, the playwright provides different functions to handle the UI elements and pages.
For this test case I have used goto(), click(), fill() waitFor().

process.env.WEB_URL, process.env.WEB_USERNAME and process.env.WEB_PASSWORD are the variables we are accessing from the .env file. (The use of the .env file is explained below in point no 6).

To access the .env file I have imported const path = require(‘path’);

const { expect } = require('@playwright/test')
const path = require('path');
require('dotenv').config({
    path: path.join(__dirname, '../.env'),
});
class LoginPage {
    async navigate() {
        await global.page.goto(process.env.WEB_URL)
    }
    async enterUsername() {
        await global.page.locator('//input[@placeholder="Username"]').waitFor({ status: 'visible' })
        await global.page.locator('//input[@placeholder="Username"]').fill(process.env.WEB_USERNAME)
    }
    async enterPassword() {
        await global.page.locator('//input[@placeholder="Password"]').fill(process.env.WEB_PASSWORD)
    }
    async clickOnLoginButton() {
        await global.page.locator('//button[@type="submit"]').click()
    }
    async verifyDashboardURL() {
       expect(await global.page.url()).toEqual('https://opensource-demo.orangehrmlive.com/web/index.php/dashboard/index')
    }
}
module.exports = { LoginPage }

5. Cucumber.json:

In this file, we specify the paths of all the required files. It helps to identify files in the framework.
Whenever you create any new file in the framework, you have to add a path for that new file in this Cucumber.json file so that it can be accessible during the test case execution.

{
    "default":{
        "require": [
            "steps/*.js",
            "page/*.js",
          "Utility/*.js"
        }
    }
}

6. .env:

.env file is a Configuration file that contains environment variables. Using a .env file is a best practice for keeping sensitive information separate from the code. Moreover, for this framework, we have stored information like URL to navigate and username and password to Login into the OrangeHRM Web application.

headless= false
WEB_URL= 'https://opensource-demo.orangehrmlive.com/web/index.php/auth/login'
WEB_USERNAME = 'Admin'
WEB_PASSWORD = 'admin123'

To execute the test case and get the report you will need to add the following command in a script tag of the package.json file

"scripts": 
{
    "test": "npx cucumber-js --require ./steps/*.js --tags @login --publish
}

We are executing the ‘npx’ command to run the cucumber-js package which is a test framework for BDD.
1) –require ./steps/*.js specifies The step files from the specified path that should be loaded.
2)–tags @login specifies scenarios with @login tags are going to be executed.
You can add more than one tag if needed.

3)–publish flag specifies that test results should be published to the Cucumber Cloud which is a service for storing and analyzing test results.

To start execution you can execute the command ‘npm run test’ in the terminal.
Once execution is completed you can see the link for cucumber reports is available in the terminal. By clicking on this link you can see the execution report.

This is how the report looks when you click on the above URL

Now as we have the framework ready, I have added this framework to the following Git Repository.
https://github.com/spurqlabs/Playwright_JS_BDD_Framework

Conclusion:

In conclusion, the BDD automation framework using Cucumber in JavaScript and Playwright helps improve the quality and efficiency of their testing process.
This framework will help you to write test cases for any web application very efficiently, It also provides a great reusability of code.

Read more blogs here.

18