Wait for the element - WebDriver - PageObject pattern

While I am using the PageObject template, I wondered where to wait for the element on dynamic pages. Suppose we have a testing method and a pageObject class. Should I do something like (in the testing method):

  • Press button
  • Wait for the item to display
  • Check element (contains, for example, the isElementDisplayed () method)

Or maybe there is another good practice to wait for an item? Maybe we should wait for the element in the isElementDisplayed method, which is located in PageObject.class?

+8
java selenium selenium-webdriver webdriver pageobjects
source share
2 answers

You should wait for the elements in your page object class, and not in the test class, because your elements must be defined in the page object class, the test class should not know anything about any elements, selectors or the like. Tests, IMHO, should contain only chains of method calls that describe the testing process, all interaction with the website and the underlying DOM should occur in the Page Object class.

Thus, a too verbose method of waiting for the appearance of an element may look something like this:

private final By yourElement = By.id("id"); @Override public void isLoaded() throws Error { new FluentWait<WebDriver>(driver) .withTimeout(60, TimeUnit.SECONDS) .pollingEvery(1, TimeUnit.SECONDS) .ignoring(NoSuchElementException.class) .ignoring(StaleElementReferenceException.class) .until(new Function<WebDriver, Boolean>() { @NotNull @Override public Boolean apply(WebDriver webDriver) { WebElement element = driver.findElement(yourElement); return element != null && element.isDisplayed(); } }); } 

Simply put, the function polls the DOM for 60 seconds (every 1 second) to see if an element exists in the DOM and whether it is visible (meaning it has a height and width of more than 1 pixel). If an element exists (and is displayed), the function returns the found element and stops polling (although isLoaded() does not return the element in this particular case).

It makes sense to ignore the NoSuchElementException which can be findElement by the findElement method if the element is not found, and the StaleElementException , which indicates that the link to the element is now "out of date" - the element is no longer displayed in the DOM of the page. This usually means that something (most often JS) has changed the DOM and the link is no longer valid, so WebDriver should look for it again.

Of course, a shorter code would do, too, something like this:

  new WebDriverWait(driver, 60) .until(ExpectedConditions.visibilityOf(someWebElement)); 

The documentation is actually pretty good at that.

EDIT: Reply to comment:

Well understood. But what if an element is present after pressing a button, etc.?

Suppose you have a script where you have a button, and after clicking this button, a text field appears and you want to interact with it.

 public class PageObject extends LoadableComponent<PageObject>{ public PageObject() throws Exception { driver = getWebDriver(); PageFactory.initElements(driver, this); isLoaded(); } private WebDriver driver = null; @FindBy(id = "yourButton") private WebElement button; @FindBy(id = "textBoxThatAppears") private WebElement txtBox; @Override public void isLoaded() throws Error { // Initial loading, called when creating the page object to make sure that the page is loaded to a state where it is ready to interact with us, in our case it means that button is present in DOM and visible. waitForVisibility(button); } private void waitForVisibility(WebElement element) throws Error{ new WebDriverWait(driver, 60) .until(ExpectedConditions.visibilityOf(element)); } public void clickButton(){ button.click(); } public void interactWithTextbox(String text){ // Wait for txtBox to be visible, then send text waitForVisibility(txtBox); txtBox.sendKeys(text); // EDIT 27.04.14: // Actually you should not do the assertion here or anywhere in // the pageObject, because when reusing the method in some other test, you might // not want to assert, you might wonder that why wouldn't you assert some // specific condition every time, but I would throw that question right back // to you and ask: What is the point of checking the exact same thing over and // over again. There are 2 things, firstly the assertion takes resources (and // that can become important when test suite grows, secondly your tests can // simply start failing at the same point when one little condition is not as // it should be. Also, having the asserts in the test, makes the test more // readable and understandable for others. // end edit 27.04.14 // Next line is no longer recommended by this answer. // assert that something happened that you expected. } } 

And now your test class:

 public void TestClass { @Test public void testClickButtonAndInteractWithTextbox(){ // Initiate the page object Pageobject po = new PageObject(); po.clickButtonAndWaitForTextbox(); po.interactWithTextbox("blabla"); // edit 27.04.14 assertSomethingGoodHappened(); } } 
+15
source share

Another effective test page concept (starting with selenium 1) from one of the selenium testing systems - ISFW can be used here. It has a lazy loaded item, a custom component function and auto wait (implicit wait that slows down performance), built-in wait methods with elements and other functions that are very useful for ajax database applications.

It provides the following building blocks for developing a test case:

  • Testing Page
  • Component
  • Testing step

In addition, Reporting is also descriptive.

0
source share

All Articles