Wait for element - WebDriver - PageObject pattern

落爺英雄遲暮 提交于 2019-11-27 01:30:06

问题


As long as I use PageObject pattern I wondered where should I wait for element on dynamic pages. Assuming we have test method and pageObject class. Should I do something like (in test method):

  1. Click on button
  2. Wait for element to be displayed
  3. Verify the element (contains eg. method isElementDisplayed())

Or maybe there is other good practice to wait for the element? Maybe we should wait for element in method isElementDisplayed which is in PageObject.class?


回答1:


You should wait for elements in your page object class, not in test class, because your elements should be defined in page object class, test class should know nothing of any elements, selectors or similar. Tests, IMHO, should contain only chains of method calls that describe the test flow, all the interaction with the website and underlying DOM should take place in Page Object class.

So an overly verbose method to wait for some element to appear could be something like:

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();
                }
            });
}

In plain words, the function if polling the DOM for 60 secs (every 1 second) to see, if the element exists in DOM and it is visible (means has height and witdh greater than 1px). If the element exists (and is displayed), the function returns the found element and stops the polling (although isLoaded() method does not return the element in this particular case).

It makes sense to ignore NoSuchElementException which can be thrown by findElement method in case the element is not found, and StaleElementException, which indicates that a reference to an element is now "stale" - the element no longer appears on the DOM of the page. This usually means, that something (most commonly JS) has modified the DOM and the reference is no longer valid, hence the WebDriver needs to look it up again.

Of course shorter code would also to the trick, something like:

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

The documentation is actually pretty good on this.

EDIT: answer to the comment:

OK, understood. But what if element is present after clicking on some button etc.?

Lets say you have a scenario, where you have a button and after clicking that button a textbox 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();
     }
}



回答2:


Another efficient concept of test page(Since selenium 1) from one of the selenium testing-frameworks - ISFW can be utilized over here. It has lazy loaded element, custom component feature and auto wait (not implicit wait that reduce performance), inbuilt wait methods with element and other features that are very useful for ajax bases application.

It provide following building blocks for developing test case:

  1. Test Page
  2. Component
  3. Test step

In addition Reporting is also descriptive.



来源:https://stackoverflow.com/questions/18843581/wait-for-element-webdriver-pageobject-pattern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!