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


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 !
You’re welcome
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…
Can you send me your project file? (adapt in @cucumber/cucumber repo) I need to learn for my educaion. Please tarosliced@gmail.com
I’m glad the article was helpful 😊