I've extended the existing card with more examples of the same pitfall where Capybara spends much time waiting for nothing than needed.
Changes
- Element finding is a central feature of Capybara. Since `#find` is normally used to get elements from the current page and interact with them, it's a good thing that some Capybara drivers (e.g. Selenium) will wait an amount of time until the expected element shows up. But if Capybara cannot `#find` it at all, you'll get an error.
- ```ruby
- if page.find('.that-element')
- # Do something
- else
- # Never happens because #find raises
- end
- ```
-In order to simply check whether an element is present, without errors raised, you can use `#has_css?`. It will return a Boolean – but will wait as well. If the element _does not_ exist, it will take the configured `Capybara.default_wait_time` for this check to return `false`, which is usually several seconds.- +In order to simply check whether an element is present, without errors raised, you can use `#has_css?`. It will return a Boolean – but will wait as well. If the element *does not* exist, it will take the configured `Capybara.default_max_wait_time` for this check to return `false`, which is usually several seconds.
- +
- +The same goes for the other direction and for `#all`:
- +
- +- `has_no_css?` returns `true` as soon as the element is gone, but `false` only after the full wait time if the element is there.
- +- Since Capybara 3, `all` waits for a first match, so `all('.that-element').empty?` takes the full wait time whenever nothing matches.
- +
- +In a shared helper that branches on the state of the page, this quickly adds up to minutes per test run.
- +
- The solution is to disable the waiting for just that check:
- ```ruby
- if page.has_css?('.that-element', wait: 0)
- # Do something
- else
- # Do something else
- end
- +
- +page.has_no_css?('.that-element', wait: 0)
- +page.all('.that-element', wait: false).empty?
- ```
-> [important]- +> [!IMPORTANT]
- > If you opt-out of Capybara's retry mechanism you need to retry yourself or your test will be flaky.
-Note the `wait: 0` argument. Actually there is [a host of options](https://www.rubydoc.info/github/jnicklas/capybara/Capybara/Node/Finders#all-instance_method) worth knowing (scroll down to the "Options Hash" section).- +..or use a pre-existing matcher depending on your use case:
- +
- +```rb
- +expect(page).to have_no_css('.that-element') # ✅ returns as soon as the element is gone
- +expect(page.has_css?('.that-element')).to eq(false) # ❌ waits the full time whenever it passes
- +```
- +
- +Note the `wait: 0` argument. Actually there is [a host of options](https://www.rubydoc.info/github/jnicklas/capybara/Capybara/Node/Finders#all-instance_method) worth knowing (scroll down to the "Options Hash" section).
Posted by Michael Leimstädtner to makandra dev (2026-10-19 11:47)