Automated testing with CucumberJS with Selenium Webdriver using JavaScript

I’m currently picking up something new at work. And I guess the title of the post gives it away. It’s not a brand new thing altogether, just something that I haven’t tried out before. And in one of the blogs I stumbled upon, there was a line that captured what I wanted to do in this post (and I guess in a lot of other previous posts too): helping me remember what I figure[d] out. Anyways, this is just a gist of the basic setup. Much of the learning is in the actual scripting, and most of it is when things don’t work as expected.

First things first: Setting up

  • Download and install Node from https://nodejs.org/en/download. This will also install the Node Package Manager (NPM).
  • Download the drivers into a folder in your local.
  • Update your environment variables to include the drivers into your PATH variable.
    • Add SELENIUM_DRIVERS as a system variable and specify the folder where you placed the drivers
    • Update the PATH system variable by appending “;%SELENIUM_DRIVERS%;”
  • We used a starter found here. Download the files from there, and that’ll give us stuff that I have no idea how to write from scratch at this point:
    • package.json
    • Gruntfile.js
    • features/support folder contains world.js, env.js and hooks.js
  • Install the needed dependencies.
    • Dependencies like CucumberJS, Chai, Selenium Webdriver, etc. are indicated in the package.json file.
    • Open the Command Prompt, then go to the folder where the starter files are placed. Run “npm install”.

Writing our Feature File and Step Definitions

Since we’re using CucumberJS, we’ll write up a feature file in Gherkin format. This means that scenarios that we’ll be testing for are written in a Given-When-Then format. Given includes the needed setup for the test. When refer to actions taken from the initial state (as setup in the Givens). And Then includes the expected outcomes that will be checked for.

For each Given, When and Then, corresponding code has to be written to actually perform the automated steps. These steps are stored in step definition files stored under features/step_definitions.

Feature: Searching for cucumbers
  As an internet user
  In order to find out more about cucumbers
  I want to be able to search for information about cucumbers

  Scenario: Google cucumber search
    Given I go to the Google website
    When I search Google for "cucumbers"
    Then I should see some results
'use strict';

var expect = require('chai').expect;

module.exports = function() {
  this.World = require('../support/world.js').World;

  this.Given('I go to the Google website', function (next) {
    this.browser.get('http://www.google.com').then(function () {
      next();
    });
  });

  this.When('I search Google for "$searchQuery"', function (searchQuery, next) {

    this.browser.findElement(this.webdriver.By.css('input[name="q"]')).sendKeys(searchQuery);
    this.browser.findElement(this.webdriver.By.css('input[name="q"]')).sendKeys(this.webdriver.Key.ENTER)
    .then(function () {
      next();
    });
  });

  this.Then('I should see some results', function (next) {
    this.waitFor('div.g', 10000);
    this.browser.findElements(this.webdriver.By.css('div.g')).then(function (elements) {
      expect(elements.length).to.not.equal(0);
      next();
    });
  });
};

Okay, actually writing our step definitions

To interact with the web site under test, we use Selenium Webdriver. While working on a POC, we had to look for elements within the page under test, and then interact with those elements by either triggering an action like clicking or sending keys or we also interact by extracting information about the element I found. For the checks in the Then steps, we use Chai to do the comparisons. For the POC at least, I pretty much managed to get by with simple scenarios using the items below.


//Finding Elements with Selenium Webdriver
//Find Element by ID
this.browser.findElement(this.webdriver.By.id('sp-search-input'))

//Find Element by CSS
this.browser.findElement(this.webdriver.By.css('#sp-search-input'))
this.browser.findElement(this.webdriver.By.css('.ui-chip'))
this.browser.findElement(this.webdriver.By.css('.ui-chip[data-val="hello"]'))

//Interacting with Elements with Selenium Webdriver
this.browser.findElement(this.webdriver.By.id('sp-search-input')).sendKeys(searchText+"\n");
this.browser.findElement(this.webdriver.By.id('sp-add-widget')).click();
this.browser.findElement(this.webdriver.By.css('.ui-chip>span')).getText();
//looks for element with class "ui-chip" and then looks for a <span> and gets the text in that <span>

this.browser.findElement(this.webdriver.By.id('sp-search-input')).getAttribute('placeholder');
//e.g., <input id="sp-search-input" placeholder="Add Search Tags" …>
//above will return "Add Search Tags"

this.browser.isElementPresent(this.webdriver.By.css('.ui-toggle.checked'));
//returns boolean value

//Comparisons using Chai
expect(actualText).to.equal(expectedText);
expect(textFound).to.contain(expectedString);
expect(toggleState).to.be.ok;

Running our scripts

Using the Command Prompt, go to your test project folder, then run “cucumber-js”. There’s also an option to run it with other options. I find the tags to be most helpful. What I do is I tag the scenarios that I’m working on in the feature file. The format of the tag is “@tagname” in the line before the scenario you are tagging.

