Manage and automatically select needed WebDriver in Java 8 Selenium project

Last Updated on by

Post summary: Example code how to efficiently manage and automatically select needed local WebDriver using Java 8 method reference used as lambda expression.

Code examples in current post can be found in GitHub selenium-samples-java/design-patterns repository.

Java 8 features

In this example lambda expression and method reference Java 8 features are used. More in Java 8 features can be found in Java 8 features – Lambda expressions, Interface changes, Stream API, DateTime API post.

Functional interface

Before explaining lambda it is needed to understand the idea of functional interface as they are leveraged for use with lambda expressions. Functional interface is interface that has only one abstract method that is to be implemented. Functional interface may or may not have default or static methods (again new Java 8 feature). Although not mandatory good practice is to annotate functional interface with @FunctionalInterface.

Lambda expressions

There is not such term in Java, but you can think of lambda expression as anonymous method. Lambda expression is piece of code that provides inline implementation of a functional interface, eliminating the need of using anonymous classes. Lambda expressions facilitate functional programming and ease development by reducing the amount of code needed.

Method reference

Sometimes when using lambda expression all you do is call a method by name. Method reference provides easy way to call the method making code more readable.

Managing WebDriver

Proposed solution of managing WebDriver has enumeration called Browser and class called WebDriverFactory. Another important thing is web drivers should be placed in folder with name webdrivers and named with special pattern.

Browser enum

Code is shown bellow:

package com.automationrhapsody.designpatterns;

import java.util.Arrays;
import java.util.function.Supplier;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;

public enum Browser {
	FIREFOX("gecko", FirefoxDriver::new),
	CHROME("chrome", ChromeDriver::new),
	IE("ie", InternetExplorerDriver::new);

	private String name;
	private Supplier<WebDriver> driverSupplier;

	Browser(String name, Supplier<WebDriver> driverSupplier) {
		this.name = name;
		this.driverSupplier = driverSupplier;
	}

	public String getName() {
		return name;
	}

	public WebDriver getDriver() {
		return driverSupplier.get();
	}

	public static Browser fromString(String value) {
		for (Browser browser : values()) {
			if (value != null && value.toLowerCase().equals(browser.getName())) {
				return browser;
			}
		}
		System.out.println("Invalid driver name passed as 'browser' property. "
			+ "One of: " + Arrays.toString(values()) + " is expected.");
		return FIREFOX;
	}
}

Enumeration’s constructor has Supplier functional interface as parameter. When constructor is called method reference FirefoxDriver::new is called as lambda expression which purpose is to instantiate new Firefox driver. If only lambda expression is used is would be: () -> new FirefoxDriver(). Notice that method reference is much shorter and easy to read. getDriver() method invokes Supplier’s get() method which is implemented by the lambda expression, so lambda expression is executed hence instantiating new web driver. With this approach Firefox web dirver object is created only when getDriver() method is called.

WebDriverFactory

Code is:

package com.automationrhapsody.designpatterns;

import java.io.File;

import org.openqa.selenium.WebDriver;

class WebDriverFactory {

	private static final String WEB_DRIVER_FOLDER = "webdrivers";

		public static WebDriver createWebDriver() {
		Browser browser = Browser.fromString(System.getProperty("browser"));
		String arch = System.getProperty("os.arch").contains("64") ? "64" : "32";
		String os = System.getProperty("os.name").toLowerCase().contains("win") 
				? "win.exe" : "linux";
		String driverFileName = browser.getName() + "driver-" + arch + "-" + os;
		String driverFilePath = driversFolder(new File("").getAbsolutePath());
		System.setProperty("webdriver." + browser.getName() + ".driver", 
				driverFilePath + driverFileName);
		return browser.getDriver();
	}

	private static String driversFolder(String path) {
		File file = new File(path);
		for (String item : file.list()) {
			if (WEB_DRIVER_FOLDER.equals(item)) {
				return file.getAbsolutePath() + "/" + WEB_DRIVER_FOLDER + "/";
			}
		}
		return driversFolder(file.getParent());
	}
}

This code recursively searches for folder named webdrivers in the project. This is done because when you have multi-module project running from IDE and from Maven has different root folder and finding web drivers is not possible from both simultaneously. Once folder is found then proper web driver is selected based on OS and architecture. Code reads browser system property which can be passed from outside hence making selection of web driver easy to configure. Important part is to have web drivers with special naming convention.

Web drivers naming convention

In order code above to work web drivers should be place in webdrivers folder in the project and their names should match the pattern: {DIVER_NAME}-{ARCHITECTURE}-{OS}, e.g. geckodriver-64-win.exe for Windows 64 bit and geckodriver-64-linux for Linux 64 bit.

Conclusion

Proposed solution is very elegant way to manage your web drivers and select proper one just by passing -Dbrowser={BROWSER} Java system property.

