Read more

Change how Capybara sees or ignores hidden elements

Ulrich Berkmueller
March 27, 2012Software engineer

The information in this card is no longer accurate for modern Capybaras.

Short version

  • Capybara has a global option (Capybara.ignore_hidden_elements) that determines whether Capybara sees or ignores hidden elements.
  • Prefer not to change this global option, and use the :visible option when calling page.find(...). This way the behavior is only changed for this one find and your step doesn't have confusing side effects.
  • Every Capybara driver has its own notion of "visibility".

Long version

Capybara has an option (Capybara.ignore_hidden_elements) to configure the default query behavior of finding nodes within the DOM. It's default value is false. That means that your css or xpath queries will find all nodes in the document regardless of their visibility on the page. You can overwrite this behavior for an individual query by passing the :visible => true|false option.

# default behavior for hidden elements
# Capybara.ignore_hidden_elements = false

# find all elements (hidden or visible)
page.all(".articles .article[id='foo']")

# find visible elements only (overwrite the standard behavior just for this query)
page.all(".articles .article[id='foo']", :visible => true)


# changing the default behavior (e.g. in your features/support/env.rb file)
Capybara.ignore_hidden_elements = true

# now the query just finds visible nodes by default
page.all(".articles .article[id='foo']")

# but you can change the default behaviour by passing the :visible option again
page.all(".articles .article[id='foo']", :visible => false)
Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

But there is still one unanswered question. Capybara supports different drivers like RackTest or Selenium. The driver's interface defines a method called visible? for nodes which raises an NotImplementedError. That means each driver has to implement it's own detection when an element on the page is visible or not. I'll give you a short description of what visible? does for RackTest and Selenium.

How Capybara::Driver::Node#visible? works for RackTest and Selenium

RackTest

RackTest is a simple browser simulator that is just aware of plain HTML represented as a string (HTTP response body). It does not evaluate CSS or JavaScript. It uses Nokogiri for parsing the response body. This way you can use query selectors to find nodes, click links and so on. Since CSS and JS are not respected, the visible? method can only look for a style="display: none" attribute set for the node or it's ancestors. Furthermore the visibility: hidden rule is not checked at all.

Selenium

Selenium Show archive.org snapshot is an integration test framework that consists of different tools to test websites and web-applications with real browsers. Capybara has a driver for Selenium that wraps around selenium-webdriver Show archive.org snapshot which is a Ruby binding to remote control real browsers via Selenium's WebDriver API. What does that mean for capybara's visible? method? Due to the fact that a real browser is used for your website tests, the browser itself is aware of all visible and hidden elements since it parses CSS rules and JavaScript, too.

Conclusion

In my opinion I would not recommend to ignore hidden elements by default unless you know what you are doing. The fact that hidden elements (by CSS or JS) can't be detected by RackTest but by Selenium makes it hard to change a test's driver.

Posted by Ulrich Berkmueller to makandra dev (2012-03-27 09:23)