Skip to content

Commit

Permalink
Add ability to inspect all describable matchers
Browse files Browse the repository at this point in the history
In a previous commit, a new inspection tree builder was added which
was designed to handle built-in RSpec matchers as well as matchers
created via the matcher DSL, by reusing the `description` of the matcher
as the inspection text. However, this inspector did not cover custom
matchers defined from scratch rather than via the DSL. This commit
corrects this by making use of the `is_a_describable_matcher?` method
from RSpec::Matchers.
  • Loading branch information
mcmire committed Feb 10, 2024
1 parent 5700196 commit 6b71778
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 94 deletions.
2 changes: 1 addition & 1 deletion lib/super_diff/rspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def self.rspec_version
ObjectInspection::InspectionTreeBuilders::ObjectHavingAttributes,
# ObjectInspection::InspectionTreeBuilders::Primitive,
ObjectInspection::InspectionTreeBuilders::ValueWithin,
ObjectInspection::InspectionTreeBuilders::RSpecMatcher
ObjectInspection::InspectionTreeBuilders::GenericDescribableMatcher
)
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ module InspectionTreeBuilders
:Double,
"super_diff/rspec/object_inspection/inspection_tree_builders/double"
)
autoload(
:GenericDescribableMatcher,
"super_diff/rspec/object_inspection/inspection_tree_builders/generic_describable_matcher"
)
autoload(
:HashIncluding,
"super_diff/rspec/object_inspection/inspection_tree_builders/hash_including"
Expand All @@ -34,10 +38,6 @@ module InspectionTreeBuilders
:Primitive,
"super_diff/rspec/object_inspection/inspection_tree_builders/primitive"
)
autoload(
:RSpecMatcher,
"super_diff/rspec/object_inspection/inspection_tree_builders/rspec_matcher"
)
autoload(
:ValueWithin,
"super_diff/rspec/object_inspection/inspection_tree_builders/value_within"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ module SuperDiff
module RSpec
module ObjectInspection
module InspectionTreeBuilders
class RSpecMatcher < SuperDiff::ObjectInspection::InspectionTreeBuilders::Base
class GenericDescribableMatcher < SuperDiff::ObjectInspection::InspectionTreeBuilders::Base
def self.applies_to?(value)
value.is_a?(::RSpec::Matchers::BuiltIn::BaseMatcher) ||
value.is_a?(::RSpec::Matchers::DSL::Matcher)
::RSpec::Matchers.is_a_describable_matcher?(value)
end

def call
Expand Down
177 changes: 177 additions & 0 deletions spec/integration/rspec/generic_describable_matchers_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
require "spec_helper"

RSpec.describe "Integration with describable matchers not handled specially",
type: :integration do
context "when the expected value contains a built-in matcher (not an aliased matcher)" do
it "produces the correct failure message when used in the positive" do
as_both_colored_and_uncolored do |color_enabled|
snippet = <<~TEST.strip
actual = {
number: "not a number"
}
expected = hash_including(
number: be_a(Numeric)
)
expect(actual).to match(expected)
TEST
program = make_plain_test_program(snippet, color_enabled: color_enabled)

expected_output =
build_expected_output(
color_enabled: color_enabled,
snippet: "expect(actual).to match(expected)",
expectation:
proc do
line do
plain "Expected "
actual %|{ number: "not a number" }|
plain " to match "
expected "#<a hash including (number: #<be a kind of Numeric>)>"
plain "."
end
end,
diff:
proc do
plain_line " {"
expected_line "- number: #<be a kind of Numeric>"
actual_line %|+ number: "not a number"|
plain_line " }"
end
)

expect(program).to produce_output_when_run(expected_output).in_color(
color_enabled
)
end
end

it "produces the correct failure message when used in the negative" do
as_both_colored_and_uncolored do |color_enabled|
snippet = <<~TEST.strip
actual = {
number: 4
}
expected = hash_including(
number: be_a(Numeric)
)
expect(actual).not_to match(expected)
TEST
program = make_plain_test_program(snippet, color_enabled: color_enabled)

expected_output =
build_expected_output(
color_enabled: color_enabled,
snippet: "expect(actual).not_to match(expected)",
expectation:
proc do
line do
plain "Expected "
actual "{ number: 4 }"
plain " not to match "
expected "#<a hash including (number: #<be a kind of Numeric>)>"
plain "."
end
end
)

expect(program).to produce_output_when_run(expected_output).in_color(
color_enabled
)
end
end
end

context "when the expected value contains a custom matcher defined via RSpec::Matchers::DSL" do
it "produces the correct failure message" do
as_both_colored_and_uncolored do |color_enabled|
snippet = <<~TEST.strip
actual = {
number: "something else"
}
expected = hash_including(
number: failing_custom_matcher_from_dsl(42)
)
expect(actual).to match(expected)
TEST
program = make_plain_test_program(snippet, color_enabled: color_enabled)

expected_output =
build_expected_output(
color_enabled: color_enabled,
snippet: "expect(actual).to match(expected)",
newline_before_expectation: true,
expectation:
proc do
line do
plain "Expected "
actual %|{ number: "something else" }|
end

line do
plain "to match "
expected "#<a hash including (number: #<custom matcher defined via the DSL with value 42>)>"
end
end,
diff:
proc do
plain_line " {"
expected_line "- number: #<custom matcher defined via the DSL with value 42>"
actual_line %|+ number: "something else"|
plain_line " }"
end
)

expect(program).to produce_output_when_run(expected_output).in_color(
color_enabled
)
end
end
end

context "when the expected value contains a custom matcher defined from scratch" do
it "produces the correct failure message" do
as_both_colored_and_uncolored do |color_enabled|
snippet = <<~TEST.strip
actual = {
number: "something else"
}
expected = hash_including(
number: failing_custom_matcher_from_scratch(42)
)
expect(actual).to match(expected)
TEST
program = make_plain_test_program(snippet, color_enabled: color_enabled)

expected_output =
build_expected_output(
color_enabled: color_enabled,
snippet: "expect(actual).to match(expected)",
newline_before_expectation: true,
expectation:
proc do
line do
plain "Expected "
actual %|{ number: "something else" }|
end

line do
plain "to match "
expected "#<a hash including (number: #<custom matcher defined from scratch with value 42>)>"
end
end,
diff:
proc do
plain_line " {"
expected_line "- number: #<custom matcher defined from scratch with value 42>"
actual_line %|+ number: "something else"|
plain_line " }"
end
)

expect(program).to produce_output_when_run(expected_output).in_color(
color_enabled
)
end
end
end
end
86 changes: 0 additions & 86 deletions spec/integration/rspec/unhandled_matcher_spec.rb

This file was deleted.

34 changes: 34 additions & 0 deletions spec/support/integration/matchers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,40 @@ def pass_with_singleline_failure_message
PassWithSinglelineFailureMessageMatcher.new
end

RSpec::Matchers.define :failing_custom_matcher_from_dsl do |value|
match { false }

description do
"custom matcher defined via the DSL with value #{value.inspect}"
end
end

def failing_custom_matcher_from_scratch(value)
FailingCustomMatcherFromScratch.new(value)
end

class FailingCustomMatcherFromScratch
def initialize(value)
@value = value
end

def matches?(_)
false
end

def description
"custom matcher defined from scratch with value #{value.inspect}"
end

def failure_message
"Expected custom matcher not to fail, but did"
end

private

attr_reader :value
end

class FailWithIndentedMultilineFailureMessageMatcher
def matches?(_)
false
Expand Down

0 comments on commit 6b71778

Please sign in to comment.