Read more...

Complete guide how to use design patterns in automation

Last Updated on by

Post summary: Complete code example of how design patterns can be used in real life test automation.

With series of posts I’ve described 5 design patterns that each automation test engineer should know and use. I’ve started with brief description of the patterns. Then I’ve explained in details with code snippets following patterns: Page objects, Facade, Factory, Singleton, Null object. Code examples are located in GitHub for C# and Java.

Overview

This post is intended to bond all together in a complete guide how to do write better automation code. Generally automation project consists of two parts. Automation framework project and tests project. Current guide is intended to describe how to build your automation testing framework. How to structure your tests is different topic. Remember once having correctly designed framework then tests will be much more clean, maintainable and easy to write. To keep post shorter some of the code that is not essential for representing the idea is removed. Whole code is in GitHub.

Page objects

Everything start by defining proper page objects. There is no fixed recipe for this. It all depends on the structure of application under test. General rule is that repeating elements (header, footer, menu, widget, etc) are extracted as separate objects. The whole idea is to have one element defined in only one place (stay DRY)! Bellow is our HomePage object. What you can do generally is make search and clear search terms. Note that clearing is done with jQuery code. This is because of a bug I’ve described with workaround in Selenium WebDriver cannot click UTF-8 icons post.

using OpenQA.Selenium;

namespace AutomationRhapsody.DesignPatterns
{
	class HomePageObject
	{
		private WebDriverFacade webDriver;
		public HomePageObject(WebDriverFacade webDriver)
		{
			this.webDriver = webDriver;
		}

		private IWebElement SearchField
		{
			get { return webDriver.FindElement(By.Id("search")); }
		}

		public void SearchFor(string text)
		{
			SearchField.SendKeys(text);
		}

		public void ClearSearch()
		{
			webDriver.ExecuteJavaScript("$('span.cancel').click()");
		}
	}
}

WebDriver factory

WebDriver factory will be responsible for instantiating the WebDriver based on condition which browser we want to run our tests with.

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.IE;

namespace AutomationRhapsody.DesignPatterns
{
	public class WebDriverFactory
	{
		public IWebDriver CreateInstance(Browsers browser)
		{
			if (Browsers.Chrome == browser)
			{
				return new ChromeDriver();
			}
			else if (Browsers.IE == browser)
			{
				return new InternetExplorerDriver();
			}
			else
			{
				return new FirefoxDriver();
			}
		}
	}
}

Constructor take an argument browser type. Browser type is defined as enumeration. This is very important. Avoid passing back and forth strings. Always stick to enums or special purpose classes. This will save you time investigating bugs in your automation.

public enum Browsers
{
	Chrome, IE, Firefox
}

NullWebElement

This is null object pattern and implements IWebElement. There is a NULL property that is used to compare is given element is not found or no.

using OpenQA.Selenium;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;

namespace AutomationRhapsody.DesignPatterns
{
	public class NullWebElement : IWebElement
	{
		private const string nullWebElement = "NullWebElement";
		public bool Displayed { get { return false; } }
		public bool Enabled { get { return false; } }
		public Point Location { get { return new Point(0, 0); } }
		public bool Selected { get { return false; } }
		public Size Size { get { return new Size(0, 0); } }
		public string TagName { get { return nullWebElement; } }
		public string Text { get { return nullWebElement; } }
		public void Clear() { }
		public void Click() { }
		public string GetAttribute(string attributeName) { return nullWebElement; }
		public string GetCssValue(string propertyName) { return nullWebElement; }
		public void SendKeys(string text) { }
		public void Submit() { }
		public IWebElement FindElement(By by) { return this; }
		public ReadOnlyCollection<IWebElement> FindElements(By by)
		{
			return new ReadOnlyCollection<IWebElement>(new List<IWebElement>());
		}

		private NullWebElement() { }

		private static NullWebElement instance;
		public static NullWebElement NULL
		{
			get
			{
				if (instance == null)
				{
					instance = new NullWebElement();
				}
				return instance;
			}
		}
	}
}

WebDriver facade

WebDriver facade main responsibility is to define custom behaviour on elements location. This gives you centralised control over elements location. Constructor takes browser type and uses the factory to create WebDriver instance which is used internally in the facade. FindElement method defines explicit wait. If element is not found then NullWebElement which is actually implementation of Null object pattern. The idea is to safely locate elements with try/catch and then just use them skipping checks for null.

using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using System;
using System.Collections.ObjectModel;

namespace AutomationRhapsody.DesignPatterns
{
	public class WebDriverFacade
	{
		private IWebDriver webDriver = null;
		private TimeSpan waitForElement = TimeSpan.FromSeconds(5);

