3

Does the Selenium FindBy annotation actually instantiate WebElement instances, and if so, what is the connotation to the framework that uses them?

What I have been doing in my page objects looks like this right now. All my test framework methods take By locators as arguments (not WebElement instances).

//fields in the page
public static final By SEARCH_BOX = By.id("input-what");

My question is, does using FindBy instantiate WebElement instances at the time of class instantiation? If so, then I suspect my framework methods would need to take WebElement instances. Is this correct, and which is preferred in a framework: By locator arguments or WebElement arguments?

@FindBy(id = "input-what")
public WebElement SEARCH_BOX_ELEMENT;

I know I am expecting a somewhat opinionated answer. If you give me a hyperlink citation for your belief, then I think that would be a reasonable answer. I think this has far-reaching implications: for example, the methods in Selenide framework, don't take WebElement instances in their arguments and therefore PageObjects that use FindBy annotations would not be able to pass those elements to Selenide methods?

djangofan
  • 28,471
  • 61
  • 196
  • 289

2 Answers2

3

If I understand what you are asking, your answer is on the very first line of the documentation:

In order to use the PageFactory, first declare some fields on a PageObject that are WebElements or List<WebElement>...

Or possibly the end of the same documentation:

WebElements are evaluated lazily. That is, if you never use a WebElement field in a PageObject, there will never be a call to "findElement" for it.

Edit: To complete the answer: PageObject is a coding style of collecting information about your webapp. In order to make this coding style less verbose, Selenium offers a PageFactory, which uses the @FindBy annotation to decorate WebElements in your PageObject classes.

djangofan
  • 28,471
  • 61
  • 196
  • 289
SiKing
  • 10,003
  • 10
  • 39
  • 90
  • Sorry, my question is outside of the context of using PageFactory. In other words, my question is asked in the context where the PageObject does not ever call PageFactory. – djangofan Feb 18 '16 at 19:53
  • @djangofan `@FindBy` is used **only** by PageFactory. Using your own PageObjects will ignore the annotation. – SiKing Feb 18 '16 at 19:55
  • Ahh. That answers part of my question. Any link to where that is documented? – djangofan Feb 18 '16 at 19:55
  • Yes but I was thinking along the same lines as SiKing... if you pass your class to a PageFactory to instantiate the WebElements for you, then aren't they by definition not instantiated before? At least that was where my answer was headed... :) – JeffC Feb 18 '16 at 19:56
  • It's documented in [FindBy](https://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/support/FindBy.html)... `...Used in conjunction with PageFactory this...` – JeffC Feb 18 '16 at 19:57
  • Ok, I read the doc: so are they or aren't the WebElements loaded lazily, without calling PageFactory, but upon the first reference of the WebElement object? Doc isnt' super clear about that. – djangofan Feb 18 '16 at 20:00
  • 1
    @djangofan Without using PageFactory, the `@FindBy` annotations are **ignored**, and you get **nothing**. – SiKing Feb 18 '16 at 20:03
  • Ok, thanks. So, I will keep my current method that allows me not to preload the elements, but instead locate them on demand. Thanks. – djangofan Feb 18 '16 at 20:04
  • @djangofan Your edit to my answer is **not** correct. Again from the documentation: "every time we call a method on the WebElement, the driver will go and find it on the current page **again**" (emphasis mine). Please revert your edit! – SiKing Feb 18 '16 at 20:11
  • Ok. I will. I got that impression from the documentation. Sorry. If that is the case, then it seems that using PageFactory with FindBy is a superior method to the way I have been doing it. – djangofan Feb 18 '16 at 20:13
  • @djangofan It is superior to anything else you can have. If you think you have something better, I would encourage you to have it included in the official Selenium code. – SiKing Feb 18 '16 at 20:22
1

I was not aware of these new annotations in selenium.

Kind of have seen page object pattern implemented through Stand Alone Weld based frameworks.

In any case, I think it's relatively clear: https://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/support/FindBy.html

Used in conjunction with PageFactory this allows users to quickly and easily create PageObjects.

Wenever you ask the factory to return you a page object, it will inject the page object with the webelements are read at that point in time. If you page has something like comet functionality, and is going to get stale with time, you would be well advised to not expect your injected web elements to get stale.

From what I've seen so far, you want page objects to simplify your interaction with the browser content. But you want them to be stateless.

I would defnitly, as a rule of thumb, of ajax enabled pages, never have state on my page objects.

If Wanted to write to a text box. I Would offer an api:

public void writePassword(String password){
    ... callPrivateGetterToGetPasswordField().writeText(password);
}

And so on. I would promote methods that use short burst of read dom content and write dom content and try to not have page objects harvesting stale content.

99Sono
  • 3,554
  • 27
  • 39