I have the following expectation in a feature spec (pretty low-level but still necessary):
expect(Addressable::URI.parse(current_url).query_values).to include(
'some => 'value',
'some_other' => String
)
Note the second query value is a fuzzy match because I just want to make sure it's there but I can't be more specific about it.
I'd like to extract this into a custom matcher. I started with:
RSpec::Matchers.define :have_query_params do |expected_params|
match do |url|
Addressable::URI.parse(url).query_values == expected_params
end
end
but this means I cannot pass {'some_other' => String}
in there. To keep using a fuzzy match, I'd have to use the include
matcher in my custom matcher.
However, anything within RSpec::Matchers::BuiltIn
is marked as private API, and Include
specifically is documented as:
# Provides the implementation for `include`.
# Not intended to be instantiated directly.
So, my question is: Is using a built-in matcher within a custom matcher supported in RSpec? How would I do that?
RSpec::Matchers
appears to be a supported API (its rdoc doesn't say otherwise), so you can write your matcher in Ruby instead of in the matcher DSL (which is supported; see the second paragraph of the custom matcher documentation) and use RSpec::Matchers#include
like this:
spec/support/matchers.rb
module My
module Matchers
def have_query_params(expected)
HasQueryParams.new expected
end
class HasQueryParams
include RSpec::Matchers
def initialize(expected)
@expected = expected
end
def matches?(url)
actual = Addressable::URI.parse(url).query_values
@matcher = include @expected
@matcher.matches? actual
end
def failure_message
@matcher.failure_message
end
end
end
end
spec/support/matcher_spec.rb
include My::Matchers
describe My::Matchers::HasQueryParams do
it "matches" do
expect("http://example.com?a=1&b=2").to have_query_params('a' => '1', 'b' => '2')
end
end