-
-
Notifications
You must be signed in to change notification settings - Fork 395
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow satisfy
to match the block expectation return value
#1477
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,20 @@ Feature: `satisfy` matcher | |
end | ||
``` | ||
|
||
The `satisfy` matcher can also be used on block expectations to match the returned value of the block: | ||
|
||
```ruby | ||
expect { 2 + 2 }.to satisfy { |returned_value| returned_value == 4 } | ||
``` | ||
|
||
This comes handy to check both the side effects of the subject under test and its returned value: | ||
|
||
```ruby | ||
expect { request! } | ||
.to change { Log.count }.by(1) | ||
.and satisfy { |response| response.success? } | ||
``` | ||
|
||
@skip-when-ripper-unsupported | ||
Scenario: Basic usage | ||
Given a file named "satisfy_matcher_spec.rb" with: | ||
|
@@ -39,3 +53,20 @@ Feature: `satisfy` matcher | |
| expected 10 to satisfy expression `v > 15` | | ||
| expected 10 not to be greater than 5 | | ||
| expected 10 to be greater than 15 | | ||
|
||
@skip-when-ripper-unsupported | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you just copy this tag or check to see if it works without it? I'd expect it to work without it as its not matching source. |
||
Scenario: Matching the block expectation return value | ||
Given a file named "satisfy_matcher_returned_value_spec.rb" with: | ||
"""ruby | ||
RSpec.describe "double-purpose" do | ||
it "adds an entry and returns the sum" do | ||
ary = [1, 2, 3] | ||
expect { ary.shift } | ||
.to change { ary }.to([2, 3]) | ||
.and satisfy { |returned_value| returned_value == 1 } | ||
end | ||
end | ||
""" | ||
When I run `rspec satisfy_matcher_returned_value_spec.rb` | ||
Then the output should contain all of these: | ||
| 1 example, 0 failures | |
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -795,8 +795,9 @@ def respond_to(*names) | |||||||||||
alias_matcher :an_object_responding_to, :respond_to | ||||||||||||
alias_matcher :responding_to, :respond_to | ||||||||||||
|
||||||||||||
# Passes if the submitted block returns true. Yields target to the | ||||||||||||
# block. | ||||||||||||
# Passes if the submitted block returns true. | ||||||||||||
# For value expectations, yields target to the block. | ||||||||||||
# For block expectations, yields the expectation's returned value to the block. | ||||||||||||
Comment on lines
+798
to
+800
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
# | ||||||||||||
# Generally speaking, this should be thought of as a last resort when | ||||||||||||
# you can't find any other way to specify the behaviour you wish to | ||||||||||||
|
@@ -810,6 +811,10 @@ def respond_to(*names) | |||||||||||
# @example | ||||||||||||
# expect(5).to satisfy { |n| n > 3 } | ||||||||||||
# expect(5).to satisfy("be greater than 3") { |n| n > 3 } | ||||||||||||
# | ||||||||||||
# expect { ary.shift } | ||||||||||||
# .to change { ary }.to(be_empty) | ||||||||||||
# .and satisfy { |returned_value| returned_value == :last_on_the_list } | ||||||||||||
def satisfy(description=nil, &block) | ||||||||||||
BuiltIn::Satisfy.new(description, &block) | ||||||||||||
end | ||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -162,8 +162,13 @@ def initialize(actual, matcher_1, matcher_2) | |
|
||
inner, outer = order_block_matchers | ||
|
||
returned = nil | ||
@match_results[outer] = outer.matches?(Proc.new do |*args| | ||
@match_results[inner] = inner.matches?(inner_matcher_block(args)) | ||
p = Proc.new { |*args2| | ||
returned = inner_matcher_block(args).call(*args2) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to take care of ruby2 keywords (e.g. marked as such, not having keywords itself) so that they get passed through, I'm also a bit nervous about |
||
@match_results[inner] = inner.matches?(p) | ||
returned | ||
end) | ||
end | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -120,3 +120,54 @@ | |||||
end | ||||||
end | ||||||
end | ||||||
|
||||||
RSpec.describe "expect { ... }.to satisfy { block }" do | ||||||
it_behaves_like "an RSpec block matcher", :disallows_negation => true, :skip_deprecation_check => true do | ||||||
let(:matcher) { satisfy { |v| v == 1 } } | ||||||
before { @k = 0 } | ||||||
def valid_block | ||||||
1 | ||||||
end | ||||||
def invalid_block | ||||||
2 | ||||||
end | ||||||
end | ||||||
|
||||||
let(:ary) { [1, 2] } | ||||||
|
||||||
it "matches the returned value" do | ||||||
expect { ary.shift }.to satisfy { |returned_value| returned_value == 1 } | ||||||
end | ||||||
|
||||||
it "provides a sensible failure message", :skip => !RSpec::Support::RubyFeatures.ripper_supported? do | ||||||
expect { | ||||||
expect { ary.shift }.to satisfy { |returned_value| returned_value == :other } | ||||||
}.to fail_with("expected 1 to satisfy expression `returned_value == :other`") | ||||||
end | ||||||
|
||||||
context "when negated" do | ||||||
it "passes when the returned value doesn't match" do | ||||||
expect { ary.shift }.not_to satisfy { |returned_value| returned_value == 2 } | ||||||
end | ||||||
|
||||||
it "fails when the retuned value matches", :skip => !RSpec::Support::RubyFeatures.ripper_supported? do | ||||||
expect { | ||||||
expect { ary.shift }.not_to satisfy { |returned_value| returned_value == 1 } | ||||||
}.to fail_with("expected 1 not to satisfy expression `returned_value == 1`") | ||||||
end | ||||||
end | ||||||
|
||||||
describe "composed usage" do | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should follow on from the example group description
Suggested change
|
||||||
it "works as a root matcher" do | ||||||
expect { ary.shift }.to satisfy { |returned_value| returned_value == 1 }.and change { ary }.to([2]) | ||||||
end | ||||||
|
||||||
it "works as a supplemental matcher" do | ||||||
expect { ary.shift }.to change { ary }.to([2]).and satisfy { |returned_value| returned_value == 1 } | ||||||
end | ||||||
end | ||||||
|
||||||
pending "allows a matcher as an argument" do | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather not introduce pending specs unless its for something version specific, what needs to be done to make this work? |
||||||
expect { ary.shift }.to satisfy(eq(2)) | ||||||
end | ||||||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.