Skip to content
August 14, 2012 / selenium34

Custom Locators Part 2

Now that we’ve developed our “custom” PageFactory, we need to create create a couple of more classes before our annotation is fully usable. The first of which is the CustomElementLocatorFactory. It will be responsible for telling the PageFactory to use our CustomElementLocator, which we will go over in just a minute. Here is the implementation for our Factory method:

public class CustomElementLocatorFactory implements ElementLocatorFactory {
  private final WebDriver driver;
  public CustomElementLocatorFactory(final WebDriver driver) {
    this.driver = driver;
  public ElementLocator createLocator(final Field field) {
    if (field.isAnnotationPresent(JQueryLocator.class)) {
      return new CustomElementLocator((JavascriptExecutor) driver, field);
    } else {
      return new DefaultElementLocator(driver, field);

Once we’ve completed our CustomElementLocator we are good to go. Here’s the sample implementation:

public class CustomElementLocator implements ElementLocator {
  private final JavascriptExecutor driver;
  private final JQueryLocator jql;
  public CustomElementLocator(final JavascriptExecutor driver, final Field field) {
    this.driver = driver;
    this.jql = field.getAnnotation(JQueryLocator.class);
  public WebElement findElement() {
    return (WebElement) driver.executeScript("return $" + jql.$() + "[0];");
  @SuppressWarnings("unchecked") @Override
  public List<WebElement> findElements() {
    return (List<WebElement>) driver.executeScript("return $" + jql.$());

We now can utilize the new annotation in any of our Page Objects, and have it work with our custom PageFactory. Here is a sample PageObject:

public class JQueryHomePage {
  private final WebDriver driver;
  @JQueryLocator($ = "('#jq-intro')")
  private WebElement introDivWithJQuery;
  @FindBy(id = "jq-intro")
  private WebElement introDivWithDefault;
  public JQueryHomePage(final WebDriver driver) {
    this.driver = driver;
    CustomPageFactory.initElements(driver, this);
  public WebElement getIntroDivWithJQuery() {
    return introDivWithJQuery;
  public WebElement getIntroDivWithDefault() {
    return introDivWithDefault;

And here is a simple class to test that things are working as expected:

public class JQueryHomePageTest {
  private static WebDriver driver;
  private static JQueryHomePage homePage;
  public static void setup() {
    driver = new FirefoxDriver();
    homePage = new JQueryHomePage(driver);
  public void ensureItemsAreSame() {
  public static void shutdown() {

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: