Skip to main content

chainable_custom_matchers

🔗 Creating Chainable Custom Matchers​

Chainable matchers let you build flexible expectations by adding extra qualifiers. You can define multiple chain blocks inside RSpec::Matchers.define to accept additional parameters and accumulate state before evaluating the final match block.

# spec/support/matchers/be_json_response.rb
RSpec::Matchers.define :be_json_response do
match do |response|
valid_json?(response.body) && status_ok?
end

chain(:with_status) do |expected_status|
@expected_status = expected_status
end

chain(:including) do |key|
@required_key = key
end

def valid_json?(body)
JSON.parse(body)
true
rescue JSON::ParserError
false
end

def status_ok?
return response.status == @expected_status if defined?(@expected_status)
response.status == 200
end

def matches_including_key?
@required_key.nil? || JSON.parse(response.body).key?(@required_key)
end

match do |response|
valid_json?(response.body) && status_ok? && matches_including_key?
end
end

Usage:

expect(response).to be_json_response.with_status(201).including('id')