2

I'm writing tests for a system that shows a Popup on the first login but doesn't on the subsequent logins.

Currently my code is something like this:

PopupPage

class PopupPage extends BasePage {
  @FindById(id="closeBtn")
  private WebElement closeButton;

  public boolean isDisplayed(){
    //Throws an error when the popup isn't displayed because the popup isn't in the DOM.
    return closeButton.isDisplayed();       
   }
}

This is very similar to this question, but I don't want to repeat the selector that is already present in the FindById notation.

So how do I assert that the element is on page or not ? (Ideally I would like to have some method coming from the WebElement like closeButton.isStale() or something like this.

6
  • 1
    You shouldn't assert the non presence of an element since you'll get a false positive if the selector where to no longer match the targeted element. Instead assert the text in the page or try to perform an action which will be prevented by the popup and assert the exception.
    – Florent B.
    May 2, 2018 at 15:45
  • Yes, but I should check if the element exists on the DOM, otherwise I'll get a NoSuchElementException when trying to check the text May 2, 2018 at 15:53
  • You won't get any exception by reading the text from the container which contains (or not) the popup.
    – Florent B.
    May 2, 2018 at 15:59
  • Ah, now I do understand what you mean. It may work, but its not very elegant solution :/. Peter answer works too, but it doesn't seems right May 2, 2018 at 16:34
  • 1
    My goal is to be able to check that the element is not visible that is easily undernstandable. I could write: driver.findElements(By.id("closeBtn")).size() == 0 but then I would be duplicating the selector. May 2, 2018 at 17:43

3 Answers 3

2

In a page object model, all defined elements are initialized to null using the pagefactory.

If an element does not exist in the DOM, then it will remain null when you refer to it.

Therefore, simply check your element for a null value.

/**
 * Is the element displayed?
 * @author Bill Hileman
 * @param element - a web element
 * @param locator - a verbal description of the element for logging purposes
 * @return Boolean true if displayed, false if not displayed or null
 */
public Boolean isDisplayed(WebElement element, String locator) {

    Boolean passFail = false;

    try {
        if (element.isDisplayed())
            passFail = true;
    } catch (NullPointerException | NoSuchElementException e) {
        System.err.println("Unable to locate element '" + locator + "'");
    } catch (Exception e) {
        System.err.println("Unable to check display status of element '" + locator + "'");
        e.printStackTrace();
    }

    return passFail;

}
15
  • 1
    Doing this will cause the driver to wait the implicitlyWait time before triggering a NoSuchElementException . And the elements are initialized on the Page constructor by the method PageFactory.initElements(driver, this);, so they are never null May 2, 2018 at 17:47
  • 1
    I just tested it: Set the implicitlyWait to a absurd value like 200. Check the behavior of your method. It will wait for 200 seconds before the NoSuchElementException is triggered May 2, 2018 at 18:05
  • 1
    Try this, but set the time to whatever you think is appropriate, and please let me know: PageFactory.initElements(new AjaxElementLocatorFactory(driver, 15), this); May 2, 2018 at 18:14
  • 1
    @FlorentB. - I am 100% sure that find_elements() (please note plural) does not wait. find_element() (singular) is the one which waits. May 2, 2018 at 19:28
  • 1
    @FlorentB. - oh I see. I never use implicit waits, only explicit, as per best practices, and implicit default is 0. In fact, I never use raw selenium calls, just our custom convenience wrappers (which include explicit wait) :-) My bad :-( May 2, 2018 at 20:50
2

The method I use is to use findElements() and check the .size(); zero means gone, any positive number means it's still there.

Also, programming is all about not repeating yourself, so make the selector a variable :)

String idOfThing = "closeBtn";
@FindBy(id = idOfThing)
private WebElement closeButton;

if (!doesItExistById(idOfThing)) {
    System.out.println("It vanished!");
}

public boolean doesItExistById(String id) {
    return driver.findElements(By.id(id)).size() > 0;
}
1

Python has find_elements() group of methods which:

  • do not wait
  • return a matching list, which is empty if no matching elements are found

Please note is is elements. I assume Java has similar methods.

isDisplayed() can be used only on a valid located element, it will fail if element is not present.

This approach has additional benefit that you can check for a presence/absence of multiple elements (or elements with no unique locators, like error messages) which might have a name or CSS class but no known unique id.

8
  • Using find_elements works, but it doesn't seem the best approach, because then I would need to access the element by the list index, something like this: closeButton.get(0).isDisplayed() May 2, 2018 at 15:57
  • @AndréRoggeriCampos - not sure why get(0) is a problem? You have two different problems here: (1) find out if element is present at all (2) if present, if it is displayed. May 2, 2018 at 16:44
  • Because it doesn't make sense cast the WebElement that is unique as a List, because its not. Doing so will require to write the get(0) (Which is not a problem, but I'm looking for a better solution) May 2, 2018 at 17:56
  • Although, this solves my problem, I'll wait to see if some other solution is presented, otherwise I'll mark this as my answer May 2, 2018 at 17:58
  • @AndréRoggeriCampos - you don't need to cast anything as list. findElements() will return a list and do it without waiting. You are used to deal with unique locators, which always wait. I often use find_elements() and then loop over returned elements and pick one by other attributes. It gives me flexibility to use more robust locators (which might not be unique). I commend you to wait for other answers, more people should give a chance other timezones to respond :-) May 2, 2018 at 18:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.