Dec 29

Cucumber-JVM – a BDD Zeitgeist about-turn?

As a long-term(ish) user of Java but a recent adopter (I hesitate to say convert) of Ruby and Cucumber, I’ve been aware of Cucumber-JVM — a rewrite of Cucumber in Java for the uninitiated — for some time now.

But first, some background. I reacquainted myself — and got more serious with — Java a couple of years ago (after allowing myself to get far too rusty with it after my degree finished). Getting certified re-taught me a lot of the fundamentals as well as properly uncovering the deep, dark depths of the language for the first time. At the time I was using Java with the most popular BDD framework at the time – JBehave.

With hindsight, JBehave was unwieldy, unfriendly and simply tried to do too much. I didn’t realise this at the time as verbosity and unwieldiness are often part-and-parcel of Java (and other similar languages e.g. C#). This isn’t a criticism of the language itself — it’s just how it is.

Eventually, I moved on to another company where I was exclusively using Ruby and Cucumber for the first time. Initially it was a struggle but now I fully appreciate just how powerful and flexible the language is and how strongly I identify with Ruby’s mantra and raison d’être.

Which brings us to the whole point of this post.

Ruby and Cucumber

What I love about Ruby and Cucumber is that the simplicity of each perfectly compliments the other.

There is no mandatory boilerplate.

There aren’t numerous ways to configure the execution.

It just works.

My personal transition from Java to Ruby has given me food for thought. In the same way that I learnt from my own journey, perhaps Java also can learn from the leanness of Cucumber?

Java vs. Ruby

I decided to put the idea into practise.

Today I looked at implementing a basic example from the ITV back-end test suite in Java and Cucumber-JVM. Take a look on my GitHub account for the complete example.

It’s difficult to directly compare the two implementations as they do differ very slightly in their aim and use of helper methods but you cannot deny how similar the two snippets look:

    @Given("^I request the (\\w+) Most Watched Feed for (\\w+)$")
    public void I_request_the_type_Most_Watched_Feed_for_platform(String type, String platform) throws Throwable {
        mercuryRequest = new MercuryRequest();
        response = mercuryRequest.requestMostWatchedFeed(type, platform);
    }

    @Then("^I get a successful (\\w+) response with the correct (\\w+)$")
    public void I_get_a_successful_type_response_with_the_correct_platform(String type, String platform) throws Throwable {
        String text;

        switch (RequestType.valueOf(type.toUpperCase())) {
            case JSON:
                JSONObject json = mercuryRequest.stringToJson(response);
                text = JsonPath.read(json, "$.Parameters.Platform");
                assertEquals(platform, text);
                break;
            case XML:
                Document xml = mercuryRequest.stringToXml(response);
                XPathFactory xpf = XPathFactory.newInstance();
                XPath xpath = xpf.newXPath();
                text = xpath.evaluate("//Params/Param[2]/Value", xml.getDocumentElement());
                assertEquals(platform, text);
                break;
        }
    }
Given /^I request the (\w+) (\w+) (.*) api$/ do |type, platform, uri|
  @uri = "#{EnvConfig['mercury_url']}/api/#{type}/#{platform}/#{uri}"
  @response = @mercury_api.get_response_from_url @uri
end

Then /^I get a successful (\w+) response with the correct (\w+)$/ do |type, platform|
  case type
    when 'xml'
      xml = @mercury_api.get_xml_from_response @response
      unless @mercury_api.value_exists_in_xml_node?(xml, "Value", platform)
        raise "could not find the correct platform value: #{platform} in the response for uri: #@uri"
      end
    when 'json'
      json = @mercury_api.parse_json_response @response
      @mercury_api.find_value_in_hash("Platform", json).should == platform
  end
end

Looking Ahead – The Killer Questions

I’m not trying to draw any concrete conclusions but I think the next year or two could be an interesting time for BDD development with regard to Java and Ruby (and possibly other languages).

  • Will Java learn from Cucumber (and Ruby’s) example in terms of verbosity, clarity and maintainability?
  • Will the emergence of Cucumber-JVM together with the open-source movement encourage developers/testers to focus more strongly on a common language — particularly in light of Ruby’s comparatively poor performance for enterprise applications versus Java?
  • Will Ruby truly be able to throw off the performance shackles it wears with the release of Ruby 2.0 and become more than a niche startup, prototyping and test automation language?
Mar 31

Highlighting Elements in Selenium WebDriver

I’ve decided to write smaller blog entries for a while as I have such a huge backlog of things I’d like to put on here.

So today I’d like to introduce how to highlight elements in the browser using Selenium WebDriver (Java).

Rather than simply explaining how it’s done and giving some code snippets, I’ve also included the functionality in a small Java project that uses my favourite test runner – JBehave. This way, you can build the project yourself, see a “real-life” example and tinker with it.

I’d like to thank Iain for his blog post on highlighting elements.

Getting Started

First of all – if you are building an automation framework at your organisation – it’s a good idea to route all calls to the WebDriver API through a bespoke common library. I’ve discussed at length why I think this is a good idea but here’s a few more reasons:

  • It helps enforce standards inside your organisation. Flexibility is a good thing but do you really want people using your framework to select elements using findElement.By.partialLinkText rather than an Xpath or CSS Selector? A restrictive approach does not necessarily stifle innovation.
  • It can vastly reduce code.
  • It increases code readability.
  • Particularly difficult things to automate (e.g. hover and click, drag and drop) can be used again and again by different project teams.
  • A solid common library makes tests more stable as it is harder to introduce silly errors into your code.
  • It is much much easier to update common methods with the latest API additions and best practise.

We need two methods to achieve our aim.

First, we need to create a setAttribute() method similar to the WebDriver getAttribute() method. The WebDriver API does not have this built in because it is specifically designed to mimic the user’s interactions with the browser – and the user cannot change attribute values (through “normal” use).

The definition of this method depends on your setup. You need to cast your WebDriver instance to JavaScriptExecutor for it to work.

If you use JBehave like I do then WebDriverPage casts the WebDriver instance to JavaScriptExecutor for you already. Like so:

    public Object executeScript(String s, Object... args) {
        makeNonLazy();
        return ((JavascriptExecutor) webDriver()).executeScript(s, args);
    }

So we can call executeScript() directly in our method without worrying about casting it first.

  /**
   * Set an attribute in the HTML of a page.
   * 
   * @param element
   *          The WebElement to modify
   * @param attributeName
   *          The attribute to modify
   * @param value
   *          The value to set
   */
  private void setAttribute(WebElement element, String attributeName, String value) {
    executeScript("arguments[0].setAttribute(arguments[1], arguments[2])", element, attributeName, value);
  }

If you don’t use JBehave then this should do the trick:

  /**
   * Set an attribute in the HTML of a page.
   * 
   * @param driver 
   *          The WebDriver you are using
   * @param element
   *          The WebElement to modify
   * @param attributeName
   *          The attribute to modify
   * @param value
   *          The value to set
   */
  private void setAttribute(WebDriver driver, WebElement element, String attributeName, String value) {
    JavascriptExecutor js = (JavascriptExecutor) driver;
    js.executeScript("arguments[0].setAttribute(arguments[1], arguments[2])", element, attributeName, value);
  }

Now we just need to create a highlight method that uses setAttribute().

  /**
   * Highlight an element in the UI.
   * 
   * @param element
   *          The WebElement to highlight
   */
  private void highlight(WebElement element) {
    final int wait = 75;
    String originalStyle = element.getAttribute("style");
    try {
      setAttribute(element, "style",
          "color: yellow; border: 5px solid yellow; background-color: black;");
      Thread.sleep(wait);
      setAttribute(element, "style",
          "color: black; border: 5px solid black; background-color: yellow;");
      Thread.sleep(wait);
      setAttribute(element, "style",
          "color: yellow; border: 5px solid yellow; background-color: black;");
      Thread.sleep(wait);
      setAttribute(element, "style",
          "color: black; border: 5px solid black; background-color: yellow;");
      Thread.sleep(wait);
      setAttribute(element, "style", originalStyle);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

It’s not the prettiest code but the effect is pretty cool.

You could parametrise the colours if you wanted to. I also feel that the wait time is enough to clearly notice what’s going on without slowing tests down.

Using it in your code.

OK so let’s see the code in action.

As I mentioned earlier, I built a small Java project for this which is available at my public GitHub repository. You just need Maven and Firefox installed.

Simply follow the running instructions to see the highlight method in action while searching for things on Amazon.

Feb 06

Building Powerful and Reliable WebDriver Automated Tests without Learning the API

I’d like to take a quick break from the technical side of things in order to introduce this particular topic which I strongly believe in.

One of the most common complaints surrounding automation relates to learning the API (in this case Selenium WebDriver). Less confident programmers (usually testers) will usually confuse the host language (e.g. Java) and the automation API (Selenium WebDriver) and fail to understand where one begins and the other ends. Similarly – from my experience – experienced Java developers will view the API with suspicion and complain that “they don’t have enough time” to learn it or need some sort of training in order to do so.

There is some truth in the latter statement. I’ve found it quite difficult at times to find really solid advice and examples with regard to Selenium WebDriver (one of the reasons why I started this blog). So let’s put this statement out there:

It is possible (and so easy!) to write your tests in such a way that the user does not need to know ANYTHING about Selenium WebDriver and how it works or why.

One of the things I love about WebDriver is that it so fast and powerful. But as Peter Parker would say, with great power comes great responsibility…or something like that at least. WebDriver is utterly unforgiving if you don’t respect it. By this, I am of course talking about implicit/explicit waits – or rather WebDriver falling over in a heap if it can’t act upon some element that you haven’t told it to wait for.

So what do I propose?

A simple solution really. I assume you’re currently using the Page Object pattern. If not, take a step back and learn this as it’s a fundamental technique which contributes to solid tests. Let’s have a look at a fictional example:

public class HomePage extends WebDriverPage {

private static final String SEARCH_FIELD = "//*[@id='search']";
private static final String SUBMIT = "//*[@id='submit']";

    public HomePage(WebDriverProvider driverProvider) {
        super(driverProvider);
    }


    public void go() {
        get("http://www.bensnape.com");
    }


    public void search(String content) {
        findElement(By.xpath(SEARCH_FIELD)).sendKeys(content);
        findElement(By.xpath(SUBMIT)).click();
    }
}

Let’s assume this page object represents www.bensnape.com and allows you to navigate to the page – go() and do a search using search(). Now the code for this looks fine, right? But what if in our automated test we navigated to this page via a link and not via the blocking WebDriver get() before trying to call the search() method. What happens? WebDriver falls over because the page hasn’t finished loading.

The typical reaction would be to put some sort of wait (implicit or explicit) at the start of the search() method. However, this is bad practise for the following reasons:

  1. It would be very difficult to anticipate how your page objects might be used in further iterations of your project, or longer term by other projects in related areas.
  2. Putting waits everywhere would clutter your code and hamper readability.

The solution is to introduce a class or set of classes to extend all your page objects from which contain easy-to-use, re-usable and efficient helper methods. Let’s implement that class now:

public class CommonMethods extends WebDriverPage {

    public CommonMethods(WebDriverProvider driverProvider) {
        super(driverProvider);
    }

    public void clickLink(String xpath) {
        WebElement link = new WebDriverWait(webDriver(), 10).until(ExpectedConditions.elementToBeClickable(By.xpath(xpath)));
		
	link.click();
    }
	
    public void fillField(String xpath, String content) {
	WebElement field = new WebDriverWait(webDriver(), wait).until(ExpectedConditions.visibilityOfElementLocated(By.xpath(xpath)));
		
	field.sendKeys(content);
    }
	
}

And so we extend that common class to wrap all our WebDriver API calls with targeted and explicit waits related only to the element we are interacting with in clean, easy to understand methods of our own choosing – namely clickLink() and fillField().

public class HomePage extends CommonMethods {

private static final String SEARCH_FIELD = "//*[@id='search']";
private static final String SUBMIT = "//*[@id='submit']";

    public HomePage(WebDriverProvider driverProvider) {
        super(driverProvider);
    }

    public void go() {
        get("http://www.bensnape.com");
    }

    public void search(String content) {
        fillField(SEARCH_FIELD, content);
        clickLink(SUBMIT);
    }
}

I introduced this simple but powerful concept at Yell. It enables less experienced programmers to easily perform complicated API calls without needing to learn the WebDriver API at all. By simply abstracting the technical implementation inside easy-to-understand business language – e.g. clickLink, fillField, selectFromDropdown etc. code readability, durability and stability vastly improve, along with testers’ output and confidence levels.

Dec 18

Using the Advanced User Interactions API in Selenium 2 (Webdriver)

I was recently automating an internal sales tool used at Yell when I came across this particular problem. I needed to hover over the navigation bar and then click on one of the options that drops down (see Play.com for a working example).

This requires use of Selenium’s Advanced User Interactions API – which was new to me – but this was only the start of my problems as we will discover.

The scenario

We have some HTML that looks like this:

Note: this probably isn’t syntactically correct but you can see that the navigation bar is an unordered list of unordered lists. The dropdown menu is initially hidden from view (display:none).

<div id="navBar">
 <ul>
  <li>
   <a href="http://customer"> My Customers </a>
    <ul id="dropDownMenu" style="display:none;">
     <li>
      <a id="searchCustomer" href="http://searchcustomer">Search</a>
     </li>
…

Once you hover over the main link, the HTML transforms, exposing the hidden links (display:block):

<div id="navBar">
 <ul>
  <li>
   <a href="http://customer"> My Customers </a>;
    <ul id="dropDownMenu" style="display:block;">
     <li>
      <a id="searchCustomer" href="http://searchcustomer">Search</a>
     </li>
…

Start creating a solution

I wanted to solve this problem and at the same time create a helper method for the framework that was flexible, powerful and reusable. The method declaration would look something like this:

public void clickHiddenMenuBarItem(String menuXpath, String menuItemXpath, long timeout)

In the interest of best practice, I try to ensure that all tests make frequent use of helper methods which typically include targeted explicit waits. That way tests are much more readable with the complexity hidden away and it also reduces the likelihood of testers making those simple but frustrating programming errors.

So clickHiddenMenuBarItem as the name implies, would click on a hidden menu bar link which must be revealed by hovering over the menu link first.

So let’s build two explicit waits for the main link and the hidden link (note: the latter is hidden from the user and Selenium’s direct interactions but you can still verify its existence).

NB: due to my setup (I use Spring to run my code), the Selenium commands are missing the prefix driver.. Similarly, you would need to use driver instead of webDriver() for your WebDriver instance (or whatever you named it).

  public void clickHiddenMenuBarItem(final String menuXpath, final String menuItemXpath, long timeout) {

    // Explicit wait for the menu
    WebElement menu = (new WebDriverWait(webDriver(), timeout)).until(new ExpectedCondition() {
      public WebElement apply(WebDriver d) {
        return d.findElement(By.xpath(menuXpath));
      }
    });

    // Explicit wait for the menu option
    WebElement menuOption = (new WebDriverWait(webDriver(), timeout)).until(new ExpectedCondition() {
      public WebElement apply(WebDriver d) {
        return d.findElement(By.xpath(menuItemXpath));
      }
    });
  }

These are your standard explicit waits as defined by the documentation. As each wait makes use of an inner class we must declare the xpath arguments as final.

You might want to extend the piece of code above to check the visibility of the elements, as this helped me to diagnose problems later on:

System.out.println("Menu displayed: " + menu.isDisplayed());
System.out.println("Menu option displayed: " + menuOption.isDisplayed());

This should return true and false respectively.

Introducing the Advanced User Interactions API

Now that piece of code is working fine, we can move onto making use of the Advanced User Interactions API. This is where I got a little stuck and where isDisplayed() came in handy.

According to the documentation you should be able to do something like this:

// Configure the action
Actions builder = new Actions(webDriver());

builder.moveToElement(menu)
.click(menuOption);

// Get the action
Action clickMenuOption = builder.build();

// Perform the action
clickMenuOption.perform();

This compiled fine for me, ran without errors but nothing seemed to happen. The mouse didn’t hover on the menu, even when I stepped through it using the debugger. So I tried a variant on this, which is available from the same link above:

// Configure the action
Actions builder = new Actions(webDriver());

// Get and build the action
Action clickMenuOption = builder.moveToElement(menu)
.click(menuOption)
.build();

// Perform the action
clickMenuOption.perform();

Again nothing was happening. After some searching around I found that someone had had a related problem. Essentially, you need to perform the click() outside of the action chain. So here’s the code:

Actions builder = new Actions(webDriver());

builder.moveToElement(menu).perform();

menuOption.click();

I tried this…and it almost worked. The mouse certainly hovered on the link but the code fell over as there is a tiny (<500ms) delay where the menu option becomes 'un-hidden'. To achieve this diagnosis I put the earlier isDisplayed() code along with a small static wait in-between builder.moveToElement(menu).perform() and menuOption.click()

Now I knew what the problem was I needed to find a neat and tidy way of structuring this wait.

Using the ExpectedConditions class

This question of a neat and tidy wait had me stumped for some time. I knew that you could use an explicit wait whilst waiting for the existence of an element – but I had already proved that in my previous code. I needed a way of somehow combining the visibility of an element with a wait (and importantly, elegantly).

An implicit wait for 1 or 2 seconds worked – manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS) but it is bad practise to combine explicit and implicit waits. Besides, the implicit wait would live for the life of the WebDriver instance which is unacceptable. I almost resorted to Thread.sleep(500) to achieve the desired effect. Finally, I found the Selenium ExpectedConditions class. I needed to know when, after hovering on the menu, the menu option became visible and clickable – and elementToBeClickable was a perfect match. So simply put that condition as part of a WebDriverWait statement like so:

Actions builder = new Actions(webDriver());
builder.moveToElement(menu).perform(); // hover

new WebDriverWait(webDriver(), 10).until(ExpectedConditions.elementToBeClickable(By.xpath(menuItemXpath)));
menuOption.click();

Test the solution

This code worked for my application but when I tested it on Play.com – which has a very similar navigation bar – it didn’t work. I had a hunch that my code was failing due to being “too slow” in identifying when the hidden element was clickable and acting upon it.

There are two possible solutions:

  1. Use a different WebDriverWait constructor to specify the element polling interval (measured in milliseconds).
  2. new WebDriverWait(webDriver(), 10, 50).until(ExpectedConditions.elementToBeClickable(By.xpath(menuItemXpath)));
    
  3. Use a FluentWait which works similarly to WebDriverWait (which in fact extends FluentWait) but gives you a little more flexibility.
  4. new FluentWait(webDriver())
    .withTimeout(timeout, TimeUnit.SECONDS)
    .pollingEvery(50, TimeUnit.MILLISECONDS)
    .ignoring(NoSuchElementException.class)
    .until(ExpectedConditions.elementToBeClickable(By.xpath(menuItemXpath)));
    

Whilst the FluentWait offers more flexibility – in particular the ability to choose the WebDriver exception to ignore – in this case I opted for the more finely-tuned WebDriverWait as it achieved what I needed in one line of code.

Full code

  /**
   * Click a hidden menu bar item (AKA hover and click) using a configurable wait.
   * 
   * @param menuXpath
   *          The xpath of the main menu parent item.
   * @param menuItemXpath
   *          The xpath of the hidden/drop-down menu item.
   * @param timeout
   *          The wait timeout (10 is recommended).
   */
  public void clickHiddenMenuBarItem(final String menuXpath, final String menuItemXpath, long timeout) {

    // Explicit wait for up to 10 seconds for the menu
    WebElement menu = (new WebDriverWait(webDriver(), timeout)).until(new ExpectedCondition<WebElement>() {
      public WebElement apply(WebDriver d) {
        return d.findElement(By.xpath(menuXpath));
      }
    });

    // Explicit wait for up to 10 seconds for the menu option
    WebElement menuOption = (new WebDriverWait(webDriver(), timeout)).until(new ExpectedCondition<WebElement>() {
      public WebElement apply(WebDriver d) {
        return d.findElement(By.xpath(menuItemXpath));
      }
    });

    /*
     * Use the Advanced User Interactions API to perform a hover and click.
     * A WebDriverWait utilising elementToBeClickable() is required between the hover and click.
     */
    Actions builder = new Actions(webDriver());
    builder.moveToElement(menu).perform();  // hover

    new WebDriverWait(webDriver(), 10, 50).until(ExpectedConditions.elementToBeClickable(By.xpath(menuItemXpath)));

    menuOption.click();
  }