Configuring Twist for Selenium 2

The Challenge

I have been happily using the Sahi driver with Twist for the last few months now.  However, I wanted to try driving some mobile devices in via Twist with Selenium 2 to give our team some extra scope and flexibility.  Fortunately, this proved achievable with a small amount of code and some Spring configuration with Twist.

Creating a Driver Factory

The Twist documentation provides some excellent documentation on how to switch to alternative Selenium drivers.  So I essentially followed that template.  After downloading and referencing the Selenium 2 jars in project class path, I created a factory class for WebDriver with the following code:

package twist.drivers;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.android.AndroidDriver;
import org.openqa.selenium.iphone.IPhoneDriver;

public class WebDriverFactory {
  
  private enum DeviceType {
    iphone, android
  }

  private WebDriver webDriver;
  private DeviceType deviceType;
  private String deviceURL;

  public WebDriverFactory(String deviceType, String deviceURL) {
    this.deviceType = DeviceType.valueOf(deviceType);
    this.deviceURL = deviceURL;
  }

  public void start() {
    try {
      if(deviceType.equals(DeviceType.iphone)) {
        webDriver = new IPhoneDriver(deviceURL);
      } else if(deviceType.equals(DeviceType.android)) {
        webDriver = new AndroidDriver(deviceURL);
      } else {
        throw new RuntimeException("Device type not selected");
      }
    } catch (Exception e) {
      throw new RuntimeException(e);
    } finally {
      //
    }
  }

  public void stop() {
    webDriver.quit();
  }

  public WebDriver getWebDriver() {
    return webDriver;
  }
}

An enumeration was used to allow the management of execution device targets.  In this case, I switched the appropriate driver implementation to the interface based on these values.  These could as easily be different browser types such as Firefox, IE, Safari, or Google Chrome.

Configuring the Spring Context (Suite)

The “applicationContext-suite.xml” file was then configured to use the driver factory with the following XML:

<bean id="webDriverFactory" class="twist.drivers.WebDriverFactory" init-method="start"
    destroy-method="stop" lazy-init="true">
  <constructor-arg value="${webdriver.device.type}"/>
  <constructor-arg value="${webdriver.device.url}"/>
</bean>

<bean id="webdriver" factory-bean="webDriverFactory" factory-method="getWebDriver" lazy-init="true" />

You’ll probably notice that both the device type and device URL are being injected in to the constructor via placeholders.  This meant I could give the flexibility of launching to different execution targets based on properties file settings (see more on this at my previous post Switch Test Runner Browsers Easily).

Scenario Writing and Test Code

One real advantage of using a tool like Twist is that the scenario writing and high level test code doesn’t need to be altered when switching or evolving drivers.  In fact, it shows that you’re along the right lines with scenario definition if that is the case.  This is especially true when you code to an automation framework pattern that abstracts site implementation along the lines of PageObjects (see the Selenium 2 wiki for further information on PageObjects).

The bottom line is that however you code your automation, you can now pick up and use the driver by passing it in via a constructor.  The example below gives a snippet of how this might look for a workflow class without such a pattern being used for a simple illustration of using the driver Spring bean:

package web.workflows;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import static org.junit.Assert.assertThat;
import static org.hamcrest.core.Is.is;

public class HomePageTests {

  private WebDriver driver;

  public HomePageTests(WebDriver driver) {
    this.driver = driver;
  }

  private WebElement dateDropDown(){
    return driver.findElement(By.id("date"));
  }

  public void setDate(String date){
    dateDropDown().sendKeys(date);
  }

  public String getDate(){
    return dateDropDown().getValue();
  }

  public void verifyDateSet(String date){
    setDate(date);
    assertThat(getDate(), is(date));
  }
}

Conclusion

The flexibility and ease at which this can be a achieved with Twist can’t be understated.  You can be up and running with Selenium 2 in a very short amount of time.  The other side of this spike for me was getting the mobile devices set up for driving tests through both real devices and simulators.  However, that’s another post in itself (especially the iPhoneWebDriver)… I’ll post that as a part II to this post at a later date.

As ever, please feel free to post comments or alternative views.  I’ll try to help where I can.

1 thought on “Configuring Twist for Selenium 2

Leave a Reply

%d bloggers like this: