rspec-expectations icon indicating copy to clipboard operation
rspec-expectations copied to clipboard

Compound failure messages with more than 2 matchers are wrongly indented

Open yujinakayama opened this issue 10 years ago • 4 comments

Running the following spec:

describe 'compound expectation' do
  context 'with 2 matchers' do
    it 'indents the messages properly' do
      expect { :nothing }
        .to  change { @foo }
        .and change { @bar }
    end
  end

  context 'with 3 matchers' do
    it 'indents the messages wrongly' do
      expect { :nothing }
        .to  change { @foo }
        .and change { @bar }
        .and change { @baz }
    end
  end
end

... outputs the following messages:

Failures:

  1) compound expectation with 2 matchers indents the messages properly
     Failure/Error:
       expect { :nothing }
         .to  change { @foo }
         .and change { @bar }

          expected result to have changed, but is still nil

       ...and:

          expected result to have changed, but is still nil
     # ./spec/test_spec.rb:4:in `block (3 levels) in <top (required)>'

  2) compound expectation with 3 matchers indents the messages wrongly
     Failure/Error:
       expect { :nothing }
         .to  change { @foo }
         .and change { @bar }
         .and change { @baz }

          expected result to have changed, but is still nil

       ...and:

             expected result to have changed, but is still nil

          ...and:

             expected result to have changed, but is still nil
     # ./spec/test_spec.rb:12:in `block (3 levels) in <top (required)>'

Finished in 0.02502 seconds (files took 0.13832 seconds to load)
2 examples, 2 failures

yujinakayama avatar Nov 17 '15 06:11 yujinakayama

This is working as designed. The nesting intentionally mirrors the grouping. In the expression:

expect { :nothing }
         .to  change { @foo }
         .and change { @bar }
         .and change { @baz }

...the ordering of ruby's evaluation causes this equivalent to be created:

Compound::And.new(
  Change.new { @foo },
  Compound::And.new(
    Change.new { @bar },
    Change.new { @baz }
  )
)

...and the failure output mirrors that structure. Now, in the case of just and or just or, it's associative, so that A & (B & C) and (A & B) & C are equivalent (and some with the ||). So we could flatten the failure output for these cases.

But if you're mixing and and or:

expect { :nothing }
         .to  change { @foo }
         .and(change { @bar }
         .or change { @baz })

or:

expect { :nothing }
         .to (change { @foo }
         .and change { @bar })
         .or change { @baz }

...then it's not associative, the grouping very much matters, and I think it's important that the failure output mirrors the structure.

There might be a simple way to get the flattened output for when the user is using all and or all or, but for the general case I think we need to keep the nested output format.

myronmarston avatar Nov 17 '15 08:11 myronmarston

...then it's not associative, the grouping very much matters, and I think it's important that the failure output mirrors the structure.

That makes sense.

There might be a simple way to get the flattened output for when the user is using all and or all or, but for the general case I think we need to keep the nested output format.

:+1:

yujinakayama avatar Nov 17 '15 12:11 yujinakayama

Close?

JonRowe avatar Nov 17 '15 22:11 JonRowe

There might be a simple way to get the flattened output for when the user is using all and or all or

I think I will try implementing this.

yujinakayama avatar Nov 18 '15 03:11 yujinakayama

Closing due to inactivity during the monorepo migration

JonRowe avatar Nov 27 '24 21:11 JonRowe