diff --git a/Changelog.md b/Changelog.md index 10a7b736d..c9630b9be 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,6 +5,7 @@ Breaking Changes: * Ruby < 2.3 is no longer supported. (Phil Pirozhkov, #1231) * Remove `should` and `should_not` syntax (including one-liners). (Phil Pirozhkov, #1245) +* Turn `strict_predicate_matchers` on by default. (Phil Pirozhkov, #1277) Enhancements: diff --git a/features/built_in_matchers/predicates.feature b/features/built_in_matchers/predicates.feature index 41d78abe1..4107da849 100644 --- a/features/built_in_matchers/predicates.feature +++ b/features/built_in_matchers/predicates.feature @@ -39,7 +39,7 @@ Feature: Predicate matchers In either case, RSpec provides nice, clear error messages, such as: - `expected zero? to be truthy, got false` + `expected zero? to return true, got false` Calling private methods will also fail: @@ -60,7 +60,7 @@ Feature: Predicate matchers """ When I run `rspec be_zero_spec.rb` Then the output should contain "2 examples, 1 failure" - And the output should contain "expected `7.zero?` to be truthy, got false" + And the output should contain "expected `7.zero?` to return true, got false" Scenario: is_expected.not_to be_empty (based on Array#empty?) Given a file named "not_to_be_empty_spec.rb" with: @@ -75,7 +75,7 @@ Feature: Predicate matchers """ When I run `rspec not_to_be_empty_spec.rb` Then the output should contain "2 examples, 1 failure" - And the output should contain "expected `[].empty?` to be falsey, got true" + And the output should contain "expected `[].empty?` to return false, got true" Scenario: is_expected.to have_key (based on Hash#has_key?) Given a file named "have_key_spec.rb" with: @@ -88,7 +88,7 @@ Feature: Predicate matchers """ When I run `rspec have_key_spec.rb` Then the output should contain "2 examples, 1 failure" - And the output should contain "expected `{:foo=>7}.has_key?(:bar)` to be truthy, got false" + And the output should contain "expected `{:foo=>7}.has_key?(:bar)` to return true, got false" Scenario: is_expected.to have_decimals (based on custom #have_decimals? method) Given a file named "have_decimals_spec.rb" with: @@ -114,7 +114,7 @@ Feature: Predicate matchers """ When I run `rspec have_decimals_spec.rb` Then the output should contain "2 examples, 1 failure" - And the output should contain "expected `42.0.has_decimals?` to be truthy, got false" + And the output should contain "expected `42.0.has_decimals?` to return true, got false" Scenario: matcher arguments are passed on to the predicate method Given a file named "predicate_matcher_argument_spec.rb" with: @@ -136,8 +136,8 @@ Feature: Predicate matchers """ When I run `rspec predicate_matcher_argument_spec.rb` Then the output should contain "4 examples, 2 failures" - And the output should contain "expected `12.multiple_of?(4)` to be falsey, got true" - And the output should contain "expected `12.multiple_of?(5)` to be truthy, got false" + And the output should contain "expected `12.multiple_of?(4)` to return false, got true" + And the output should contain "expected `12.multiple_of?(5)` to return true, got false" Scenario: the config `strict_predicate_matchers` impacts matching of results other than `true` and `false` Given a file named "strict_or_not.rb" with: @@ -159,14 +159,14 @@ Feature: Predicate matchers end end - context 'with non-strict matchers (default)' do - let(:strict) { false } + context 'with strict matchers (default)' do + let(:strict) { true } + # deliberate failure it { is_expected.to have_strange_result } end - context 'with strict matchers' do - let(:strict) { true } - # deliberate failure + context 'with non-strict matchers' do + let(:strict) { false } it { is_expected.to have_strange_result } end end diff --git a/features/test_frameworks/minitest.feature b/features/test_frameworks/minitest.feature index 164ef841f..687a82be0 100644 --- a/features/test_frameworks/minitest.feature +++ b/features/test_frameworks/minitest.feature @@ -47,7 +47,7 @@ Feature: Minitest integration """ When I run `ruby rspec_expectations_test.rb` Then the output should contain "4 runs, 5 assertions, 2 failures, 0 errors" - And the output should contain "expected `[1, 2].empty?` to be truthy, got false" + And the output should contain "expected `[1, 2].empty?` to return true, got false" And the output should contain "be_an_int is deprecated" And the output should contain "Got 2 failures from failure aggregation block" @@ -105,7 +105,7 @@ Feature: Minitest integration """ When I run `ruby rspec_expectations_spec.rb` Then the output should contain "9 runs, 10 assertions, 5 failures, 0 errors" - And the output should contain "expected `[1, 2].empty?` to be truthy, got false" + And the output should contain "expected `[1, 2].empty?` to return true, got false" And the output should contain "expected ZeroDivisionError but nothing was raised" And the output should contain "Got 2 failures from failure aggregation block" And the output should contain "Expected [1, 2] to be empty?" diff --git a/lib/rspec/expectations/configuration.rb b/lib/rspec/expectations/configuration.rb index ddfbb5313..42f81d419 100644 --- a/lib/rspec/expectations/configuration.rb +++ b/lib/rspec/expectations/configuration.rb @@ -26,7 +26,7 @@ class Configuration def initialize @on_potential_false_positives = :warn - @strict_predicate_matchers = false + @strict_predicate_matchers = true end # Configures the maximum character length that RSpec will print while @@ -126,9 +126,9 @@ def on_potential_false_positives=(behavior) @on_potential_false_positives = behavior end - # Configures RSpec to check predicate matchers to `be(true)` / `be(false)` (strict), - # or `be_truthy` / `be_falsey` (not strict). - # Historically, the default was `false`, but `true` is recommended. + # Configures RSpec to check the values returned by predicate matchers + # to be exactly true/false (strict), or truthy/falsey (not strict). + # Before RSpec 4, the default was `false`. def strict_predicate_matchers=(flag) raise ArgumentError, "Pass `true` or `false`" unless flag == true || flag == false @strict_predicate_matchers = flag diff --git a/spec/rspec/expectations/configuration_spec.rb b/spec/rspec/expectations/configuration_spec.rb index 59ced1c05..700881430 100644 --- a/spec/rspec/expectations/configuration_spec.rb +++ b/spec/rspec/expectations/configuration_spec.rb @@ -61,6 +61,23 @@ class << rspec_dup; undef configuration; end end end + describe "#strict_predicate_matchers?" do + it "is true by default" do + expect(config.strict_predicate_matchers?).to be(true) + end + + it "can be set to false" do + config.strict_predicate_matchers = false + expect(config.strict_predicate_matchers?).to be(false) + end + + it "can be set back to true" do + config.strict_predicate_matchers = false + config.strict_predicate_matchers = true + expect(config.strict_predicate_matchers?).to be(true) + end + end + describe "#max_formatted_output_length=" do before do @orig_max_formatted_output_length = RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length diff --git a/spec/rspec/matchers/built_in/has_spec.rb b/spec/rspec/matchers/built_in/has_spec.rb index fbb128bc9..4a437d129 100644 --- a/spec/rspec/matchers/built_in/has_spec.rb +++ b/spec/rspec/matchers/built_in/has_spec.rb @@ -131,7 +131,7 @@ def o.has_sym?(sym); sym == :foo; end expect({ :a => "A" }).not_to have_key(:b) end - context "when strict_predicate_matchers is set to true" do + context "when strict_predicate_matchers is set to true", with_configuration: {strict_predicate_matchers: true} do it "fails when #has_sym? returns nil" do actual = double("actual", :has_foo? => nil) expect { @@ -140,13 +140,7 @@ def o.has_sym?(sym); sym == :foo; end end end - context "when strict_predicate_matchers is set to false" do - around do |example| - RSpec::Expectations.configuration.strict_predicate_matchers = false - example.run - RSpec::Expectations.configuration.strict_predicate_matchers = true - end - + context "when strict_predicate_matchers is set to false", with_configuration: {strict_predicate_matchers: false} do it "passes if #has_sym?(*args) returns nil" do actual = double("actual", :has_foo? => nil) expect(actual).not_to have_foo diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2a64f429d..039537205 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -40,7 +40,6 @@ def hash_inspect(hash) config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true - expectations.strict_predicate_matchers = true end config.mock_with :rspec do |mocks| @@ -70,6 +69,23 @@ def hash_inspect(hash) end RSpec.configuration.include_context "with warn_about_potential_false_positives set to false", :warn_about_potential_false_positives +RSpec.shared_context "with modified configuration" do + around do |example| + configuration = example.metadata[:with_configuration] + original = configuration.keys.each.with_object({}) do |key, config| + config[key] = RSpec::Expectations.configuration.public_send(key) + end + configuration.each do |key, value| + RSpec::Expectations.configuration.public_send("#{key}=", value) + end + example.run + original.each do |key, value| + RSpec::Expectations.configuration.public_send("#{key}=", value) + end + end +end +RSpec.configuration.include_context "with modified configuration", :with_configuration + module MinitestIntegration include ::RSpec::Support::InSubProcess