rspec-expectations
rspec-expectations copied to clipboard
Output chained matchers description
Subject of the issue
I've created a custom matcher which allows to chain other matchers against a computed value :
matcher :have_html_body do
chain :to, :other_matcher
match do |actual|
@actual = actual.parsed_body
html_body_valid?(@actual) && other_matcher_matches?(@actual)
end
def other_matcher_matches?(actual)
other_matcher.nil? || other_matcher.matches?(actual)
end
end
I can then chain any matchers to match the parsed body :
expect(response).to have_html_body.to include("Hello World")
expect(response).to have_html_body.to match(/hello/)
expect(response).to have_html_body.to have_selector("#test", text: "Hello World")
It works fine, but descriptions are cumbersome :
is expected to have html body to #<RSpec::Matchers::BuiltIn::Include:0x0000000108887c10 [...long output...]>
is expected to have html body to #<RSpec::Matchers::BuiltIn::Match:0x000000010f476228 [...long output...]>
is expected to have html body to #<Capybara::RSpecMatchers::Matchers::HaveText:0x0000000140b35fd8 [...long output...]>
Expected behavior
It should generate a readable description :
is expected to have html body to include "Hello World"
is expected to have html body to match /hello/
is expected to have html body to have visible css "#test" with text "Hello World"
Your environment
- Ruby 3.2.2
- rspec 3.12.0
- rspec-expectations 3.12.3
- rspec-support 3.12.1
config.include_chain_clauses_in_custom_matcher_descriptions is already set to true
Investigation
There are 3 methods involved to generate chained description :
RSpec::Matchers::DSL#chained_method_clause_sentencesRSpec::Matchers::EnglishPhrasing#listRSpec::Support::ObjectFormatter.format
I'm not sure which one is the most relevant to fix the issue but my guess is EnglishPhrasing. Something like :
def self.list(obj)
return " #{RSpec::Support::ObjectFormatter.format(obj)}" if !obj || Struct === obj || Hash === obj
- items = Array(obj).map { |w| RSpec::Support::ObjectFormatter.format(w) }
+ items = Array(obj).map { |w| w.is_a?(RSpec::Matchers::Composable) ? w.description : RSpec::Support::ObjectFormatter.format(w) }