Using PageFactory and @FindBy in base class

415 views
Skip to first unread message

Jeff

unread,
Mar 25, 2011, 11:58:18 AM3/25/11
to webdriver
I'm trying to put common functionality into a base class and use the Annotations provided in the support library.  Here is a basic simplified illustration of the base class:
public abstract class Element {
  protected final WebDriver driver;
 
  //@FindBy won't work here because this is in the base class
  // and needs unique values
  protected WebElement e;
 
  public Element(WebDriver driver) {
    this.driver = driver;
  }
 
  public String getAttribute(String name) {
     return e.getAttribute(name);
  }
  ....
}
Now I want to create a subclass:
public class LabelElement extends Element {  ...  }
Element.e needs to be annotated but needs the unique 'How' and 'using' values only available when LabelElement is defined.  However, I don't think I can annotate 'e' from the LabelElement subclass.
 
If I move 'e' to LabelElement,  I must pass in 'e' to all calls to the base class methods needing it (e.g., getAttribute(e, "class")).
 
Is there another trick I'm overlooking that facilitates subclassing with annotations?
 
--
Jeff Vincent
See my LinkedIn profile at:
 

Sergii

unread,
Mar 25, 2011, 12:18:21 PM3/25/11
to webd...@googlegroups.com
It seems that you need to pass a WebElement to the constructor of the
Element. However in this case it is not clear why you need a wrapper
around the WebElement :) Of course, if you have some common actions to
be executed over the element, then it can be something like this:


public abstract class Element {

protected WebElement element;

public Element(WebElement element) {
this.element = element;
}

public String getAttribute(String name) {
return element.getAttribute(name);
}

public void doSomethingCommon() {
.......
}
....
}

> --
> You received this message because you are subscribed to the Google Groups
> "webdriver" group.
> To post to this group, send email to webd...@googlegroups.com.
> To unsubscribe from this group, send email to
> webdriver+...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/webdriver?hl=en.
>

Jeff

unread,
Mar 25, 2011, 4:07:51 PM3/25/11
to webd...@googlegroups.com
Sorry, the example I gave was (too?) oversimplified for illustration.  Another disclaimer is that I'm just trying things at this point to see what "can" be done in order to fit it in with my task so this is very much an experiment with PageFactory and the support annotations.
 
To that end, the idea is to build a heirarchy of reusable PageObject-esque classes where the base class encapsulates the most common information about (among other things) expected element state and some housekeeping stuff to deal with times when a page reload or ajax call rewrites the DOM and invalidates the WebElement references.
 
The rub comes when trying to use the annotations (@FindBy, etc.) since they don't seem to lend themselves to being abstracted to a base class.
 
As an example, the HTML sample below is from a section of the Step 2 in the wizard I am testing.  The "Lesson Title" has the main label text, sub-label text and an input field.  The "Lesson Description has the same format of main label and sub-label but has a textarea.  The set of elements for the "URL where lesson is hosted" follows the same pattern.  These elements will appear as shown (except for the value of the input and textareas) on all the wizard step2 pages.  The label and sub-labels will be localized so I need to verify their values for the given language.
 
//Title Elements - shared with all lesson types.
  <label>
    <span class="">Lesson Title —</span>
    <span class="sub-label">(1024 characters max)</span>
  </label>
  <input gtbfieldid="4" name="view:courseTitle" value="A1 - Teacher's Resource Lesson" type="text">
//Description Elements - shared with all lesson yypes
  <label>
    <span class="">Lesson Description —</span>
    <span class="sub-label">(2048 characters max)</span>
  </label>
  <textarea rows="10" cols="60" name="view:courseDescription">test</textarea>
//URL for Online Lesson - unique to online lesson type
  <label>
    <span class="">URL where lesson is hosted —</span>
    <span class="sub-label">(full URL - 1024 characters max)</span>
  </label>
  <input gtbfieldid="5" name="view:courseUrl" value="http://www.google.com" type="text">
Hopefully what I'm doing makes sense.  As I've typed this response (good therapy), I think to your point, I may be trying to work at too granular of a level.  Going to refactor a bit and see what falls out.  
 
Thanks!  This is good stuff! 

Daniel Wagner-Hall

unread,
Mar 25, 2011, 9:30:17 PM3/25/11
to webdriver, Jeff
We use a FieldDecorator to replace WebElements with proxies; this was
designed in a nice pluggable way, so you can implement your own
FieldDecorator which does some slightly more clever filling in, using
the values of other fields on the class or whatever.

You can pass in a custom field decorator to
PageFactory.initElements(FieldDecorator decorator, Object page)

org.openqa.selenium.support.pagefactory.FieldDecorator has a concise,
well defined interface, and the default implementation which just
fills in WebElements:
org.openqa.selenium.support.pagefactory.DefaultFieldDecorator is
surprisingly simple :)

Reply all
Reply to author
Forward
0 new messages