Read more

Chaining Capybara matchers in RSpec

Henning Koch
March 07, 2024Software engineer at makandra GmbH

You can chain multiple Capybara matchers Show archive.org snapshot on the page or any element:

expect(page)
  .to have_content('Example Course')
  .and have_css('.course.active')
  .and have_button('Start')
Illustration online protection

Rails professionals since 2007

Our laser focus on a single technology has made us a leader in this space. Need help?

  • We build a solid first version of your product
  • We train your development team
  • We rescue your project in trouble
Read more Show archive.org snapshot

When you chain multiple matchers using and, Capybara will retry the entire chain Show archive.org snapshot if any of the matchers fail.

This helps when browser state changes between expectations, e.g. by async JavaScript that mutates the DOM tree while you're making multiple observations.

Custom matchers must be retryable

For Capybara to be able to retry chain, any custom matchers must be able to re-run their match block.

Here is a ❌ bad example of a matcher that memoizes its observation (in #actual_state) and cannot be retried:

RSpec::Matchers.define :have_state do |expected_state|

  match do |element|
    actual_state(element) == expected_state
  end
  
  failure_message do
    "expected state to be #{expected_state}, but was #{actual_state(element)}"
  end

  def actual_state(element)
    @actual_state ||= element['data-state']
  end

end
Posted by Henning Koch to makandra dev (2024-03-07 08:50)