Arthur
Arthur

Reputation: 179

Wait.until() with Webdriver PageFactory elements

i'm using @FindBy annotations to locate elements on my page. Like this:

   @FindBy(xpath = "//textarea")
    public InputBox authorField;

Please, help. I want use wait (ExpectedConditions) with my annotated elements. Like this:

wait.until(visibilityOfElementLocated(authorField));

instead of:

wait.until(visibilityOfElementLocated(By.xpath("//textarea")));

Thanks for advance

Upvotes: 4

Views: 13171

Answers (4)

Spriha
Spriha

Reputation: 107

As mentioned in other answers, ExpectedConditions.visibilityOf(authorField); will do the job. Mentioning a detailed solution below for more clarity.

public class YourTestPage {
    private WebDriver driver;
    private WebDriverWait wait;

    @FindBy(xpath = "//textarea")
    private WebElement authorField;

    public YourTestPage(WebDriver driver) {
        this.driver = driver;
        wait = new WebDriverWait(driver, 15, 50);
        PageFactory.initElements(driver,this);
    }

    public void enterAuthorName() {
        wait.until(ExpectedConditions.visibilityOf(authorField)).sendKeys("Author Name");
    }
}

Upvotes: 1

Trevor Young
Trevor Young

Reputation: 545

I know that this question is already answered and was asked a while ago, but I figured that I'd provide a concrete example of how to write your own Expected Condition for this. By creating this Expected Condition class:

/**
 * Since the proxy won't try getting the actual web element until you
 * call a method on it, and since it is highly unlikely (if not impossible)
 * to get a web element that doesn't have a tag name, this simply will take
 * in a proxy web element and call the getTagName method on it. If it throws
 * a NoSuchElementException then return null (signaling that it hasn't been
 * found yet). Otherwise, return the proxy web element.
 */
public class ProxyWebElementLocated implements ExpectedCondition<WebElement> {

    private WebElement proxy;

    public ProxyWebElementLocated(WebElement proxy) {
        this.proxy = proxy;
    }

    @Override
    public WebElement apply(WebDriver d) {
        try {
            proxy.getTagName();
        } catch (NoSuchElementException e) {
            return null;
        }
        return proxy;
    }

}

Then this will allow you to do:

wait.until(new ProxyWebElementLocated(authorField));

And that's all you really need. But if you want to take the abstraction one step further, you could create a class like this:

public final class MyExpectedConditions {

    private MyExpectedConditions() {}

    public static ExpectedCondition<WebElement> proxyWebElementLocated(WebElement proxy) {
        return new ProxyWebElementLocated(proxy);
    }
}

Which would then allow you to do something like this:

wait.until(MyExpectedConditions.proxyWebElementLocated(authorField));

The MyExpectedConditions class can be a bit overkill for one Expected Condition, but if you have multiple Expected Conditions, then having it will make things much nicer.

As a final note for any that really want to go the extra mile, you can also add methods to the MyExpectedConditions class that wrap the methods in the ExpectedConditions class, and then you can get all your Expected Conditions stuff from one place. (I'd suggest extending ExpectedConditions instead of doing the wrapper methods, but it has a private constructor, making it impossible to extend. This leaves wrapper methods as the only option for those that really want everything in one place.)

Upvotes: 3

Petr Janeček
Petr Janeček

Reputation: 38414

The problem is that methods taking a WebElement usually assume the WebElement was already found (And they are right! PageFactory arranges it so that just before the element is accessed by a method, it is found.), i.e. exists on the page. When giving a By to the method, you say "I want it to be found, I just don't know when will it show up."

You can use

wait.until(visibilityOf(authorField));

in conjuction with

// right after driver is instantiated
driver.manage().timeouts().implicitlyWait(...);

That should do it just the way you'd like.

implicitlyWait() documentation says:

Specifies the amount of time the driver should wait when searching for an element if it is not immediately present.

When searching for a single element, the driver should poll the page until the element has been found, or this timeout expires before throwing a NoSuchElementException. When searching for multiple elements, the driver should poll the page until at least one element has been found or this timeout has expired.

So, basically, it waits for an element to show up every time it is looked up. Which is good for all sorts of asynchronous requests, obviously.

Upvotes: 5

Pazonec
Pazonec

Reputation: 1559

ExpectedConditions.visibilityOf(authorField);

Look at the source code of any Expected condition. It's very easy to write your own condition that can do everything you want.

Upvotes: 5

Related Questions