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.

  • 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 '18 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 – André Roggeri Campos May 2 '18 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 '18 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 – André Roggeri Campos May 2 '18 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. – André Roggeri Campos May 2 '18 at 17:43
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;

}
| improve this answer | |
  • 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 – André Roggeri Campos May 2 '18 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 – André Roggeri Campos May 2 '18 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); – Bill Hileman May 2 '18 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. – Peter M. - stands for Monica May 2 '18 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 :-( – Peter M. - stands for Monica May 2 '18 at 20:50
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.

| improve this answer | |
  • 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() – André Roggeri Campos May 2 '18 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. – Peter M. - stands for Monica May 2 '18 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) – André Roggeri Campos May 2 '18 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 – André Roggeri Campos May 2 '18 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 :-) – Peter M. - stands for Monica May 2 '18 at 18:34
1

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;
}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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