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 {
And now your test class:
public void TestClass { @Test public void testClickButtonAndInteractWithTextbox(){