Observation
Back when I started Watir, there was only one method to check for an element on the page – Element#exists?. Now, several versions later, there are three – Element#exists?, Element#visible? and Element#present?.
The three methods are not aliases of each other. They are different.
How are they different?
Exploring the Difference
RDoc description
From the watir-classic rdoc (and similarly in watir-webdriver), the three methods are described as:
- exists? – Returns whether this element actually exists.
- present? – Returns true if the element exists and is visible on the page
- visible? – If any parent element isn’t visible then we cannot write to the element. The only reliable way to determine this is to iterate up the DOM element tree checking every element to make sure it’s visible.
What does that actually mean or, more importantly, where does it matter?
Code example
Consider the following HTML page, which has one div tag that is visible (ie displayed) and one that is not.
<html> <body> <div id="1" style="display:block;">This text is displayed</div> <div id="2" style="display:none;">This text is not displayed</div> </body> </html>
When each method (exists?, present?, visible?) is run for the different elements (displayed, not displayed, non-existent), the following results are seen.
Element | .exists? | .present? | .visible? |
---|---|---|---|
Displayed (browser.div(:id => ‘1’)) | true | true | true |
Not Displayed (browser.div(:id => ‘2’)) | true | false | false |
Non-Existent (browser.div(:id => ‘3’)) | false | false | exception |
Element#exists? checks if the element is in the DOM (or HTML). Element#visible? checks if the element can be seen by the user, but throws an exception if the element is not in the DOM. Element#present? is the same as Element#visible? except that it returns false, instead of an exception, when the element is not in the DOM.
Conclusion
While the three methods are definitely different, I think, at least from my experience, that you should typically be using Element#present?.
One point to keep in mind, especially for those working with legacy watir libraries/tests, is that .exists? can lead to false positives. Imagine you have a form. When the form is submitted, an error message is displayed for fields that fail validation (ex missing a required field). In some applications this will be implemented by simply changing the style of the element containing the error message from display:none to display:block. Now consider writing a test to check that the validation message is displayed. If you use .exists?, the test will have false positives (ie it will always pass since the element is always in the DOM). In this situation, .visible? or present? should have been used.
Hello! This is a useful information. I met such problem. Some element exists, but not present, seems it cannot be operated, ie. click or other operations? If so, how to make it?
It would really depend on the page. First off, you should make sure that you are actually interacting with the right element. Then you need to figure out why the element is not visible. Is there an action that a user must take before they see the element – eg click something, mouse over something, etc? Watir is meant to mimic a user, so the script needs to do the same triggering actions.
Can you provide a page that reproduces the issue?
There is no “block” property in CSS; both divs in your example are shown. Did you mean “display: block” and “display: none”?
Thanks, I have updated the post.
funny enough if you use PageObject, some versions use .present? under the covers for .visible? and don’t even work with .present.
Example code:
on(MyPage) do |page|
page.submit if page.div_element(id: ‘MyDiv’).visible?
end
.visible? in this case works with no exception if there is no div#MyDiv
At least in Page Object 1.2.0 this is how PageObject::Platforms::WatirWebdriver::Element#visible? is defined
def visible?
element.present?
end
.present? throws an error in this case (looks not defined)
If you ask me, this inconsistency adds to the confusion that could already exist here.
Agreed, that has been a cause of confusion.
The good news is that the problem should be fixed in Page-Object v2.1. At least it looks like Page-Object no longer defines the #visible? and #present? methods. Instead it just delegate the methods directly to Watir. In other words, Page-Object and Watir should be consistent now.