		public WebDriverFacade(Browsers browser)
		{
			WebDriverFactory factory = new WebDriverFactory();
			webDriver = factory.CreateInstance(browser);
		}

		public void Start(string url)
		{
			webDriver.Url = url;
			webDriver.Navigate();
		}

		public void Stop()
		{
			webDriver.Quit();
		}

		public object ExecuteJavaScript(string script)
		{
			return ((IJavaScriptExecutor)webDriver).
				ExecuteScript("return " + script);
		}

		public IWebElement FindElement(By by)
		{
			try
			{
				WebDriverWait wait = new WebDriverWait(webDriver, waitForElement);
				return wait.Until(ExpectedConditions.ElementIsVisible(by));
			}
			catch
			{
				return NullWebElement.NULL;
			}
		}
	}
}

Tests

As I mention initially this post is about using efficiently design patterns in your framework automation project. Tests design are not being discussed here. Once you have designed the framework one simple test (without asserts) that makes search will look like code bellow.

Browsers browser = Browsers.Chrome;
WebDriverFacade webDriver = new WebDriverFacade(browser);
webDriver.Start("http://automationrhapsody.com/examples/utf8icons.html");

HomePageObject homePage = new HomePageObject(webDriver);
homePage.ClearSearch();
homePage.SearchFor("automation");

webDriver.Stop();

Conclusion

Design patterns are enabling you to write maintainable code. They increase value of your code. As shown in this series of posts they are not so complicated and you can easily adopt them in your automation. Most important is design patterns increase your value as a professional. So make the time to learn them!

Read more...

Selenium WebDriver cannot click UTF-8 icons

Last Updated on by

Post summary: Selenium WebDriver is not able to click UTF-8 icons. Solution is to use jQuery code.

In given example there is simple search form. Search value is cleared by “X” icon. This seems pretty forward case to be automated with Selenium WebDriver. It just seems! Element is properly located but when Selenium tries to click it an ElementNotVisibleException is thrown.

UTF-8 icon

When you inspect the code you can notice element is an empty SPAN. It has UTF-8 icon displayed over it by CSS “content” property. With this approach it is very easy to visualise very easy vast amount of interesting icons without being proficient in image editing.

Debug

I’ve setup very simple Selenium project for Visual Studio 2013 in my GitHub repository. On debug element can be located, but its width=0 so Selenium treats it as Displayed=false. This seems a good candidate for Selenium bug.

// Locate element
IWebElement element = webDriver.FindElement(By.CssSelector("span.cancel"));
// Debug info
bool isDisplayed = element.Displayed; // false
int width = element.Size.Width; // 0
int heigth = element.Size.Height; // 17

Solve it

Problem solved with execution of jQuery that will do the actual click of the element:

// jQuery workaround of the click
((IJavaScriptExecutor)webDriver).
	ExecuteScript("$('span.cancel').click()");

If jQuery is not available then try to do the click with function of JavaScript library used by the application you are automating. If none is used they you can just use DOM JavaScript call:

((IJavaScriptExecutor)webDriver).
	ExecuteScript("document.getElementsByClassName('cancel')[0].click();");

Bonus

There is one more interesting thing about jQuery. You can execute jQuery with some specific selector logic and this will return same IWebElement if you have located it with WebDriver.

// Locate element with jQuery
element = (IWebElement)((IJavaScriptExecutor)webDriver).
	ExecuteScript("return $('span.cancel')[0]");

One small detail – [0] is needed in the end of jQuery code otherwise a jQuery object is returned and Selenium is not able to cast it to IWebElement. And ofcourse element is yet not clickable. I’m just giving an alternative way of locating elements if Selenium way gets too complicated.

Conclusion

jQuery can be used inside Selenium WebDriver for tasks which are impossible to be done otherwise or are too hard and not worth wasting time on it. jQuery can be quite helpful in your automation. So it is worth improving your skill set with it. Remember, the essence of automation is about saving your company time and money, not wasting them on insignificant tasks.

Read more...

Efficient waiting for Ajax call data loading with Selenium WebDriver

Last Updated on by

Post summary: This post is about implementing an efficient mechanism for Selenium WebDriver wait for elements by execution of jQuery code.

Automating single page application with Selenium WebDriver could be sometimes a tricky task. You can get into the trap of timing issues. Although you set explicit waits you still can try to use element that is not yet loaded by the Ajax call. Remember Thread.Sleep() is never an option! You can use very tiny sleeps (100-200ms) in order to wait for initiation of given process, but never use sleep to wait for the end of the process.

Implement Selenium wrapper (Facade)

I good approach I like is to implement your own FindElement method which is basically a wrapper for Selenium’s methods (Facade pattern). With this approach you are hiding unneeded Selenium functionality and have centralised control over location of elements and explicit waits. Locate behaviour of your entire framework is controlled in just one method.

