Read more

Capybara: Finding invisible elements and how to test that an element is not visible

Arne Hartherz
January 11, 2022Software engineer at makandra GmbH

When Capybara locates elements in the DOM, by default it allows only accessing visible elements -- when you are using a driver that supports it (e.g. Selenium, not the default Rack::Test driver).

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

Consider the following HTML:

<div class="test1">One<div>
<div class="test2">Two</div>

With some CSS:

.test1 { display: block }
.test2 { display: none }

We will be using Capybara's find below, but this applies to any Capybara finder methods.

Default: visible: :visible or visible: true

As described above, by default Capybara finds only visible elements.

  • find('.test1') finds the .test1 element
  • find('.test2') raises a Capybara::ElementNotFound error, as the .test2 element is not rendered.

Using find(...) means the same as find(..., visible: true) or find(..., visible: :visible).

Note that you could change the default behavior by setting the ignore_hidden_elements config option. However, ignoring invisible elements is a useful default.

Ignoring visibility with visible: :all or visible: false

If you want to access the hidden .test2 element, you can do so by supplying an option visible: :all.
Note that this only removes the visibility restriction, meaning:

  • find('.test1', visible: :all) finds the .test1 element
  • find('.test2', visible: :all) finds the .test2 element

Note that Capybara also supports visible: false as a synonym for visible: :all.
Since it is not always clear that visible: false means "both hidden and visible elements", I suggest you prefer :all over false.

Finding invisible elements with visible: :hidden

What if you want to test that .test1 is not visible? Use visible: :hidden

  • find('.test1', visible: :hidden) raises a Capybara::ElementNotFound error, as the .test1 element is not hidden.
  • find('.test2', visible: :hidden) finds the .test2 element

As an example, an RSpec test which tries to confirm an element exists but is currently not visible, would say:

expect(page).to have_css('.test2', visible: :hidden)
Posted by Arne Hartherz to makandra dev (2022-01-11 12:54)