Finding visible/hidden elements with the new :visible locator

Watir 6.0 introduces a new locator – :visible. This allows you to specify whether or not the element can be seen by the user.

Usage

Consider the following page where the first div is visible and first span element is hidden:

<html>
  <body>
    <div id="visible_div">can be seen by users</div>
    <div id="hidden_div" style="display:none;">cannot be seen by users</div>

    <span id="hidden_span" style="display:none;">cannot be seen by users</span>
    <span id="visible_span">can be seen by users</span>
  </body>
</html>

By default, Watir locates the first matching element regardless of visibility:

browser.div.id
#=> "visible_div"

browser.span.id
#=> "hidden_span"

By adding visible: true, the first matching visible element is returned:

browser.div(visible: true).id
#=> "visible_div"

browser.span(visible: true).id
#=> "visible_span"

By adding visible: false, the first matching hidden element is returned:

browser.div(visible: false).id
#=> "hidden_div"

browser.span(visible: false).id
#=> "hidden_span"

Not available for collections

In at least version 6.0.2, the :visible locator is not available for collections. Hopefully this is just an oversight and will be added in future releases – Issue 499.

browser.divs(visible: true).count
#=> C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/xpath_support.rb:5:in `escape': undefined method `include?' for true:TrueClass (NoMethodError)
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/locators/element/selector_builder/xpath.rb:48:in `equal_pair'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/locators/element/selector_builder/xpath.rb:32:in `block in attribute_expression'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/locators/element/selector_builder/xpath.rb:28:in `each'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/locators/element/selector_builder/xpath.rb:28:in `map'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/locators/element/selector_builder/xpath.rb:28:in `attribute_expression'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/locators/element/selector_builder/xpath.rb:18:in `build'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/locators/element/selector_builder.rb:122:in `build_xpath'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/locators/element/selector_builder.rb:103:in `build_wd_selector'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/locators/element/selector_builder.rb:49:in `build'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/locators/element/locator.rb:140:in `find_all_by_multiple'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/locators/element/locator.rb:60:in `locate_all'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/element_collection.rb:98:in `elements'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/element_collection.rb:84:in `to_a'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/element_collection.rb:28:in `each'
#=>   from watir-webdriver.rb:98:in `count'
#=>   from watir-webdriver.rb:98:in `<main>'

Performance impact

For the locator to work, Watir iterates through the elements to check their visibility. This can be seen in the Watir::Locators::Element::Locator. A wire call, el.displayed? is made for each potentially matching element:

elements = @query_scope.wd.find_elements(how, what)
elements = elements.select { |el| visible == el.displayed? } unless visible.nil?
elements[idx] unless elements.nil?

In other words, a simple call like browser.div(visible: true).id will need to check every single div on the page. Large number of elements, means slower execution. The following shows the increasing execution time based on the number of elements on the page:

Executed 10 Times 1 div 10 divs 50 divs 100 divs
browser.div.id 0.966645 1.011956 0.943130 0.931430
browser.div(visible: true).id 1.107269 2.511261 8.877038 17.534622

You may want to consider:

  • Only using :visible when necessary – ie as a tie-breaker for a locator that matches both a visible and hidden element.
  • When using :visible, use other locators to limit the potential matches (wire calls).

Does not change interaction rules

Note that this is just a locator. It does not change the fact that the element is hidden and therefore cannot be interacted with.

browser.div(visible: false).click
#=> C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/elements/element.rb:528:in `rescue in wait_for_present': element located, but timed out after 30 seconds, waiting for true condition on {:visible=>false, :tag_name=>"div"} (Watir::Exception::UnknownObjectException)
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/elements/element.rb:518:in `wait_for_present'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/elements/element.rb:535:in `wait_for_enabled'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/elements/element.rb:658:in `element_call'
#=>   from C:/Ruby23/lib/ruby/gems/2.3.0/gems/watir-6.0.2/lib/watir/elements/element.rb:114:in `click'
#=>   from watir-webdriver.rb:99:in `<main>'
Advertisements
This entry was posted in Watir and tagged , . Bookmark the permalink.

7 Responses to Finding visible/hidden elements with the new :visible locator

  1. edmond says:

    hi Jason,

    Thanks for your article. I’m new to Watir and Ruby.

    I would like to use :visible.

    However, I’m getting this error: TypeError: expected one of [String, Regexp], got true:TrueClass

    This is the method I’m using: element(:region_sel, class: “region-selector__highlight”, visible: true)

    Your assistance is appreciated.

    • Justin Ko says:

      What version of Watir are you using? It sounds like you might be using Watir-Webdriver v0.9.9 instead of Watir v6.8.4.

      • edmond says:

        Thx, watir-webdriver is 0.9.3 although my watir is 6.8.4

        these are my gems
        *** LOCAL GEMS ***

        commonwatir (4.0.0)
        watir (6.8.4, 6.7.3, 5.0.0 x86-mingw32)
        watir-classic (4.3.0)
        watir-scroll (0.2.0)
        watir-webdriver (0.9.3)

  2. edmond says:

    sorry, but what’s the difference between watir and watir-webdriver? thx a bunch

    • Justin Ko says:

      Watir-Webdriver was the initial implementation of Watir backed by Selenium-WebDriver. As it grew in popularity and capability, it was decided to make it the standard Watir implementation. The project was moved to be just the Watir gem. Effectively, Watir v6.x is the latest version of Watir-Webdriver.

      I would guess that the commonwatir gem might be the issue. It might be causing Watir-Webdriver 0.9.3 to load rather than Watir 6.8.4. I would start by uninstalling the unnecessary gems – ie “gem uninstall commonwatir” and “gem uninstall watir-webdriver”.

      • edmond says:

        Thx for your input. I have uninstalled watir-webdriver
        btw, I joined a test team which have been using Rubymine and watir for test automation.
        I’m still a newbie so…
        What do I do when Rubymine says “RubyMine has detected that some of the gems required for … suite are not installed” Where do I go about resolving this dependency?
        This is for watir-webdriver

      • Justin Ko says:

        Given that you have a Gemfile, you should be able to do a “bundle install” to get all your gems updated.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s