Monthly Archives: January 2015

Selenium WebDriver cannot click UTF-8 icons

Last Updated on by

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

In given example, there is a simple search form. Search value is cleared by “X” icon. This seems pretty forward case to be automated with Selenium WebDriver. It just seems! The 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 a UTF-8 icon displayed over it by CSS “content” property. With this approach, it is very easy to visualize vast amount of interesting icons without being proficient in image editing.

Debug

I’ve set up very simple Selenium project for Visual Studio 2013 in my GitHub repository. On debug, the 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 the 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 a 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 the 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 at the end of jQuery code otherwise a jQuery object is returned and Selenium is not able to cast it to IWebElement. And of course, the 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 to 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 an element that is not yet loaded by the Ajax call. Remember Thread.Sleep() is never an option! You can use very tiny sleep (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 design pattern). With this approach, you are hiding unneeded Selenium functionality and have centralized control over locating 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 the 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 the 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 realize 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 the 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 the 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 make the same check for a hidden loader, but this time with a JavaScript call to the 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 the page but this time at a cost of ~30ms. I like it much better this way!

Related Posts

Read more...

Automating SignalR applications with Selenium WebDriver

Last Updated on by

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

I had to automate with Selenium WebDriver (version 2.43) a single page web application which was built with SignalR. The 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 to issues with SignalR automation so I prepared this post.

About SignalR

ASP.NET SignalR is a library for building “real-time” applications that enable the server to push events to the client instead of relying client to request data from the server. Once the application is started SignalR client tries to connect to the server with the transport protocols in the 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 the server with Long Polling transport (later on I discovered this was caused by a bug in application’s connection logic). Client (browser) opens a connection to the server. The server keeps this connection open for a relatively long time (2 minutes in my case). Seems like this open connection is confusing Selenium and it doesn’t actually know when the browser is ready. “Unstable” page loading strategy did not work 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 the application under test working with WebSocket transport protocol.

It is also beneficial for the 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...