React app powered with Selenium.

In this tutorial, we will be creating a sample React application using create-react-app and automate it using Selenium WebDriver, covering varied test cases.

Balasubramani M
HackerNoon.com
Published in
6 min readJul 9, 2018

--

Selenium Icon.

Why selenium?

Selenium WebDriver provides a programming interface to create and execute test cases. It automates our development and every developer must now to write unit test cases for their work to manage their code better.

Prerequisites

  1. Node.js & NPM (NPM comes with Node.js, you don’t need to install it separately)
  2. Selenium WebDriver
  3. Chromedriver & Geckodriver
  4. Mocha
  5. Firefox and Chrome browsers.

Let’s code

Let’s straight away jump into development.

Create a project called “react-selenium” using create-react-app.

$ npx create-react-app react-selenium
$ cd react-selenium
$ npm start

Now, you have your app ready, running in the port 3000. You can access it via http://localhost:3000

We will install the above prerequisites in our app.

$ npm i selenium-webdriver chromedriver geckodriver --save
$ npm i mocha --save-dev

Now in your root directory, create a folder called test and inside of it, create a file called test.js. Refer the final source code for reference.

In test.js, add the following code in it.

/**
* Dependency Modules
*/
var assert = require("assert").strict;
var webdriver = require("selenium-webdriver");
require("geckodriver");
// Application Server
const serverUri = "http://localhost:3000/#";
const appTitle = "React Selenium App";
/**
* Config for Chrome browser
* @type {webdriver}
*/
var browser = new webdriver.Builder()
.usingServer()
.withCapabilities({ browserName: "chrome" })
.build();
/**
* Config for Firefox browser (Comment Chrome config when you intent to test in Firefox)
* @type {webdriver}
*/
/*
var browser = new webdriver.Builder()
.usingServer()
.withCapabilities({ browserName: "firefox" })
.build();
*/
/**
* Function to get the title and resolve it it promise.
* @return {[type]} [description]
*/
function logTitle() {
return new Promise((resolve, reject) => {
browser.getTitle().then(function(title) {
resolve(title);
});
});
}
/**
* Sample test case
* To check whether the given value is present in array.
*/
describe("Array", function() {
describe("#indexOf()", function() {
it("should return -1 when the value is not present", function() {
assert.equal([1, 2, 3].indexOf(4), -1);
});
});
});
describe("Home Page", function() {
/**
* Test case to load our application and check the title.
*/
it("Should load the home page and get title", function() {
return new Promise((resolve, reject) => {
browser
.get(serverUri)
.then(logTitle)
.then(title => {
assert.strictEqual(title, appTitle);
resolve();
})
.catch(err => reject(err));
});
});
/**
* Test case to check whether the given element is loaded.
*/
it("Should check whether the given element is loaded", function() {
return new Promise((resolve, reject) => {
browser
.findElement({ id: "sel-button" })
.then(elem => resolve())
.catch(err => reject(err));
});
});
/**
* End of test cases use.
* Closing the browser and exit.
*/
after(function() {
// End of test use this.
browser.quit();
});
});

Quite long right? I will explain part by part in it.

/**
* Dependency Modules
*/
var assert = require("assert").strict;
var webdriver = require("selenium-webdriver");
require("geckodriver");

Add these lines at the top, which are the required dependencies to automate our development. assert is the default Node.js library so no need to install it. Selenium-WebDriver is the base driver for selenium to run and geckodriver is essential to run our test cases in other browsers than chrome.

// Application Server
const serverUri = "http://localhost:3000/#";
const appTitle = "React Selenium App";

We are going to work on two test cases.

First, we are going to load our application using Selenium by providing the required URI, get our app title once our application loads and checking it with the given appTitle value.

Second, we are going to find an element in our application to check whether the given element is loaded, which we are going to add it later in this post.

Visit index.html file in the public folder and change the title value as React Selenium App.

/**
* Config for Chrome browser
* @type {webdriver}
*/
var browser = new webdriver.Builder()
.usingServer()
.withCapabilities({ browserName: "chrome" })
.build();
/**
* Config for Firefox browser (Comment Chrome config when you intent to test in Firefox)
* @type {webdriver}
*/
/*
var browser = new webdriver.Builder()
.usingServer()
.withCapabilities({ browserName: "firefox" })
.build();
*/

It’s time to configure selenium by providing proper inputs like in which browser the test cases should load, what are all the configurations needed etc.

Here first browser config value contains configuration for Chrome browsers and I have commented configurations for Firefox browsers. You can do vice-versa when you are ready to test in Firefox.

/**
* Function to get the title and resolve it it promise.
* @return {[type]} [description]
*/
function logTitle() {
return new Promise((resolve, reject) => {
browser.getTitle().then(function(title) {
resolve(title);
});
});
}

Sample function to get the title of the browser using Selenium-WebDriver inbuilt method called getTitle() and resolving it using Promise.

/**
* Sample test case
* To check whether the given value is present in array.
*/
describe("Array", function() {
describe("#indexOf()", function() {
it("should return -1 when the value is not present", function() {
assert.equal([1, 2, 3].indexOf(4), -1);
});
});
});

Just a sample test case to make you feel more comfortable. Here we are checking whether value 4 present in the given array [1, 2, 3]. In this case, it will return -1 since it is not present, which is equal to -1 (RHS). So the test case is passed. LHS = RHS.

/**
* Test case to load our application and check the title.
*/
it("Should load the home page and get title", function() {
return new Promise((resolve, reject) => {
browser
.get(serverUri)
.then(logTitle)
.then(title => {
assert.strictEqual(title, appTitle);
resolve();
})
.catch(err => reject(err));
});
});

In this test case, the string given in the it denotes the name of the test case.

We are returning the Promise object because Mocha handles promise objects efficiently and it will be easy to manage our test cases better.

After, we are first opening our app by providing the serverUri. After that, we are calling the logTitle function to get the title of our app and passing the title value to the next callback function.

Using assert.strictEqual method, we are comparing title(LHS) with appTitle(RHS).

Finally, we are resolving it. If those values don’t match, we are rejecting it.

/**
* Test case to check whether the given element is loaded.
*/
it("Should check whether the given element is loaded", function() {
return new Promise((resolve, reject) => {
browser
.findElement({ id: "sel-button" })
.then(elem => resolve())
.catch(err => reject(err));
});
});

For this second test case, let’s add a button in our App.js file and check whether the button is loaded.

Open App.js file and add the following code after <p> tag.

<button id="sel-button">Click me!</button>

browser.findElement (inbuilt Selenium-WebDriver method) find for the element using the given id sel-button in our app and we are resolving it when we find the element and rejecting it when we fail to find the element.

/**
* End of test cases use.
* Closing the browser and exit.
*/
after(function() {
// End of test use this.
browser.quit();
});

Finally, after the end of test cases, we are closing the browser and it’s instance.

Run the test-case

Now, we are going to run these test cases. Add the below line (command) in the script object in your package.json file.

"s-test": "mocha test"

It’s time to run. From your root directory, run the following command as follows.

$ npm run s-test

Now you can see your test cases are running in your browser automatically and it gets closed after the test cases are over.

Mocha Test Cases Result.

You have automated your development.

Thank you.

Final source code can be found here.

--

--