Chaining Capybara matchers in RSpec

Posted . Visible to the public. Repeats.

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')

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
Henning Koch
Last edit
Dennis
License
Source code in this card is licensed under the MIT License.
Posted by Henning Koch to makandra dev (2024-03-07 07:50)