I have a custom matcher in RSpec, that ignores whitespaces / newlines, and just matches content:
RSpec::Matchers.define :be_matching_content do |expected|
match do |actual|
actual.gsub(/\s/,'').should == expected.gsub(/\s/,'')
end
diffable
end
I can use it like this:
body = " some data \n more data"
body.should be_matching_content("some data\nmore wrong data")
However, when a test fails (like the one above), the diff output looks not good:
-some data
-more wrong data
+ some data
+ more data
Is it possible to configure the diffable output? The first line some data
is right, but the second more wrong data
is wrong. It would be very useful, to only get the second line as the root cause of the failure.
You can override the expected
and actual
methods that will then be used when generating the diff. In this example, we store the expected and actual values as instance variables and define methods that return the instance variables:
RSpec::Matchers.define :be_matching_content do |expected_raw|
match do |actual_raw|
@actual = actual_raw.gsub(/\s/,'')
@expected = expected_raw.gsub(/\s/,'')
expect(expected).to eq(@actual)
end
diffable
attr_reader :actual, :expected
end
Another example is to match for specific attributes in two different types of objects. (The expected object in this case is a Client
model.)
RSpec::Matchers.define :have_attributes_of_v1_client do |expected_client|
match do |actual_object|
@expected = client_attributes(expected_client)
@actual = actual_object.attributes
expect(actual_object).to have_attributes(@expected)
end
diffable
attr_reader :actual, :expected
def failure_message
"expected attributes of a V1 Client view row, but they do not match"
end
def client_attributes(client)
{
"id" => client.id,
"client_type" => client.client_type.name,
"username" => client.username,
"active" => client.active?,
}
end
end
Example failure looks like this:
Failure/Error: is_expected.to have_attributes_of_v1_client(client_active_partner)
expected attributes of a V1 Client view row, but they do not match
Diff:
@@ -1,6 +1,6 @@
"active" => true,
-"client_type" => #<ClientType id: 2, name: "ContentPartner">,
+"client_type" => "ContentPartner",
"id" => 11,
I believe you should disable default diffable
behaviour in RSpec and substitute your own implementation:
RSpec::Matchers.define :be_matching_content do |expected|
match do |actual|
@stripped_actual = actual.gsub(/\s/,'')
@stripped_expected = expected.gsub(/\s/,'')
expect(@stripped_actual).to eq @stripped_expected
end
failure_message do |actual|
message = "expected that #{@stripped_actual} would match #{@stripped_expected}"
message += "\nDiff:" + differ.diff_as_string(@stripped_actual, @stripped_expected)
message
end
def differ
RSpec::Support::Differ.new(
:object_preparer => lambda { |object| RSpec::Matchers::Composable.surface_descriptions_in(object) },
:color => RSpec::Matchers.configuration.color?
)
end
end
RSpec.describe 'something'do
it 'should diff correctly' do
body = " some data \n more data"
expect(body).to be_matching_content("some data\nmore wrong data")
end
end
produces the following:
Failures:
1) something should diff correctly
Failure/Error: expect(body).to be_matching_content("some data\nmore wrong data")
expected that somedatamoredata would match somedatamorewrongdata
Diff:
@@ -1,2 +1,2 @@
-somedatamorewrongdata
+somedatamoredata
You can use custom differ if you want, even reimplement this whole matcher to a system call to diff
command, something like this:
♥ diff -uw --label expected --label actual <(echo " some data \n more data") <(echo "some data\nmore wrong data")
--- expected
+++ actual
@@ -1,2 +1,2 @@
some data
- more data
+more wrong data
Cheers!
There is a gem called diffy which can be used.
But it goes through a string line by line and compares them so instead of removing all whitespace you could replace any amount of whitespace with a newline and diff those entries.
This is an example of something you could do to improve your diffs a little bit. I am not 100% certain about where to insert this into your code.
def compare(str1, str2)
str1 = break_string(str1)
str2 = break_string(str2)
return true if str1 == str2
puts Diffy::Diff.new(str1, str2).to_s
return false
end
def break_string(str)
str.gsub(/\s+/,"\n")
end
The diffy gem can be set to produce color output suitable for the terminal.
Using this code would work like this
str1 = 'extra some content'
str2 = 'extra more content'
puts compare(str1, str2)
this would print
extra
-some # red in terminal
+more # green in terminal
content
\ No newline at end of file
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With