Automated testing with Selenium WebDriver and Node.js

Automated testing with Selenium WebDriver and Node.js

Source Code

Intro

Selenium is an automated open source and cross-platform testing tool. It can be used in all major browsers(Chrome, Firefox, Opera, IE, and Edge) using almost all major programming languages. Also, it can be integrated with various native testing tools and library. In this article, I will explain a test procedure in google search homepage with selenium web-driver and Node.js.

Flow

Here we run an automated test on https://www.google.com/ LOL

  1. First, we test if the landing page has an input box and a button to submit.

  2. Then we put a random name to the input box and hit submit. We will check if the search results appear.

All these activities will be taken care of by our selenium web-driver.

For the testing framework, we are using mocha, and we include chai assertion library with it.

Project Setup

**Clone or fork the repo for further changes**

Our project will follow the following structure.

    ├── ...
    │
    ├── lib                         # Helper methods
    │   ├── basePage.js             # Generic functionality for tests
    │   └── homePage.js             # Home page testing functionality
    │
    ├── test                        # Test suite
    │   └── homePage.test.js        # Testing in home page
    │
    ├── utils                       # Utility files for testing
    │   ├── fakeData.js             # Generating random keyword for searching
    │   └── locator.js              # HTML and CSS identifier for elements to test
    │
    ├── package.json                # Project dependency
    ├── ...

Your final package.json should look similar like this.

{
  "name": "googlesearch",
  "version": "1.0.0",
  "description": "Google home page automated test ",
  "main": "index.js",
  "scripts": {
    "test": "mocha test --reporter mochawesome --reporter-options autoOpen=true"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/bmshamsnahid/Automation-With-Selenium-And-Node.js.git"
  },
  "author": "B M Shams Nahid",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/bmshamsnahid/Automation-With-Selenium-And-Node.js/issues"
  },
  "homepage": "https://github.com/bmshamsnahid/Automation-With-Selenium-And-Node.js#readme",
  "devDependencies": {
    "chai": "^4.1.2",
    "chai-as-promised": "^7.1.1",
    "chromedriver": "^2.41.0",
    "faker": "^4.1.0",
    "mocha": "^5.2.0",
    "mochawesome": "^3.0.3",
    "selenium-webdriver": "^4.0.0-alpha.1"
  }
}

Utility Methods

We have 2 utility methods in out util directory.

  1. fakeData.js

  2. locator.js

In utils/fakeData.js, We generate the random name to search in the google.

const faker = require('faker');

module.exports = {
    nameKeyword: faker.name.findName()
};

In utils/locator.js we put the HTML elements selector to manipulate.

module.exports = {
    searchInputSelectorId: 'lst-ib',
    searchButtonSelectorName: 'btnK',
    resultConfirmationId: 'resultStats'
};

Here are the three selectors.

  1. Google search input box as “searchInputSelectorId”,

  2. Google search button key as “searchButtonSelectorName”

  3. No of search results found on the result page as “resultStats”

Helper Methods

We put our generic methods in lib/basePage.js

*Code reference Quit Driver Get Url Find Element Find By Id Fill Input*

const {Builder, By, until} = require('selenium-webdriver');

const chrome = require('selenium-webdriver/chrome');
let o = new chrome.Options();
// o.addArguments('start-fullscreen');
o.addArguments('disable-infobars');
// o.addArguments('headless'); // running test on visual chrome browser
o.setUserPreferences({ credential_enable_service: false });

var Page = function() {
    this.driver = new Builder()
        .setChromeOptions(o)
        .forBrowser('chrome')
        .build();

    // visit a webpage
    this.visit = async function(theUrl) {
        return await this.driver.get(theUrl);
    };

    // quit current session
    this.quit = async function() {
        return await this.driver.quit();
    };

    // wait and find a specific element with it's id
    this.findById = async function(id) {
        await this.driver.wait(until.elementLocated(By.id(id)), 15000, 'Looking for element');
        return await this.driver.findElement(By.id(id));
    };

    // wait and find a specific element with it's name
    this.findByName = async function(name) {
        await this.driver.wait(until.elementLocated(By.name(name)), 15000, 'Looking for element');
        return await this.driver.findElement(By.name(name));
    };

    // fill input web elements
    this.write = async function (el, txt) {
        return await el.sendKeys(txt);
    };
};

module.exports = Page;

For test purpose, page specific methods are put in the utils/homePage.js

let Page = require('./basePage');
const locator = require('../utils/locator');
const fake = require('../utils/fakeData');

const searchInputSelectorId = locator.searchInputSelectorId;
const searchButtonSelectorName = locator.searchButtonSelectorName;
const resultConfirmationSelectorId = locator.resultConfirmationId;

const fakeNameKeyword = fake.nameKeyword;

let searchInput, searchButton, resultStat;

Page.prototype.findInputAndButton = async function () {
    searchInput = await this.findById(searchInputSelectorId);
    searchButton = await this.findByName(searchButtonSelectorName);

    const result = await this.driver.wait(async function () {
        const searchButtonText = await searchButton.getAttribute('value');
        const searchInputEnableFlag = await searchInput.isEnabled();

        return {
            inputEnabled: searchInputEnableFlag,
            buttonText: searchButtonText
        }
    }, 5000);
    return result;
};

Page.prototype.submitKeywordAndGetResult = async function() {
    await this.findInputAndButton();
    await this.write(searchInput, fakeNameKeyword);
    await searchButton.click();
    resultStat = await this.findById(resultConfirmationSelectorId);
    return await this.driver.wait(async function () {
        return await resultStat.getText();
    }, 5000);
};

module.exports = Page;

We have two methods here.

The first method finds the button and input box. Check its availability.

The second method put a random name(grabbed from the faker.js) in the input box and confirm the search results found.

Test Suite

Time to create our first test suite in test/homePage.test.js

const { describe, it, after, before } = require('mocha');
const Page = require('../lib/homePage');

const chai = require('chai');
const expect = chai.expect;
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);

process.on('unhandledRejection', () => {});

(async function example() {
    try {
        describe ('Google search automated testing', async function () {
            this.timeout(50000);
            let driver, page;

            beforeEach (async () => {
                page = new Page();
                driver = page.driver;
                await page.visit('https://www.google.com/');
            });

            afterEach (async () => {
                await page.quit();
            });

            it ('find the input box and google search button', async () => {
                const result = await page.findInputAndButton();
                expect(result.inputEnabled).to.equal(true);
                expect(result.buttonText).to.include('Google');
            });

            it ('put keyword in search box and click search button', async () => {
                const result = await page.submitKeywordAndGetResult();
                expect(result.length).to.be.above(10);
            });
        });
    } catch (ex) {
        console.log (new Error(ex.message));
    } finally {

    }
})();

Here we are running two tests, one for checking the existing of the input box and search button.

Another for checking the search results, after we put our desired key in the search box and hit the search button.

Run Test

We are ready to perform our first test. Make sure in your package.json file, the test script is written properly. For confirmation, you can check my package.json file. I shared above of the post.

Run

npm test

Now the test will run and both of them should pass.

Tweak Configuration

In order to run the test in the headless browser, go to lib/basePage.js and uncomment the ‘headless’ option for chrome.

In case you want to use Firefox, IE, Edge or Opera browser check the documentation.

Conclusion

Stay tuned and if there is a confusing term or something, response below. I will replay ASAP.