cucumber-js --tags @dev               //tagged with @dev
cucumber-js --tags ~@dev              //NOT tagged with @dev
cucumber-js --tags @foo,@bar          //tagged with @foo OR bar
cucumber-js --tags @foo --tags @bar   //tagged with @foo AND bar

Well, that’s about it. Again, the learning really comes when you’re actually scripting. Sometimes, you just need to dive in knowing you don’t know everything, and hopefully you’ll figure it out as you go along.

Summary of references

Example, Starter – https://github.com/Matt-B/cucumber-js-selenium-webdriver-example
CSS Selectors – http://www.w3schools.com/cssref/css_selectors.asp
Chai – http://chaijs.com/api/bdd/
Selenium Webdriver – http://www.seleniumhq.org/docs/03_webdriver.jsp
CucumberJS – https://github.com/cucumber/cucumber-js
Gherkin – https://github.com/cucumber/cucumber/wiki/Gherkin
Cucumber – http://cukes.info
Cucumber tags – https://github.com/cucumber/cucumber/wiki/Tags
Blog post – http://www.tcias.co.uk/blog/2014/09/03/writing-our-first-functional-test/ (2014 Sep 3)
Blog post – http://transitioning.to/2012/01/cucumber-and-js-getting-started-with-cucumber-js/ (2012 Jan 27)

Advertisements

WTANZ: “Test automation series”

Since the seventh session, the WTANZ topics have all been geared towards test automation.

  • WTANZ07 (Jul 25) offered an introduction to watir. Here we tried to automate simple tasks like logging in, finding a forum and then posting a reply to it.
  • WTANZ08 (Aug 22) was sort of a continuation of the previous session. Here the mission was to find a bug and then write a failing test for it. This session also provided a mini refactoring lesson for me since I placed the task of calling a particular function and the actual test under just one function. In retrospect, (I think Marlena also pointed this out) this session would have been a good time to try out assertions.
  • WTANZ09 (Sep 19) was another session on watir. I missed this session but I did get to read a bit about it through Marlena’s blog post.
  • WTANZ10 (Oct 17) earlier today was an introduction to Cucumber and Gherkin. From what I understand, Cucumber is the tool that does the automated test execution, whereas Gherkin is the language used to define the tests and it’s the language that cucumber understands. With the use of gherkin, test scenarios can be described in the format Given-When-Then-. And being in plain English, the business analyst can then supposedly be requested to write the test scenarios that he expects. Gherkin reminded me of Fitnesse wherein non-programmers are said to be able to write test cases in wiki format. For both tools, I guess the technical part of the actual automation is obscured from the non-programmers allowing them to focus on the scenarios or inputs that they would like to test.

Links:

WTANZ07: Watir basics

For this Sunday’s weekend testing session, Oliver introduced the group to a web test automation tool called Watir which works with Ruby. I also found out that this session will be a precursor for yet another session for a test automation tool called Cucumber but the next session will be four weeks away though. I’m digressing. Anyways, as a prerequisite (supposedly), we were asked to install ruby and watir onto our workstations following instructions laid out in http://watir.com/installation/#win.

The session started off with Oliver walking us through with some basic commands, then afterwards he let us work on our own on a mission to use watir for posting a forum reply in weekendtesting.com.  I had some trouble at first. For one, when I worked with IE7, one of the commands (b.text.include? "<text>") just kept returning false. I’m guessing watir was still looking at the blank tab rather than at the tab where the test web page was launched. I then tried using Firefox instead but I was getting an error message on jssh even though I’ve just installed the plug-in as indicated in the watir installation site. I later realized that I had two versions of Firefox and the command Watir::Browser.new seemed to be opening the older one which didn’t have the plug-in installed. After getting that sorted out, it was pretty much smooth sailing. 🙂

Here’s a summary of commands I used in the session:

require "watir"

Watir::Browser.default = "firefox"

b = Watir::Browser.new
b.goto("http://weekendtesting.com")

# Find text
b.text.include? "Forum"

# Click links
b.link(:text, "Forum").click
b.link(:text, /Next Weekend/).click

# Log in
b.text_field(:id, "user_login").set "<username>"
b.text_field(:id, "user_pass").set "<password>"
b.button(:value, "Log In").click

# Post a reply for the WTANZ07 topic
# Would only work if the topic is still in the list of Ongoing Discussions
# Searching for "WTANZ session #07" didn't work (even thru manual approach)
b.link(:text, "Forum").click
b.link(:text, /WTANZ session.*07/).click
b.link(:text, "Reply").click
b.text_field(:name, "message").set("Test reply yada yada blah blah")
b.button(:value, "Submit").click

# Log out
b.link(:text, /Logout/).click

Right after the session, I found some more links on watir to check out later when I have time. :p