Codementor Events

How to use Cucumber and Selenium WebDriver effectively for BDD test automation (part 2)

Published Jun 01, 2020Last updated Jun 14, 2020
How to use Cucumber and Selenium WebDriver effectively for BDD test automation (part 2)

This is in continuation of PART 1 where a basic project setup was discussed and the cucumber feature file for this tutorial was created. Our focus here will be the implementation of step-definitions.
So, the file structure should be modified to:

e2e
├── config.js
│   │
├── features
│   │
│   ├── app.feature
│   │
│   ├── step-definitions
│   │   ├── app.js
│   │
│   ├── common
│   │   ├── action.js
│   │   ├── browser.js
│   │   ├── selectors.js
│   │
│   ├── support
│   │   ├── world.js
│   │   ├── hooks.js

Update the files accordingly:
e2e/features/common/browser.js

const {By, until} = require('selenium-webdriver');
const {timeout} = require('../../config');

function browser(driver){
  function waitAndLocateByCSS(selector){
    return driver.wait(until.elementLocated(By.css(selector)), timeout);
  }
  
  function waitAndLocateByXpath(selector){
    return driver.wait(until.elementLocated(By.xpath(selector)), timeout);
  }

  return {
    waitAndLocateByCSS,
    waitAndLocateByXpath
  };
}

module.exports = browser;

e2e/features/common/selectors.js

module.exports = {
  'email input': 'input[name="identifier"]'
  'password input': 'input[name="password"]'
  'Sign in', '//a[contains(text(), "Sign in")]',
  'Create account', '//a[contains(text(), "Create")]',
  'Next': '//span[contains(text(), "Next")]'
};

e2e/features/common/action.js

const {baseURL, email, password} = require('../config');
const helper = require('./common/browser');
const selector = require('./common/selector');

const action = {
  navigateToPage: function() {
    return this.driver.get(baseURL);
  },
  enterInput: function(text, inputField) {
    const itemSelector = selector[inputField],
    const mapText = {
    	'<email>': email,
        '<password>': password
    };
    const value = mapText[text] || text;
    return helper(this.driver).waitAndLocateByCSS(itemSelector).sendKeys(value);
  },
  click: async function(identifier) {
  	const itemSelector = selector[identifier],
    await helper(this.driver).waitAndLocateByXpath(itemSelector).click();
  },
  confirmUserId: async function() {
    await helper(this.driver).waitAndLocateByXpath(`//a[contains(@aria-label, "${email}")]`);
  },
  confirmTextVisibility: async function(text) {
    await helper(this.driver).waitAndLocateByXpath(`//*[contains(text(), "${text}")]`);
  },
  confirmMultipleTextVisibility: async function(dataTable) {
  // convert cucumber dataTables to array of objects
    const arrayOfObjects = dataTable.hashes();
    const locateText = [];

    arrayOfObjects.forEach((value) => {
      const textArray = Object.values(value);
      const [text] = textArray;
      locateText.push(helper(this.driver).waitAndLocateByXpath(`//*[text()="${text}"]`));
    });

    await Promise.all(locateText);
  }
};

module.exports = action;

e2e/features/step-definitions/app.js

const {Given, When, Then} = require('cucumber');
const {
  navigateToPage,
    enterInput,
    click,
    confirmTextVisibility,
    confirmMultipleTextVisibility,
    confirmUserId
} = require('../common/action');

Given('A user visits mail.google.com', navigateToPage);

Then(/^the user should see the following .*$/, confirmMultipleTextVisibility);

When(/^the user clicks on '(.*)' .*$/, click);

When ('the user enters {string} into the {string} field', enterInput);

Then(/^the user should see '(.*)' .*$/, confirmTextVisibility);

Then('the user should see the Google Account used to sign in to the email', confirmUserId);

Part 3 (coming soon) will focus on how to write resilient BDD tests

Discover and read more posts from Marcus Chukwuoma
get started
post comments5Replies
Maylanie Mesnier 🦄
4 years ago

I love cucumber, was a bit lost thought about how to deal with selector in a clean and maintenable way… this solution could be nice. Thanks a lot !

Marcus Chukwuoma
4 years ago

You’re welcome

AnotherUsername
4 years ago

Hey Marcus,

Nice guide. However, several lines of code in the examples are incorrect. I.e. extra ‘,’ or missing semicolons etc.

I adapted this using the latest @cucumber/cucumber repo and all worked fine with a few tweaks. Look forward to part 3…

Jarukit Rungruang
4 years ago

Can you send me your project file? (adapt in @cucumber/cucumber repo) I need to learn for my educaion. Please tarosliced@gmail.com

Marcus Chukwuoma
3 years ago

I’m glad the article was helpful 😊

Show more replies