private static TimeSpan waitForElement = TimeSpan.FromSeconds(10);

public static IWebElement FindElement(By by)
{
	try
	{
		WaitForReady();
		WebDriverWait wait = new WebDriverWait(webDriver, waitForElement);
		return wait.Until(ExpectedConditions.ElementIsVisible(by));
	}
	catch
	{
		return null;
	}
}

Code above is C# one and is implementation of explicit wait with WebDriverWait class from OpenQA.Selenium.Support.UI. You can see an unknown (so far) method WaitForReady(). Note that ElementIsVisible is used instead of ElementExists because element might be on page but yet not ready to work with.

Wait for Ajax call to finish

Initially WaitForReady() was supposed to check that Ajax has finished loading by using jQuery.active property. This is in case jQuery is used in the application under test. If this property is 0 then there are no active Ajax request to server.

private static void WaitForReady()
{
	WebDriverWait wait = new WebDriverWait(webDriver, waitForElement);
	wait.Until(driver => (bool)((IJavaScriptExecutor)driver).
			ExecuteScript("return jQuery.active == 0"));
}

Wait for Ajax call to finish and data to load

You can realise that sometimes it is not enough to wait for Ajax to finish rather than to wait for data to be rendered. There is fancy loader in my application under which is a DIV shown when some action is being performed. If there is one on your application then you’d better wait not only for Ajax to finish, but to loader to hide.

private static void WaitForReady()
{
	WebDriverWait wait = new WebDriverWait(webDriver, waitForElement);
	wait.Until(driver =>
	{
		bool isAjaxFinished = (bool)((IJavaScriptExecutor)driver).
			ExecuteScript("return jQuery.active == 0");
		try
		{
			driver.FindElement(By.ClassName("spinner"));
			return false;
		}
		catch
		{
			return isAjaxFinished;
		}
	});
}

If “spinner” location gives exception then loader is not present and we can stop waiting. Good!

Improve the wait for data load

What about performance? When putting a timer the result was ~300ms for each Selenium search for loader. Not so good… Is 300ms long? Sure not, but taking into consideration this is called every time an element is located then this could make a huge difference in test execution times.

Why not making the same check for hidden loader, but this time with a JavaScript call to browser? I’m familiar with jQuery, then why not.

private static void WaitForReady()
{
	WebDriverWait wait = new WebDriverWait(webDriver, waitForElement);
	wait.Until(driver =>
	{
		bool isAjaxFinished = (bool)((IJavaScriptExecutor)driver).
			ExecuteScript("return jQuery.active == 0");
		bool isLoaderHidden = (bool)((IJavaScriptExecutor)driver).
			ExecuteScript("return $('.spinner').is(':visible') == false");
		return isAjaxFinished & isLoaderHidden;
	});
}

Conclusion

Same logic to check that element with class=”spinner” is not visible on page but this time at a cost of ~30ms. I like it much better this way!

Read more...

Automating SignalR applications with Selenium WebDriver

Last Updated on by

Post summary: This post is about an “No response from server for url” issue during automation of web application using SignalR with Selenium WebDriver. Issue was resolved by configuring application to connect to server through WebSocket protocol.

I had to automate with Selenium WebDriver (version 2.43) a single page web application which was build with SignalR. First thing to do when you start an automation is to automate a smoke test scenario. So did I. It run fine on Internet Explorer (version 11) and Chrome (version 37). I was happy and confident I’m going to finish this project on time. The happy face was dramatically changed when I run the suite on Firefox (version 33). The driver timed out with “No response from server for url” issue. I searched the net for similar problems with no luck. I couldn’t find an end-to-end solution on issues with SignalR automation so I prepared this post.

About SignalR

ASP.NET SignalR is a library for building “real-time” applications that enables server to push events to client instead on relying client to request data from server. Once application is started SignalR client tries to connect to server with transport protocols in order shown in the list: WebSocket, Server-sent events, Forever Frame (IE only) and finally Ajax long polling.

My application was forced to connect to server with Long Polling transport (later on I discovered this was caused by a bug in application’s connection logic). Client (browser) opens connection to server. Server keeps this connection open for relatively long time (2 minutes in my case). Seems like this open connection is confusing Selenium and it doesn’t actually know when browser is ready. “Unstable” page loading strategy did not worked out:

FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("webdriver.load.strategy", "unstable");
WebDriver driver = new FirefoxDriver(profile);

The only solution to make Selenium working with SignalR in all three browsers was to make application under test working with WebSocket transport protocol.

It is also beneficial for application itself to work with WebSockets. There are several SignalR prerequisites in order to use it with WebSockets: IIS 8 or IIS 8 Express with enabled WebSockets. In order to get enabled Web Sockets are installed additionally to IIS as a Windows feature.

Read more...