Saturday, 17 December 2011

Driving a Flex Application via Selenium 2 WebDriver


A while ago my colleague Julia posted an article on acceptance testing a Flex application using Selenium. Now that Selenium 2 has been released I wondered how easy it would be to achieve the same functionality with WebDriver?
As it turns out it isn’t all that difficult. The interaction with JavaScript in the Browser has changed but that aside the changes required to make FlexSelenium operate with WebDriver are straightforward.
The basic principle still remains that the ActionScript extensions for FlexSelenium need to be compiled into your Flex application to expose access to widgets via JavaScript. The changes required are in the way the Java portion of the framework interacts with the browser JavaScript engine.
The WebDriver framework provides an interface that concrete implementations for each browser can implement in order to provide access to the browser’s JavaScript engine. Both the Firefox and Chrome drivers provide such implementations. The code for FlexWebDriver below uses this interface to execute a piece of anonymous JavaScript to call the exposed functions from FlexSelenium.
import org.openqa.selenium.JavascriptExecutor;
import
org.openqa.selenium.WebDriver;
public class FlexWebDriver {
private final WebDriver webDriver;
private final String flashObjectId;

public FlexWebDriver(final WebDriver webDriver, final String flashObjectId) {
this.webDriver = webDriver;
this
.flashObjectId = flashObjectId;
}

public String click(final String objectId, final String optionalButtonLabel) {
return call("doFlexClick", objectId, optionalButtonLabel);
}

public
String click(final String objectId) {
 return click(objectId, "");
}

//... Omitted for clarity ...

private
String call(final String functionName, final String... args) {
final Object result =
((JavascriptExecutor)webDriver).executeScript(
makeJsFunction(functionName, args),
new Object[0]);

  return result != null ? result.toString() : null;
}

private
String makeJsFunction(final String functionName, final String... args) {
 final StringBuffer functionArgs = new StringBuffer();

if
(args.length > 0) {
for (int i = 0; i < args.length; i++) {
if (i > 0) {
functionArgs.append(",");
}
functionArgs.append(String.format("'%1$s'", args[i]));
}
}
return String.format(
"return document.%1$s.%2$s(%3$s);",
flashObjectId,
functionName,
functionArgs);
}
}
The main changes are to use org.openqa.selenium.WebDriver instead ofcom.thoughtworks.selenium.Selenium, and to build the correct JavaScript function to execute via the JavascriptExecutor interface.
A very trivial example of using this to drive a Flex application:
final FirefoxDriver driver = new FirefoxDriver();
final FlexWebDriver flexDriver = new FlexWebDriver(driver, “my-application”);
driver.get(“http://localhost:8080/application”);
// Wait for the application to load
Assert.assertEquals(“true”, flexDriver.click(“aButton”));
I’ve tested this with Selenium 2.0a7 using the Firefox and Google Chrome browser drivers running under Ubuntu 10.10.