From eb7929b6d0f66633880eac3fcc87edee39a26e1a Mon Sep 17 00:00:00 2001 From: Yudai Takada Date: Thu, 13 Jun 2024 08:18:15 +0900 Subject: [PATCH 01/40] Fix to upgrade_to_version_3.adoc This PR is fixes about the .rubocop.yml changes for migration v3. --- docs/modules/ROOT/pages/upgrade_to_version_3.adoc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/upgrade_to_version_3.adoc b/docs/modules/ROOT/pages/upgrade_to_version_3.adoc index d0ad8adfd..7ce7dc7f2 100644 --- a/docs/modules/ROOT/pages/upgrade_to_version_3.adoc +++ b/docs/modules/ROOT/pages/upgrade_to_version_3.adoc @@ -25,8 +25,9 @@ end [source,yaml] ---- -Capybara: - Enabled: true +require: + - rubocop-rspec + - rubocop-capybara ---- And you need to remove the old department in your `.rubocop.yml` file: From e6106a32edd6088be4e13d34c172b86d83fcb561 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Thu, 13 Jun 2024 09:08:57 +0200 Subject: [PATCH 02/40] [Fix #1913] Fix broken autocorrect for `RSpec/ScatteredSetup` when block contains heredoc Autocorrect previously looked like this which not correct syntax: ```rb describe Foo do before { foo bar(<<~TEXT) } end ``` The block source doesn't contain the heredoc source: For more details see https://github.com/rubocop/rubocop-ast/issues/293 --- CHANGELOG.md | 2 + lib/rubocop/cop/rspec/scattered_setup.rb | 8 +++- .../rubocop/cop/rspec/scattered_setup_spec.rb | 39 +++++++++++++++---- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1996901a9..644219220 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Fix wrong autocorrect for `RSpec/ScatteredSetup` when hook contains heredoc. ([@earlopain]) + ## 3.0.1 (2024-06-11) - Bump RuboCop requirement to +1.61. ([@ydah]) diff --git a/lib/rubocop/cop/rspec/scattered_setup.rb b/lib/rubocop/cop/rspec/scattered_setup.rb index cd23e02d3..56a0444ff 100644 --- a/lib/rubocop/cop/rspec/scattered_setup.rb +++ b/lib/rubocop/cop/rspec/scattered_setup.rb @@ -23,6 +23,7 @@ module RSpec # end # class ScatteredSetup < Base + include FinalEndLocation include RangeHelp extend AutoCorrector @@ -75,8 +76,13 @@ def message(occurrences, occurrence) def autocorrect(corrector, first_occurrence, occurrence) return if first_occurrence == occurrence || !first_occurrence.body + # Take heredocs into account + body = occurrence.body&.source_range&.with( + end_pos: final_end_location(occurrence).begin_pos + ) + corrector.insert_after(first_occurrence.body, - "\n#{occurrence.body&.source}") + "\n#{body&.source}") corrector.remove(range_by_whole_lines(occurrence.source_range, include_final_newline: true)) end diff --git a/spec/rubocop/cop/rspec/scattered_setup_spec.rb b/spec/rubocop/cop/rspec/scattered_setup_spec.rb index 09a297465..7e9afea79 100644 --- a/spec/rubocop/cop/rspec/scattered_setup_spec.rb +++ b/spec/rubocop/cop/rspec/scattered_setup_spec.rb @@ -14,7 +14,7 @@ expect_correction(<<~RUBY) describe Foo do before { bar - baz } + baz } end RUBY end @@ -34,8 +34,8 @@ expect_correction(<<~RUBY) describe Foo do after { bar - baz - baz } + baz#{' '} + baz } end RUBY end @@ -53,7 +53,7 @@ expect_correction(<<~RUBY) describe Foo do before(:all) { bar - baz } + baz } end RUBY end @@ -143,9 +143,9 @@ expect_correction(<<~RUBY) describe Foo do before(:each, :special_case) { foo - bar - bar - bar } + bar#{' '} + bar#{' '} + bar } before(:example, special_case: false) { bar } end RUBY @@ -168,4 +168,29 @@ end RUBY end + + it 'flags hooks that contain heredoc arguments and autocorrects correctly' do + expect_offense(<<~RUBY) + describe Foo do + before { foo } + ^^^^^^^^^^^^^^ Do not define multiple `before` hooks in the same example group (also defined on line 3). + before do + ^^^^^^^^^ Do not define multiple `before` hooks in the same example group (also defined on line 2). + bar(<<~'TEXT') + Hello World! + TEXT + end + end + RUBY + + expect_correction(<<~RUBY) + describe Foo do + before { foo + bar(<<~'TEXT') + Hello World! + TEXT + } + end + RUBY + end end From fb290efb3f171c70de9f0b6f7399da356810558a Mon Sep 17 00:00:00 2001 From: Yudai Takada Date: Thu, 13 Jun 2024 13:36:50 +0900 Subject: [PATCH 03/40] Add link to "Upgrade to Version 3.x" in README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 2f8b38ec8..22e88af40 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,10 @@ or if you use bundler put this in your `Gemfile` gem 'rubocop-rspec', require: false ``` +### Upgrading to RuboCop RSpec v3.x + +Read all the details in our [Upgrade to Version 3.x](https://docs.rubocop.org/rubocop-rspec/3.0/upgrade_to_version_3.html) document. + ### Upgrading to RuboCop RSpec v2.x Read all the details in our [Upgrade to Version 2.x](https://docs.rubocop.org/rubocop-rspec/2.0/upgrade_to_version_2.html) document. From dc309440a85e99ff692d3c612c9beba8e7b6ca70 Mon Sep 17 00:00:00 2001 From: ydah Date: Sun, 16 Jun 2024 10:57:32 +0900 Subject: [PATCH 04/40] Add table of contents in README --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 22e88af40..61b5ff355 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,15 @@ [RSpec](https://rspec.info/)-specific analysis for your projects, as an extension to [RuboCop](https://github.com/rubocop/rubocop). +- [Installation](#installation) + - [Upgrading to RuboCop RSpec v3.x](#upgrading-to-rubocop-rspec-v3x) + - [Upgrading to RuboCop RSpec v2.x](#upgrading-to-rubocop-rspec-v2x) +- [Usage](#usage) +- [Documentation](#documentation) +- [The Cops](#the-cops) +- [Contributing](#contributing) +- [License](#license) + ## Installation Just install the `rubocop-rspec` gem From 5fd12281e7acd22bc29f33c34c5b1612b1c2a5dd Mon Sep 17 00:00:00 2001 From: Brendan Mulholland Date: Tue, 18 Jun 2024 16:58:52 +0200 Subject: [PATCH 05/40] chore(docs): Gem names and troubleshooting for v3 migration instructions --- docs/modules/ROOT/pages/upgrade_to_version_3.adoc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/upgrade_to_version_3.adoc b/docs/modules/ROOT/pages/upgrade_to_version_3.adoc index 7ce7dc7f2..75b9066ee 100644 --- a/docs/modules/ROOT/pages/upgrade_to_version_3.adoc +++ b/docs/modules/ROOT/pages/upgrade_to_version_3.adoc @@ -10,7 +10,11 @@ In version 3.x: [discrete] === Extraction of cop departments. (`Capybara`, `FactoryBot`, `Rails`) -If you are using the RSpec/Capybara, RSpec/FactoryBot, or RSpec/Rails departments, you need to install the corresponding gem and add it to your `.rubocop.yml` file. +If you are using the RSpec/Capybara, RSpec/FactoryBot, or RSpec/Rails departments -- or have one in a `require` list in your rubocop.yml -- you need to install the corresponding gem and add it to your `.rubocop.yml` file: + +* Capybara: `ubocop-capybara` +* FactoryBot: `rubocop-factory_bot` +* Rails: `rubocop-rspec_rails` For example, if you are using the RSpec/Capybara department, you need to install the `rubocop-capybara` gem and add it to your `.rubocop.yml` file: @@ -50,3 +54,7 @@ RSpec/FactoryBot: RSpec/Rails: Enabled: false ---- + +== Troubleshooting + +If you're seeing `cannot load such file` when running rubocop, even after installing the gems, try restarting your LSP with `rubocop --restart-server`. From 5646c8c679027dd3c33aa7f0fa4c1ef3ebdc7d01 Mon Sep 17 00:00:00 2001 From: Phil Pirozhkov Date: Tue, 18 Jun 2024 21:44:46 +0500 Subject: [PATCH 06/40] Apply suggestions from code review Co-authored-by: Benjamin Quorning <22333+bquorning@users.noreply.github.com> --- docs/modules/ROOT/pages/upgrade_to_version_3.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/upgrade_to_version_3.adoc b/docs/modules/ROOT/pages/upgrade_to_version_3.adoc index 75b9066ee..29de466d4 100644 --- a/docs/modules/ROOT/pages/upgrade_to_version_3.adoc +++ b/docs/modules/ROOT/pages/upgrade_to_version_3.adoc @@ -12,7 +12,7 @@ In version 3.x: If you are using the RSpec/Capybara, RSpec/FactoryBot, or RSpec/Rails departments -- or have one in a `require` list in your rubocop.yml -- you need to install the corresponding gem and add it to your `.rubocop.yml` file: -* Capybara: `ubocop-capybara` +* Capybara: `rubocop-capybara` * FactoryBot: `rubocop-factory_bot` * Rails: `rubocop-rspec_rails` @@ -57,4 +57,4 @@ RSpec/Rails: == Troubleshooting -If you're seeing `cannot load such file` when running rubocop, even after installing the gems, try restarting your LSP with `rubocop --restart-server`. +If you're seeing `cannot load such file` when running rubocop, even after installing the gems, restart the server with `rubocop --restart-server`. From 7586bc3dde891364015189aed7b52720364a25a2 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:41:41 +0200 Subject: [PATCH 07/40] Fix false negative for `RSpec/PredicateMatcher` when expectation contains custom failure message This leaves `predicate_matcher_block?` since RSpec doesn't seem to handle that case --- CHANGELOG.md | 1 + lib/rubocop/cop/rspec/predicate_matcher.rb | 10 ++++--- .../cop/rspec/predicate_matcher_spec.rb | 26 +++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 644219220..f35c9f367 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Master (Unreleased) - Fix wrong autocorrect for `RSpec/ScatteredSetup` when hook contains heredoc. ([@earlopain]) +- Fix false negative for `RSpec/PredicateMatcher` when expectation contains custom failure message. ([@earlopain]) ## 3.0.1 (2024-06-11) diff --git a/lib/rubocop/cop/rspec/predicate_matcher.rb b/lib/rubocop/cop/rspec/predicate_matcher.rb index 560b00600..a9b51e262 100644 --- a/lib/rubocop/cop/rspec/predicate_matcher.rb +++ b/lib/rubocop/cop/rspec/predicate_matcher.rb @@ -32,7 +32,7 @@ def check_inflected(node) (block $(send !nil? #predicate? ...) ...) $(send !nil? #predicate? ...)}) $#Runners.all - $#boolean_matcher?) + $#boolean_matcher? ...) PATTERN # @!method be_bool?(node) @@ -183,8 +183,12 @@ def heredoc_argument?(matcher) (send (send nil? :expect $!nil?) #Runners.all - {$(send nil? #predicate_matcher_name? ...) - (block $(send nil? #predicate_matcher_name? ...) ...)}) + { + $(send nil? #predicate_matcher_name? ...) + (block $(send nil? #predicate_matcher_name? ...) ...) + } + ... + ) PATTERN # @!method predicate_matcher_block?(node) diff --git a/spec/rubocop/cop/rspec/predicate_matcher_spec.rb b/spec/rubocop/cop/rspec/predicate_matcher_spec.rb index c37b2c7fe..bd1f4c1fb 100644 --- a/spec/rubocop/cop/rspec/predicate_matcher_spec.rb +++ b/spec/rubocop/cop/rspec/predicate_matcher_spec.rb @@ -16,6 +16,8 @@ expect_offense(<<~RUBY) expect(foo.empty?).to be_truthy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_empty` matcher over `empty?`. + expect(foo.empty?).to be_truthy, 'fail' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_empty` matcher over `empty?`. expect(foo.empty?).not_to be_truthy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_empty` matcher over `empty?`. expect(foo.empty?).to_not be_truthy @@ -30,6 +32,7 @@ expect_correction(<<~RUBY) expect(foo).to be_empty + expect(foo).to be_empty, 'fail' expect(foo).not_to be_empty expect(foo).not_to be_empty expect(foo).not_to be_empty @@ -42,6 +45,8 @@ expect_offense(<<~RUBY) expect(foo.exist?).to be_truthy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `exist` matcher over `exist?`. + expect(foo.exist?).to be_truthy, 'fail' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `exist` matcher over `exist?`. expect(foo.exists?).to be_truthy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `exist` matcher over `exists?`. expect(foo.has_something?).to be_truthy @@ -58,6 +63,7 @@ expect_correction(<<~RUBY) expect(foo).to exist + expect(foo).to exist, 'fail' expect(foo).to exist expect(foo).to have_something expect(foo).not_to have_something @@ -71,6 +77,8 @@ expect_offense(<<~RUBY) expect(foo.something?('foo')).to be_truthy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_something` matcher over `something?`. + expect(foo.something?('foo')).to be_truthy, 'fail' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_something` matcher over `something?`. expect(foo.something?('foo', 'bar')).to be_truthy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_something` matcher over `something?`. expect(foo.something? 1, 2).to be_truthy @@ -85,6 +93,7 @@ expect_correction(<<~RUBY) expect(foo).to be_something('foo') + expect(foo).to be_something('foo'), 'fail' expect(foo).to be_something('foo', 'bar') expect(foo).to be_something 1, 2 expect(foo).to have_key('foo') @@ -112,6 +121,8 @@ expect_offense(<<~RUBY) expect(foo.all?(&:present?)).to be_truthy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_all` matcher over `all?`. + expect(foo.all?(&:present?)).to be_truthy, 'fail' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_all` matcher over `all?`. expect(foo.all? { |x| x.present? }).to be_truthy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_all` matcher over `all?`. expect(foo.all?(n) { |x| x.present? }).to be_truthy @@ -134,6 +145,7 @@ expect_correction(<<~RUBY) expect(foo).to be_all(&:present?) + expect(foo).to be_all(&:present?), 'fail' expect(foo).to be_all { |x| x.present? } expect(foo).to be_all(n) { |x| x.present? } expect(foo).to be_all { present } @@ -151,6 +163,7 @@ it 'accepts a predicate method that is not checked true/false' do expect_no_offenses(<<~RUBY) expect(foo.something?).to eq "something" + expect(foo.something?).to eq "something", "fail" expect(foo.has_something?).to eq "something" RUBY end @@ -158,6 +171,7 @@ it 'accepts non-predicate method' do expect_no_offenses(<<~RUBY) expect(foo.something).to be(true) + expect(foo.something).to be(true), 'fail' expect(foo.has_something).to be(true) RUBY end @@ -171,6 +185,7 @@ it 'accepts strict checking boolean matcher' do expect_no_offenses(<<~RUBY) expect(foo.empty?).to eq(true) + expect(foo.empty?).to eq(true), 'fail' expect(foo.empty?).to be(true) expect(foo.empty?).to be(false) expect(foo.empty?).not_to be true @@ -188,6 +203,8 @@ expect_offense(<<~RUBY) expect(foo.empty?).to eq(true) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_empty` matcher over `empty?`. + expect(foo.empty?).to eq(true), 'fail' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_empty` matcher over `empty?`. expect(foo.empty?).not_to be(true) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `be_empty` matcher over `empty?`. expect(foo.empty?).to be(true) @@ -202,6 +219,7 @@ expect_correction(<<~RUBY) expect(foo).to be_empty + expect(foo).to be_empty, 'fail' expect(foo).not_to be_empty expect(foo).to be_empty expect(foo).not_to be_empty @@ -220,6 +238,8 @@ expect_offense(<<~RUBY) expect(foo).to be_empty ^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `empty?` over `be_empty` matcher. + expect(foo).to be_empty, 'fail' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `empty?` over `be_empty` matcher. expect(foo).not_to be_empty ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `empty?` over `be_empty` matcher. expect(foo).to have_something @@ -252,6 +272,7 @@ it 'accepts built in matchers' do expect_no_offenses(<<~RUBY) expect(foo).to be_truthy + expect(foo).to be_truthy, 'fail' expect(foo).to be_falsey expect(foo).to be_falsy expect(foo).to have_attributes(name: 'foo') @@ -275,6 +296,7 @@ it 'accepts non-predicate matcher' do expect_no_offenses(<<~RUBY) expect(foo).to be(true) + expect(foo).to be(true), 'fail' RUBY end @@ -282,6 +304,8 @@ expect_offense(<<~RUBY) expect(foo).to be_something ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `something?` over `be_something` matcher. + expect(foo).to be_something, 'fail' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `something?` over `be_something` matcher. expect(foo).not_to be_something ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using `something?` over `be_something` matcher. expect(foo).to have_something @@ -300,6 +324,7 @@ expect_correction(<<~RUBY) expect(foo.something?).to #{matcher_true} + expect(foo.something?).to #{matcher_true}, 'fail' expect(foo.something?).to #{matcher_false} expect(foo.has_something?).to #{matcher_true} expect(foo.is_a?(Array)).to #{matcher_true} @@ -403,6 +428,7 @@ 'with no argument' do expect_no_offenses(<<~RUBY) expect(foo).to include + expect(foo).to include, 'fail' RUBY end From 4c2e03e3aebaa128995374b6f47492e98b1f6006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20S=C3=B8rensen?= Date: Mon, 24 Jun 2024 09:07:02 +0200 Subject: [PATCH 08/40] Better assist rspec rails cop users when migrating to 3 Previously you would first get: ``` Error: The `RSpec/Rails/InferredSpecType` cop has been moved to `RSpecRails/InferredSpecType`. (obsolete configuration found in .rubocop.yml, please update it) ``` Then after renaming the cop, you would get: ``` Error: unrecognized cop or department RSpecRails/InferredSpecType found in .rubocop.yml Did you mean `RSpec/RepeatedDescription`? ``` Which would be a dead end. --- CHANGELOG.md | 2 ++ config/obsoletion.yml | 27 +++++---------------------- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f35c9f367..a932dab9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Fix wrong autocorrect for `RSpec/ScatteredSetup` when hook contains heredoc. ([@earlopain]) - Fix false negative for `RSpec/PredicateMatcher` when expectation contains custom failure message. ([@earlopain]) +- Facilitate the 3.0 upgrade flow with proper extracted cop messages. ([@jeppester]) ## 3.0.1 (2024-06-11) @@ -936,6 +937,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features. [@jaredmoody]: https://github.com/jaredmoody [@jdufresne]: https://github.com/jdufresne [@jeffreyc]: https://github.com/jeffreyc +[@jeppester]: https://github.com/jeppester [@jessieay]: https://github.com/jessieay [@jfragoulis]: https://github.com/jfragoulis [@johnny-miyake]: https://github.com/johnny-miyake diff --git a/config/obsoletion.yml b/config/obsoletion.yml index 5669cc85b..530bd0ed4 100644 --- a/config/obsoletion.yml +++ b/config/obsoletion.yml @@ -13,28 +13,6 @@ changed_parameters: alternative: AllowedPatterns severity: warning -renamed: - RSpec/Capybara/CurrentPathExpectation: Capybara/CurrentPathExpectation - RSpec/Capybara/MatchStyle: Capybara/MatchStyle - RSpec/Capybara/NegationMatcher: Capybara/NegationMatcher - RSpec/Capybara/SpecificActions: Capybara/SpecificActions - RSpec/Capybara/SpecificFinders: Capybara/SpecificFinders - RSpec/Capybara/SpecificMatcher: Capybara/SpecificMatcher - RSpec/Capybara/VisibilityMatcher: Capybara/VisibilityMatcher - RSpec/FactoryBot/AttributeDefinedStatically: FactoryBot/AttributeDefinedStatically - RSpec/FactoryBot/ConsistentParenthesesStyle: FactoryBot/ConsistentParenthesesStyle - RSpec/FactoryBot/CreateList: FactoryBot/CreateList - RSpec/FactoryBot/FactoryClassName: FactoryBot/FactoryClassName - RSpec/FactoryBot/FactoryNameStyle: FactoryBot/FactoryNameStyle - RSpec/FactoryBot/SyntaxMethods: FactoryBot/SyntaxMethods - RSpec/Rails/AvoidSetupHook: RSpecRails/AvoidSetupHook - RSpec/Rails/HaveHttpStatus: RSpecRails/HaveHttpStatus - RSpec/Rails/HttpStatus: RSpecRails/HttpStatus - RSpec/Rails/InferredSpecType: RSpecRails/InferredSpecType - RSpec/Rails/MinitestAssertions: RSpecRails/MinitestAssertions - RSpec/Rails/NegationBeValid: RSpecRails/NegationBeValid - RSpec/Rails/TravelAround: RSpecRails/TravelAround - split: RSpec/FilePath: alternatives: @@ -45,3 +23,8 @@ removed: RSpec/Capybara/FeatureMethods: reason: > this cop has migrated to `RSpec/Dialect`. Please use `RSpec/Dialect` instead + +extracted: + RSpec/Rails/*: rubocop-rspec_rails + RSpec/FactoryBot/*: rubocop-factory_bot + RSpec/Capybara/*: rubocop-capybara From 0cb5dc563a67131f565546309453853748e9c5ba Mon Sep 17 00:00:00 2001 From: Benjamin Quorning Date: Tue, 2 Jul 2024 21:38:17 +0200 Subject: [PATCH 09/40] Release v3.0.2 --- CHANGELOG.md | 2 ++ lib/rubocop/rspec/version.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a932dab9a..de307ae25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +## 3.0.2 (2024-07-02) + - Fix wrong autocorrect for `RSpec/ScatteredSetup` when hook contains heredoc. ([@earlopain]) - Fix false negative for `RSpec/PredicateMatcher` when expectation contains custom failure message. ([@earlopain]) - Facilitate the 3.0 upgrade flow with proper extracted cop messages. ([@jeppester]) diff --git a/lib/rubocop/rspec/version.rb b/lib/rubocop/rspec/version.rb index 79d587230..7d8dadbd0 100644 --- a/lib/rubocop/rspec/version.rb +++ b/lib/rubocop/rspec/version.rb @@ -4,7 +4,7 @@ module RuboCop module RSpec # Version information for the RSpec RuboCop plugin. module Version - STRING = '3.0.1' + STRING = '3.0.2' end end end From 59d9db078c8f451269889676569ca24f90b910bb Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Mon, 8 Jul 2024 09:52:27 -0700 Subject: [PATCH 10/40] Make Rspec/ExampleWording handle Unicode RIGHT SINGLE QUOTATION MARK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some people and editors write contractions such as "shouldn't" and "won't" using the Unicode RIGHT SINGLE QUOTATION MARK, "shouldn’t" and "won’t" so make Rspec/ExampleWording understand this alternative spelling. --- CHANGELOG.md | 2 + lib/rubocop/cop/rspec/example_wording.rb | 4 +- lib/rubocop/rspec/wording.rb | 4 +- .../rubocop/cop/rspec/example_wording_spec.rb | 39 +++++++++++++++++++ spec/rubocop/rspec/wording_spec.rb | 5 +++ 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de307ae25..80b038f06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Add support for Unicode RIGHT SINGLE QUOTATION MARK in `RSpec/ExampleWording`. ([@jdufresne]) + ## 3.0.2 (2024-07-02) - Fix wrong autocorrect for `RSpec/ScatteredSetup` when hook contains heredoc. ([@earlopain]) diff --git a/lib/rubocop/cop/rspec/example_wording.rb b/lib/rubocop/cop/rspec/example_wording.rb index a650183f2..a07e6abfa 100644 --- a/lib/rubocop/cop/rspec/example_wording.rb +++ b/lib/rubocop/cop/rspec/example_wording.rb @@ -55,8 +55,8 @@ class ExampleWording < Base MSG_INSUFFICIENT_DESCRIPTION = 'Your example description is ' \ 'insufficient.' - SHOULD_PREFIX = /\Ashould(?:n't)?\b/i.freeze - WILL_PREFIX = /\A(?:will|won't)\b/i.freeze + SHOULD_PREFIX = /\Ashould(?:n't|n’t)?\b/i.freeze + WILL_PREFIX = /\A(?:will|won't|won’t)\b/i.freeze IT_PREFIX = /\Ait /i.freeze # @!method it_description(node) diff --git a/lib/rubocop/rspec/wording.rb b/lib/rubocop/rspec/wording.rb index baee2818a..57929c3e3 100644 --- a/lib/rubocop/rspec/wording.rb +++ b/lib/rubocop/rspec/wording.rb @@ -4,10 +4,10 @@ module RuboCop module RSpec # RSpec example wording rewriter class Wording - SHOULDNT_PREFIX = /\Ashould(?:n't| not)\b/i.freeze + SHOULDNT_PREFIX = /\Ashould(?:n't|n’t| not)\b/i.freeze SHOULDNT_BE_PREFIX = /#{SHOULDNT_PREFIX} be\b/i.freeze WILL_NOT_PREFIX = /\Awill not\b/i.freeze - WONT_PREFIX = /\Awon't\b/i.freeze + WONT_PREFIX = /\Awo(?:n't|n’t)\b/i.freeze ES_SUFFIX_PATTERN = /(?:o|s|x|ch|sh|z)\z/i.freeze IES_SUFFIX_PATTERN = /[^aeou]y\z/i.freeze diff --git a/spec/rubocop/cop/rspec/example_wording_spec.rb b/spec/rubocop/cop/rspec/example_wording_spec.rb index 100ae719d..40645886b 100644 --- a/spec/rubocop/cop/rspec/example_wording_spec.rb +++ b/spec/rubocop/cop/rspec/example_wording_spec.rb @@ -148,6 +148,19 @@ RUBY end + it 'finds description with `won’t` at the beginning' do + expect_offense(<<~RUBY) + it "won’t do something" do + ^^^^^^^^^^^^^^^^^^ Do not use the future tense when describing your tests. + end + RUBY + + expect_correction(<<~RUBY) + it "does not do something" do + end + RUBY + end + it "finds description with `WON'T` at the beginning" do expect_offense(<<~RUBY) it "WON'T do something" do @@ -161,6 +174,19 @@ RUBY end + it 'finds description with `WON’T` at the beginning' do + expect_offense(<<~RUBY) + it "WON’T do something" do + ^^^^^^^^^^^^^^^^^^ Do not use the future tense when describing your tests. + end + RUBY + + expect_correction(<<~RUBY) + it "DOES NOT do something" do + end + RUBY + end + it 'flags a lone will' do expect_offense(<<~RUBY) it 'will' do @@ -200,6 +226,19 @@ RUBY end + it 'flags a lone won’t' do + expect_offense(<<~RUBY) + it "won’t" do + ^^^^^ Do not use the future tense when describing your tests. + end + RUBY + + expect_correction(<<~RUBY) + it "does not" do + end + RUBY + end + it 'finds leading its' do expect_offense(<<~RUBY) it "it does something" do diff --git a/spec/rubocop/rspec/wording_spec.rb b/spec/rubocop/rspec/wording_spec.rb index 80f7c8a43..7248f0dda 100644 --- a/spec/rubocop/rspec/wording_spec.rb +++ b/spec/rubocop/rspec/wording_spec.rb @@ -24,15 +24,20 @@ 'should wish me luck' => 'wishes me luck', 'should really only return one item' => 'really only returns one item', "shouldn't return something" => 'does not return something', + 'shouldn’t return something' => 'does not return something', 'SHOULD RETAIN UPPERCASE' => 'RETAINS UPPERCASE', "shouldn't be true" => 'is not true', + 'shouldn’t be true' => 'is not true', "SHOULDN'T BE true" => 'IS NOT true', + 'SHOULDN’T BE true' => 'IS NOT true', "SHOULDN'T NOT RETAIN UPPERCASE" => 'DOES NOT NOT RETAIN UPPERCASE', + 'SHOULDN’T NOT RETAIN UPPERCASE' => 'DOES NOT NOT RETAIN UPPERCASE', 'should WORRY' => 'WORRIES', 'should WISH me luck' => 'WISHES me luck', '' => '', 'should' => '', "shouldn't" => 'does not', + 'shouldn’t' => 'does not', 'should not' => 'does not', 'should fizz' => 'fizzes' } From 7e1d68eee4434464b032b0663741228a92b0ce7d Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Thu, 11 Jul 2024 03:27:23 +0900 Subject: [PATCH 11/40] Suppress deprecation warning for some cops Resolves https://github.com/rubocop/rubocop/pull/13032#issuecomment-2220942111. Starting from RuboCop 1.65, using `ConfigurableMax` module API, which is deprecated, will trigger deprecation warnings. This PR suppresses these warnings by using `exclude_limit` instead of the deprecated API. Related PR: https://github.com/rubocop/rubocop/pull/9471 --- CHANGELOG.md | 1 + lib/rubocop/cop/rspec/multiple_expectations.rb | 4 ++-- lib/rubocop/cop/rspec/multiple_memoized_helpers.rb | 3 ++- lib/rubocop/cop/rspec/nested_groups.rb | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80b038f06..66fa709c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Master (Unreleased) - Add support for Unicode RIGHT SINGLE QUOTATION MARK in `RSpec/ExampleWording`. ([@jdufresne]) +- Suppress deprecation warning for `RSpec/MultipleExpectations`, `RSpec/MultipleMemoizedHelpers`, and `RSpec/NestedGroups` cops. ([@koic]) ## 3.0.2 (2024-07-02) diff --git a/lib/rubocop/cop/rspec/multiple_expectations.rb b/lib/rubocop/cop/rspec/multiple_expectations.rb index 2d51f218d..bb1a32297 100644 --- a/lib/rubocop/cop/rspec/multiple_expectations.rb +++ b/lib/rubocop/cop/rspec/multiple_expectations.rb @@ -67,13 +67,13 @@ module RSpec # end # class MultipleExpectations < Base - include ConfigurableMax - MSG = 'Example has too many expectations [%d/%d].' ANYTHING = ->(_node) { true } TRUE_NODE = lambda(&:true_type?) + exclude_limit 'Max' + # @!method aggregate_failures?(node) def_node_matcher :aggregate_failures?, <<~PATTERN (block { diff --git a/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb b/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb index e386c5c68..b15dba208 100644 --- a/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +++ b/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb @@ -82,11 +82,12 @@ module RSpec # end # class MultipleMemoizedHelpers < Base - include ConfigurableMax include Variable MSG = 'Example group has too many memoized helpers [%d/%d]' + exclude_limit 'Max' + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless spec_group?(node) diff --git a/lib/rubocop/cop/rspec/nested_groups.rb b/lib/rubocop/cop/rspec/nested_groups.rb index 2529621ac..40e5aa2d8 100644 --- a/lib/rubocop/cop/rspec/nested_groups.rb +++ b/lib/rubocop/cop/rspec/nested_groups.rb @@ -92,7 +92,6 @@ module RSpec # end # class NestedGroups < Base - include ConfigurableMax include TopLevelGroup MSG = 'Maximum example group nesting exceeded [%d/%d].' @@ -103,6 +102,8 @@ class NestedGroups < Base "Configuration key `#{DEPRECATED_MAX_KEY}` for #{cop_name} is " \ 'deprecated in favor of `Max`. Please use that instead.' + exclude_limit 'Max' + def on_top_level_group(node) find_nested_example_groups(node) do |example_group, nesting| self.max = nesting From bb02b841fd446f9b582a3b2bfa9b932dc07ceb4e Mon Sep 17 00:00:00 2001 From: ydah Date: Fri, 12 Jul 2024 18:00:02 +0900 Subject: [PATCH 12/40] Release v3.0.3 --- CHANGELOG.md | 2 ++ lib/rubocop/rspec/version.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66fa709c0..0a362eaaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +## 3.0.3 (2024-07-12) + - Add support for Unicode RIGHT SINGLE QUOTATION MARK in `RSpec/ExampleWording`. ([@jdufresne]) - Suppress deprecation warning for `RSpec/MultipleExpectations`, `RSpec/MultipleMemoizedHelpers`, and `RSpec/NestedGroups` cops. ([@koic]) diff --git a/lib/rubocop/rspec/version.rb b/lib/rubocop/rspec/version.rb index 7d8dadbd0..d6618e190 100644 --- a/lib/rubocop/rspec/version.rb +++ b/lib/rubocop/rspec/version.rb @@ -4,7 +4,7 @@ module RuboCop module RSpec # Version information for the RSpec RuboCop plugin. module Version - STRING = '3.0.2' + STRING = '3.0.3' end end end From 60199baeb7f0f922bace742c8f2e564ce7604217 Mon Sep 17 00:00:00 2001 From: r7kamura Date: Thu, 18 Jul 2024 05:22:35 +0900 Subject: [PATCH 13/40] Fix false-negative for `UnspecifiedException` when matcher is chained --- CHANGELOG.md | 2 ++ .../cop/rspec/unspecified_exception.rb | 35 +++++++++++-------- .../cop/rspec/unspecified_exception_spec.rb | 27 ++++++++++++++ 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a362eaaf..f13124989 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Fix false-negative for `UnspecifiedException` when matcher is chained. ([@r7kamura]) + ## 3.0.3 (2024-07-12) - Add support for Unicode RIGHT SINGLE QUOTATION MARK in `RSpec/ExampleWording`. ([@jdufresne]) diff --git a/lib/rubocop/cop/rspec/unspecified_exception.rb b/lib/rubocop/cop/rspec/unspecified_exception.rb index c8bcf6bc9..ed49701a8 100644 --- a/lib/rubocop/cop/rspec/unspecified_exception.rb +++ b/lib/rubocop/cop/rspec/unspecified_exception.rb @@ -32,34 +32,39 @@ module RSpec # class UnspecifiedException < Base MSG = 'Specify the exception being captured' - RESTRICT_ON_SEND = %i[to].freeze - # @!method empty_raise_error_or_exception(node) - def_node_matcher :empty_raise_error_or_exception, <<~PATTERN - (send - (block - (send nil? :expect) ...) - :to - (send nil? {:raise_error :raise_exception}) - ) + RESTRICT_ON_SEND = %i[ + raise_exception + raise_error + ].freeze + + # @!method expect_to?(node) + def_node_matcher :expect_to?, <<~PATTERN + (send (block (send nil? :expect) ...) :to ...) PATTERN def on_send(node) return unless empty_exception_matcher?(node) - add_offense(node.children.last) + add_offense(node) end private def empty_exception_matcher?(node) - empty_raise_error_or_exception(node) && !block_with_args?(node.parent) - end + return false if node.arguments? || node.block_literal? - def block_with_args?(node) - return false unless node&.block_type? + expect_to = find_expect_to(node) + return false unless expect_to + return false if expect_to.block_node&.arguments? + + true + end - node.arguments? + def find_expect_to(node) + node.each_ancestor(:send).find do |ancestor| + expect_to?(ancestor) + end end end end diff --git a/spec/rubocop/cop/rspec/unspecified_exception_spec.rb b/spec/rubocop/cop/rspec/unspecified_exception_spec.rb index c4e1a6037..bb5db00bd 100644 --- a/spec/rubocop/cop/rspec/unspecified_exception_spec.rb +++ b/spec/rubocop/cop/rspec/unspecified_exception_spec.rb @@ -171,5 +171,32 @@ }.to raise_exception(my_exception) RUBY end + + it 'detects chained offenses' do + expect_offense(<<~RUBY) + expect { + foo + }.to raise_exception.and change { bar } + ^^^^^^^^^^^^^^^ Specify the exception being captured + RUBY + end + + it 'detects more chained offenses' do + expect_offense(<<~RUBY) + expect { + foo + }.to raise_exception.and change { bar }.and change { baz } + ^^^^^^^^^^^^^^^ Specify the exception being captured + RUBY + end + + it 'detects more complex chained offenses' do + expect_offense(<<~RUBY) + expect { + foo + }.to change { bar }.and raise_exception.and change { baz } + ^^^^^^^^^^^^^^^ Specify the exception being captured + RUBY + end end end From 6f06a332552bac65847843d1f529d322ff65f9ee Mon Sep 17 00:00:00 2001 From: ydah Date: Fri, 19 Jul 2024 16:02:39 +0900 Subject: [PATCH 14/40] Fix rubocop offenses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` ❯ bundle exec rubocop -A Inspecting 276 files ...................................................................................................................................................................................................................................................................................W Offenses: tasks/cut_release.rake:41:21: W: [Corrected] Lint/ImplicitStringConcatenation: Combine '\0' and "## #{version} (#{Time.now.strftime('%F')})\n\n" into a single string literal, rather than using implicit string concatenation. Or, if they were intended to be separate method arguments, separate them with a comma. '\0' "## #{version} (#{Time.now.strftime('%F')})\n\n") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tasks/cut_release.rake:41:21: C: [Corrected] Style/StringConcatenation: Prefer string interpolation to string concatenation. '\0' + "## #{version} (#{Time.now.strftime('%F')})\n\n") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 276 files inspected, 2 offenses detected, 2 offenses corrected ``` --- tasks/cut_release.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/cut_release.rake b/tasks/cut_release.rake index 130b67768..1ffa53035 100644 --- a/tasks/cut_release.rake +++ b/tasks/cut_release.rake @@ -38,7 +38,7 @@ namespace :cut_release do def add_header_to_changelog(version) update_file('CHANGELOG.md') do |changelog| changelog.sub("## Master (Unreleased)\n\n", - '\0' "## #{version} (#{Time.now.strftime('%F')})\n\n") + "\\0## #{version} (#{Time.now.strftime('%F')})\n\n") end end From 728fcc6582c78b941d0d46821b449dd50a4adc4a Mon Sep 17 00:00:00 2001 From: Benjamin Quorning Date: Mon, 5 Aug 2024 16:16:12 +0200 Subject: [PATCH 15/40] Release v3.0.4 --- CHANGELOG.md | 2 ++ lib/rubocop/rspec/version.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f13124989..53afa0ad8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +## 3.0.4 (2024-08-05) + - Fix false-negative for `UnspecifiedException` when matcher is chained. ([@r7kamura]) ## 3.0.3 (2024-07-12) diff --git a/lib/rubocop/rspec/version.rb b/lib/rubocop/rspec/version.rb index d6618e190..d1784e179 100644 --- a/lib/rubocop/rspec/version.rb +++ b/lib/rubocop/rspec/version.rb @@ -4,7 +4,7 @@ module RuboCop module RSpec # Version information for the RSpec RuboCop plugin. module Version - STRING = '3.0.3' + STRING = '3.0.4' end end end From dbd87bb1c86531b63b324622ba1c0fc48fa9bcdf Mon Sep 17 00:00:00 2001 From: Christophe Bliard Date: Thu, 8 Aug 2024 18:02:00 +0200 Subject: [PATCH 16/40] Fix false-negative and error for `RSpec/MetadataStyle` When RSpec/MetadataStyle cop is used with `EnforcedStyle: hash`, offenses must be registered only for metadata arguments being symbols. It was previously producing an exception if a variable was used in the metadata arguments (except if it was the last one). --- CHANGELOG.md | 3 ++ lib/rubocop/cop/rspec/metadata_style.rb | 7 +--- spec/rubocop/cop/rspec/metadata_style_spec.rb | 33 +++++++++++++++++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53afa0ad8..3266b77bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Fix false-negative and error for `RSpec/MetadataStyle` when non-literal args are used in metadata in `EnforceStyle: hash`. ([@cbliard]) + ## 3.0.4 (2024-08-05) - Fix false-negative for `UnspecifiedException` when matcher is chained. ([@r7kamura]) @@ -911,6 +913,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features. [@bquorning]: https://github.com/bquorning [@brentwheeldon]: https://github.com/BrentWheeldon [@brianhawley]: https://github.com/BrianHawley +[@cbliard]: https://github.com/cbliard [@cfabianski]: https://github.com/cfabianski [@clupprich]: https://github.com/clupprich [@composerinteralia]: https://github.com/composerinteralia diff --git a/lib/rubocop/cop/rspec/metadata_style.rb b/lib/rubocop/cop/rspec/metadata_style.rb index bb9d4c628..23b2b91dd 100644 --- a/lib/rubocop/cop/rspec/metadata_style.rb +++ b/lib/rubocop/cop/rspec/metadata_style.rb @@ -45,13 +45,8 @@ class MetadataStyle < Base # rubocop:disable Metrics/ClassLength PATTERN def on_metadata(symbols, hash) - # RSpec example groups accept two string arguments. In such a case, - # the rspec_metadata matcher will interpret the second string - # argument as a metadata symbol. - symbols.shift if symbols.first&.str_type? - symbols.each do |symbol| - on_metadata_symbol(symbol) + on_metadata_symbol(symbol) if symbol.sym_type? end return unless hash diff --git a/spec/rubocop/cop/rspec/metadata_style_spec.rb b/spec/rubocop/cop/rspec/metadata_style_spec.rb index 58e4a852a..810e3816a 100644 --- a/spec/rubocop/cop/rspec/metadata_style_spec.rb +++ b/spec/rubocop/cop/rspec/metadata_style_spec.rb @@ -94,6 +94,15 @@ end end + context 'with non-literal metadata and symbol metadata' do + it 'registers no offense' do + expect_no_offenses(<<~RUBY) + describe 'Something', a, :b do + end + RUBY + end + end + context 'with boolean keyword arguments metadata and symbol metadata' do it 'registers offense' do expect_offense(<<~RUBY) @@ -243,6 +252,15 @@ end end + context 'with 2 non-literal metadata' do + it 'registers no offense' do + expect_no_offenses(<<~RUBY) + describe 'Something', a, b do + end + RUBY + end + end + context 'with symbol metadata after 2 string arguments' do it 'registers offense' do expect_offense(<<~RUBY) @@ -258,6 +276,21 @@ end end + context 'with symbol metadata after non-literal metadata' do + it 'registers offense' do + expect_offense(<<~RUBY) + describe 'Something', a, :b do + ^^ Use hash style for metadata. + end + RUBY + + expect_correction(<<~RUBY) + describe 'Something', a, b: true do + end + RUBY + end + end + context 'with symbol metadata with parentheses' do it 'registers offense' do expect_offense(<<~RUBY) From f31b26862a73f2489f648e4b62a2e4a7cb774fc0 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Mon, 26 Aug 2024 21:33:18 +0200 Subject: [PATCH 17/40] Improve offense message for `RSpec/IndexedLet` Ran into this offense and thought: > Where exactly does my name contain "index"? I believe this message format is more clear. --- CHANGELOG.md | 1 + lib/rubocop/cop/rspec/indexed_let.rb | 7 +++--- spec/rubocop/cli/run_spec.rb | 8 +++---- spec/rubocop/cop/rspec/indexed_let_spec.rb | 26 +++++++++++----------- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3266b77bb..201f6b6b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Master (Unreleased) - Fix false-negative and error for `RSpec/MetadataStyle` when non-literal args are used in metadata in `EnforceStyle: hash`. ([@cbliard]) +- Improve offense message for `RSpec/IndexedLet`. ([@earlopain]) ## 3.0.4 (2024-08-05) diff --git a/lib/rubocop/cop/rspec/indexed_let.rb b/lib/rubocop/cop/rspec/indexed_let.rb index 546d56d3e..dab5d0e97 100644 --- a/lib/rubocop/cop/rspec/indexed_let.rb +++ b/lib/rubocop/cop/rspec/indexed_let.rb @@ -48,8 +48,8 @@ class IndexedLet < Base include AllowedIdentifiers include AllowedPattern - MSG = 'This `let` statement uses index in its name. Please give it ' \ - 'a meaningful name.' + MSG = 'This `let` statement uses `%s` in its name. ' \ + 'Please give it a meaningful name.' # @!method let_name(node) def_node_matcher :let_name, <<~PATTERN @@ -66,7 +66,8 @@ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless children filter_indexed_lets(children).each do |let_node| - add_offense(let_node) + index = let_name(let_node)[INDEX_REGEX] + add_offense(let_node, message: format(MSG, index: index)) end end diff --git a/spec/rubocop/cli/run_spec.rb b/spec/rubocop/cli/run_spec.rb index b8ae33670..4b0f6ba7b 100644 --- a/spec/rubocop/cli/run_spec.rb +++ b/spec/rubocop/cli/run_spec.rb @@ -39,9 +39,9 @@ == spec/example.rb == C: 2: 7: Naming/VariableNumber: Use normalcase for symbol numbers. C: 3: 7: Naming/VariableNumber: Use normalcase for symbol numbers. - C: 6: 3: RSpec/IndexedLet: This let statement uses index in its name. Please give it a meaningful name. + C: 6: 3: RSpec/IndexedLet: This let statement uses 1 in its name. Please give it a meaningful name. C: 6: 7: Naming/VariableNumber: Use normalcase for symbol numbers. - C: 7: 3: RSpec/IndexedLet: This let statement uses index in its name. Please give it a meaningful name. + C: 7: 3: RSpec/IndexedLet: This let statement uses 2 in its name. Please give it a meaningful name. C: 7: 7: Naming/VariableNumber: Use normalcase for symbol numbers. 1 file inspected, 6 offenses detected @@ -82,9 +82,9 @@ == spec/example.rb == C: 2: 7: Naming/VariableNumber: Use normalcase for symbol numbers. C: 3: 7: Naming/VariableNumber: Use normalcase for symbol numbers. - C: 6: 3: RSpec/IndexedLet: This let statement uses index in its name. Please give it a meaningful name. + C: 6: 3: RSpec/IndexedLet: This let statement uses 1 in its name. Please give it a meaningful name. C: 6: 7: Naming/VariableNumber: Use normalcase for symbol numbers. - C: 7: 3: RSpec/IndexedLet: This let statement uses index in its name. Please give it a meaningful name. + C: 7: 3: RSpec/IndexedLet: This let statement uses 2 in its name. Please give it a meaningful name. C: 7: 7: Naming/VariableNumber: Use normalcase for symbol numbers. 1 file inspected, 6 offenses detected diff --git a/spec/rubocop/cop/rspec/indexed_let_spec.rb b/spec/rubocop/cop/rspec/indexed_let_spec.rb index deff26c93..9f6cdbf4f 100644 --- a/spec/rubocop/cop/rspec/indexed_let_spec.rb +++ b/spec/rubocop/cop/rspec/indexed_let_spec.rb @@ -16,9 +16,9 @@ expect_offense(<<~RUBY) describe SomeService do let(:item_1) { create(:item) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses index in its name. Please give it a meaningful name. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses `1` in its name. Please give it a meaningful name. let(:item_2) { create(:item) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses index in its name. Please give it a meaningful name. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses `2` in its name. Please give it a meaningful name. end RUBY end @@ -27,9 +27,9 @@ expect_offense(<<~RUBY) describe SomeService do let("item_1") { create(:item) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses index in its name. Please give it a meaningful name. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses `1` in its name. Please give it a meaningful name. let("item_2") { create(:item) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses index in its name. Please give it a meaningful name. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses `2` in its name. Please give it a meaningful name. end RUBY end @@ -38,9 +38,9 @@ expect_offense(<<~RUBY) describe SomeService do let(:item1) { create(:item) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses index in its name. Please give it a meaningful name. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses `1` in its name. Please give it a meaningful name. let(:item2) { create(:item) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses index in its name. Please give it a meaningful name. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses `2` in its name. Please give it a meaningful name. end RUBY end @@ -49,9 +49,9 @@ expect_offense(<<~RUBY) describe SomeService do let(:item_1, &block) - ^^^^^^^^^^^^^^^^^^^^ This `let` statement uses index in its name. Please give it a meaningful name. + ^^^^^^^^^^^^^^^^^^^^ This `let` statement uses `1` in its name. Please give it a meaningful name. let(:item_2, &block) - ^^^^^^^^^^^^^^^^^^^^ This `let` statement uses index in its name. Please give it a meaningful name. + ^^^^^^^^^^^^^^^^^^^^ This `let` statement uses `2` in its name. Please give it a meaningful name. end RUBY end @@ -72,11 +72,11 @@ expect_offense(<<~RUBY) context SomeService do let(:user_1_item_1) { create(:item) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses index in its name. Please give it a meaningful name. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses `1` in its name. Please give it a meaningful name. let(:user_1_item_2) { create(:item) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses index in its name. Please give it a meaningful name. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses `1` in its name. Please give it a meaningful name. let(:user_2_item_1) { create(:item) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses index in its name. Please give it a meaningful name. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses `2` in its name. Please give it a meaningful name. end RUBY end @@ -112,9 +112,9 @@ expect_offense(<<~RUBY) describe SomeService do let(:item_1) { create(:item) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses index in its name. Please give it a meaningful name. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses `1` in its name. Please give it a meaningful name. let("item_2") { create(:item) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses index in its name. Please give it a meaningful name. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This `let` statement uses `2` in its name. Please give it a meaningful name. end RUBY end From a8a061c46ec1613c6008d5ab351baa13aa0290fa Mon Sep 17 00:00:00 2001 From: Benjamin Quorning Date: Sat, 7 Sep 2024 14:04:00 +0200 Subject: [PATCH 18/40] Release v3.0.5 --- CHANGELOG.md | 2 ++ lib/rubocop/rspec/version.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 201f6b6b5..3fb31d825 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +## 3.0.5 (2024-09-07) + - Fix false-negative and error for `RSpec/MetadataStyle` when non-literal args are used in metadata in `EnforceStyle: hash`. ([@cbliard]) - Improve offense message for `RSpec/IndexedLet`. ([@earlopain]) diff --git a/lib/rubocop/rspec/version.rb b/lib/rubocop/rspec/version.rb index d1784e179..554e79ce9 100644 --- a/lib/rubocop/rspec/version.rb +++ b/lib/rubocop/rspec/version.rb @@ -4,7 +4,7 @@ module RuboCop module RSpec # Version information for the RSpec RuboCop plugin. module Version - STRING = '3.0.4' + STRING = '3.0.5' end end end From 9a9027990fb73be6a5d555e452295158ded696ef Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Tue, 17 Sep 2024 16:28:08 -0700 Subject: [PATCH 19/40] Sort RuboCop config file --- .rubocop.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 4795eec03..e5b68d25d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -101,34 +101,34 @@ RSpec: - expect_no_offenses - expect_offense +RSpec/DescribeClass: + Exclude: + - spec/project/**/*.rb + RSpec/ExampleLength: CountAsOne: - heredoc Max: 11 -RSpec/DescribeClass: - Exclude: - - spec/project/**/*.rb - RSpec/MultipleExpectations: Max: 2 +RSpec/SpecFilePathFormat: + Exclude: + - spec/rubocop/cop/rspec/mixin/**/*.rb + # `expect_offense` does not use Kernel#format or String#% Style/FormatStringToken: Exclude: - spec/rubocop/**/*.rb -Style/RequireOrder: - Enabled: true - -RSpec/SpecFilePathFormat: - Exclude: - - spec/rubocop/cop/rspec/mixin/**/*.rb - Style/NumberedParameters: Enabled: true EnforcedStyle: disallow +Style/RequireOrder: + Enabled: true + # Enable RuboCop's pending cops up to v1.63 Gemspec/DeprecatedAttributeAssignment: {Enabled: true} From f4f698c1055263a40b7fae5a4f98a331a8bd4ca2 Mon Sep 17 00:00:00 2001 From: Benjamin Quorning Date: Wed, 18 Sep 2024 10:49:03 +0200 Subject: [PATCH 20/40] Fix InternalAffairs/RedundantSourceRange offenses --- lib/rubocop/cop/rspec/change_by_zero.rb | 4 ++-- lib/rubocop/cop/rspec/expect_actual.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rubocop/cop/rspec/change_by_zero.rb b/lib/rubocop/cop/rspec/change_by_zero.rb index d37ddd4dd..1ee9a40b7 100644 --- a/lib/rubocop/cop/rspec/change_by_zero.rb +++ b/lib/rubocop/cop/rspec/change_by_zero.rb @@ -104,12 +104,12 @@ def on_send(node) # rubocop:disable Metrics/MethodLength def register_offense(node, change_node) if compound_expectations?(node) - add_offense(node.source_range, + add_offense(node, message: message_compound(change_node)) do |corrector| autocorrect_compound(corrector, node) end else - add_offense(node.source_range, + add_offense(node, message: message(change_node)) do |corrector| autocorrect(corrector, node, change_node) end diff --git a/lib/rubocop/cop/rspec/expect_actual.rb b/lib/rubocop/cop/rspec/expect_actual.rb index 7a15aa25d..7aeb0fa81 100644 --- a/lib/rubocop/cop/rspec/expect_actual.rb +++ b/lib/rubocop/cop/rspec/expect_actual.rb @@ -69,7 +69,7 @@ def on_send(node) # rubocop:disable Metrics/MethodLength expect_literal(node) do |actual, send_node, matcher, expected| next if SKIPPED_MATCHERS.include?(matcher) - add_offense(actual.source_range) do |corrector| + add_offense(actual) do |corrector| next unless CORRECTABLE_MATCHERS.include?(matcher) next if literal?(expected) From a59315fb180454a4fdbf245eebac843a11952c98 Mon Sep 17 00:00:00 2001 From: Peter Aarestad Date: Tue, 13 Aug 2024 14:17:52 -0500 Subject: [PATCH 21/40] fix false positive on UnspecifiedException cop when function is named raise_exception --- CHANGELOG.md | 3 ++ .../cop/rspec/unspecified_exception.rb | 5 +- .../cop/rspec/unspecified_exception_spec.rb | 48 +++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fb31d825..f0797ef0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Fix false-positive for `RSpec/UnspecifiedException` when a method is literally named `raise_exception`. ([@aarestad]) + ## 3.0.5 (2024-09-07) - Fix false-negative and error for `RSpec/MetadataStyle` when non-literal args are used in metadata in `EnforceStyle: hash`. ([@cbliard]) @@ -899,6 +901,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features. +[@aarestad]: https://github.com/aarestad [@abrom]: https://github.com/abrom [@ahukkanen]: https://github.com/ahukkanen [@akiomik]: https://github.com/akiomik diff --git a/lib/rubocop/cop/rspec/unspecified_exception.rb b/lib/rubocop/cop/rspec/unspecified_exception.rb index ed49701a8..30d4c49af 100644 --- a/lib/rubocop/cop/rspec/unspecified_exception.rb +++ b/lib/rubocop/cop/rspec/unspecified_exception.rb @@ -62,7 +62,10 @@ def empty_exception_matcher?(node) end def find_expect_to(node) - node.each_ancestor(:send).find do |ancestor| + node.each_ancestor.find do |ancestor| + break if ancestor.block_type? + next unless ancestor.send_type? + expect_to?(ancestor) end end diff --git a/spec/rubocop/cop/rspec/unspecified_exception_spec.rb b/spec/rubocop/cop/rspec/unspecified_exception_spec.rb index bb5db00bd..2181b24bb 100644 --- a/spec/rubocop/cop/rspec/unspecified_exception_spec.rb +++ b/spec/rubocop/cop/rspec/unspecified_exception_spec.rb @@ -85,6 +85,30 @@ }.to raise_error(my_exception) RUBY end + + it 'allows a subject function to be named raise_error' do + expect_no_offenses(<<~RUBY) + def raise_exception + raise StandardError + end + + expect { + raise_error + }.to raise_error(StandardError) + RUBY + end + + it 'allows a subject function to be named raise_exception' do + expect_no_offenses(<<~RUBY) + def raise_exception + raise StandardError + end + + expect { + raise_exception + }.to raise_error(StandardError) + RUBY + end end context 'with raise_exception matcher' do @@ -198,5 +222,29 @@ ^^^^^^^^^^^^^^^ Specify the exception being captured RUBY end + + it 'allows a subject function to be named raise_exception' do + expect_no_offenses(<<~RUBY) + def raise_error + raise StandardError + end + + expect { + raise_exception + }.to raise_exception(StandardError) + RUBY + end + + it 'allows a subject function to be named raise_error' do + expect_no_offenses(<<~RUBY) + def raise_error + raise StandardError + end + + expect { + raise_error + }.to raise_exception(StandardError) + RUBY + end end end From 1f48c7b3f4362b2f01e8ad2ae51805c9b831a689 Mon Sep 17 00:00:00 2001 From: Gareth Jones Date: Fri, 27 Sep 2024 08:45:16 +1200 Subject: [PATCH 22/40] test: showcase `RSpec/UnspecifiedException` block/chain confusion is fixed --- CHANGELOG.md | 1 + spec/rubocop/cop/rspec/unspecified_exception_spec.rb | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0797ef0a..d1027dc93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Master (Unreleased) - Fix false-positive for `RSpec/UnspecifiedException` when a method is literally named `raise_exception`. ([@aarestad]) +- Fix false-positive for `RSpec/UnspecifiedException` when `not_to raise_error` is used within a block. ([@aarestad], [@G-Rath]) ## 3.0.5 (2024-09-07) diff --git a/spec/rubocop/cop/rspec/unspecified_exception_spec.rb b/spec/rubocop/cop/rspec/unspecified_exception_spec.rb index 2181b24bb..8c41e6b30 100644 --- a/spec/rubocop/cop/rspec/unspecified_exception_spec.rb +++ b/spec/rubocop/cop/rspec/unspecified_exception_spec.rb @@ -223,6 +223,14 @@ def raise_exception RUBY end + it 'does not confuse blocks with chains' do + expect_no_offenses(<<~RUBY) + expect do + expect { foo }.not_to raise_error + end.to change(Foo, :count).by(3) + RUBY + end + it 'allows a subject function to be named raise_exception' do expect_no_offenses(<<~RUBY) def raise_error From 324552cc8ff780b43a5eab2e697e0f4541213086 Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Wed, 18 Sep 2024 06:49:10 -0700 Subject: [PATCH 23/40] Add RSpec/StringAsInstanceDoubleConstant Addresses #1136 Adds a cop which can autocorrect from String declarations for instance_double to Class declarations. Symbol declarations are not affected. --- .rubocop.yml | 3 +- CHANGELOG.md | 2 + config/default.yml | 7 +++ docs/modules/ROOT/pages/cops.adoc | 1 + docs/modules/ROOT/pages/cops_rspec.adoc | 35 +++++++++++++++ .../string_as_instance_double_constant.rb | 45 +++++++++++++++++++ lib/rubocop/cop/rspec_cops.rb | 1 + ...string_as_instance_double_constant_spec.rb | 33 ++++++++++++++ 8 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 lib/rubocop/cop/rspec/string_as_instance_double_constant.rb create mode 100644 spec/rubocop/cop/rspec/string_as_instance_double_constant_spec.rb diff --git a/.rubocop.yml b/.rubocop.yml index e5b68d25d..6fb427aef 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -253,4 +253,5 @@ Style/YAMLFileRead: {Enabled: true} # Enable our own pending cops. # -# No pending cops yet. +RSpec/StringAsInstanceDoubleConstant: + Enabled: true diff --git a/CHANGELOG.md b/CHANGELOG.md index d1027dc93..bf2338aee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Master (Unreleased) +- Add `RSpec/StringAsInstanceDoubleConstant` to check for and correct strings used as instance_doubles. ([@corsonknowles]) - Fix false-positive for `RSpec/UnspecifiedException` when a method is literally named `raise_exception`. ([@aarestad]) - Fix false-positive for `RSpec/UnspecifiedException` when `not_to raise_error` is used within a block. ([@aarestad], [@G-Rath]) @@ -924,6 +925,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features. [@cfabianski]: https://github.com/cfabianski [@clupprich]: https://github.com/clupprich [@composerinteralia]: https://github.com/composerinteralia +[@corsonknowles]: https://github.com/corsonknowles [@corydiamand]: https://github.com/corydiamand [@darhazer]: https://github.com/Darhazer [@daveworth]: https://github.com/daveworth diff --git a/config/default.yml b/config/default.yml index 62135b81d..7e6e742b4 100644 --- a/config/default.yml +++ b/config/default.yml @@ -929,6 +929,13 @@ RSpec/SpecFilePathSuffix: - "**/spec/**/*" Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathSuffix +RSpec/StringAsInstanceDoubleConstant: + Description: Do not use a string as `instance_double` constant. + Enabled: pending + Safe: false + VersionAdded: "<>" + Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StringAsInstanceDoubleConstant + RSpec/StubbedMock: Description: Checks that message expectations do not have a configured response. Enabled: true diff --git a/docs/modules/ROOT/pages/cops.adoc b/docs/modules/ROOT/pages/cops.adoc index 16ddf0fd6..116d2a714 100644 --- a/docs/modules/ROOT/pages/cops.adoc +++ b/docs/modules/ROOT/pages/cops.adoc @@ -101,6 +101,7 @@ * xref:cops_rspec.adoc#rspecsortmetadata[RSpec/SortMetadata] * xref:cops_rspec.adoc#rspecspecfilepathformat[RSpec/SpecFilePathFormat] * xref:cops_rspec.adoc#rspecspecfilepathsuffix[RSpec/SpecFilePathSuffix] +* xref:cops_rspec.adoc#rspecstringasinstancedoubleconstant[RSpec/StringAsInstanceDoubleConstant] * xref:cops_rspec.adoc#rspecstubbedmock[RSpec/StubbedMock] * xref:cops_rspec.adoc#rspecsubjectdeclaration[RSpec/SubjectDeclaration] * xref:cops_rspec.adoc#rspecsubjectstub[RSpec/SubjectStub] diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 143791aa5..01240298c 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -5493,6 +5493,41 @@ spec/models/user.rb # shared_examples_for 'foo' * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathSuffix +== RSpec/StringAsInstanceDoubleConstant + +|=== +| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed + +| Pending +| No +| Always (Unsafe) +| <> +| - +|=== + +Do not use a string as `instance_double` constant. + +=== Safety + +This cop is unsafe because the correction requires loading the class. +Loading before stubbing causes RSpec to only allow instance methods +to be stubbed. + +=== Examples + +[source,ruby] +---- +# bad +instance_double('User', name: 'John') + +# good +instance_double(User, name: 'John') +---- + +=== References + +* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StringAsInstanceDoubleConstant + == RSpec/StubbedMock |=== diff --git a/lib/rubocop/cop/rspec/string_as_instance_double_constant.rb b/lib/rubocop/cop/rspec/string_as_instance_double_constant.rb new file mode 100644 index 000000000..c7a346821 --- /dev/null +++ b/lib/rubocop/cop/rspec/string_as_instance_double_constant.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Do not use a string as `instance_double` constant. + # + # @safety + # This cop is unsafe because the correction requires loading the class. + # Loading before stubbing causes RSpec to only allow instance methods + # to be stubbed. + # + # @example + # # bad + # instance_double('User', name: 'John') + # + # # good + # instance_double(User, name: 'John') + # + class StringAsInstanceDoubleConstant < Base + extend AutoCorrector + + MSG = 'Do not use a string as `instance_double` constant.' + RESTRICT_ON_SEND = %i[instance_double].freeze + + # @!method stringified_instance_double_const?(node) + def_node_matcher :stringified_instance_double_const?, <<~PATTERN + (send nil? :instance_double $str ...) + PATTERN + + def on_send(node) + stringified_instance_double_const?(node) do |args_node| + add_offense(args_node) do |corrector| + autocorrect(corrector, args_node) + end + end + end + + def autocorrect(corrector, node) + corrector.replace(node, node.value) + end + end + end + end +end diff --git a/lib/rubocop/cop/rspec_cops.rb b/lib/rubocop/cop/rspec_cops.rb index 5eed7e860..85c177e8e 100644 --- a/lib/rubocop/cop/rspec_cops.rb +++ b/lib/rubocop/cop/rspec_cops.rb @@ -99,6 +99,7 @@ require_relative 'rspec/sort_metadata' require_relative 'rspec/spec_file_path_format' require_relative 'rspec/spec_file_path_suffix' +require_relative 'rspec/string_as_instance_double_constant' require_relative 'rspec/stubbed_mock' require_relative 'rspec/subject_declaration' require_relative 'rspec/subject_stub' diff --git a/spec/rubocop/cop/rspec/string_as_instance_double_constant_spec.rb b/spec/rubocop/cop/rspec/string_as_instance_double_constant_spec.rb new file mode 100644 index 000000000..8f19ada94 --- /dev/null +++ b/spec/rubocop/cop/rspec/string_as_instance_double_constant_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::RSpec::StringAsInstanceDoubleConstant, + :config do + context 'when using a class for instance_double' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + instance_double(Shape, area: 12) + RUBY + end + end + + context 'when passing a variable to initialize instance_double' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + instance_double(type_undetectable_in_static_analysis) + RUBY + end + end + + context 'when using a string for instance_double' do + it 'replaces the string with the class' do + expect_offense <<~RUBY + instance_double('Shape', area: 12) + ^^^^^^^ Do not use a string as `instance_double` constant. + RUBY + + expect_correction <<~RUBY + instance_double(Shape, area: 12) + RUBY + end + end +end From 34c042e40092a8f92990bbc0a338e01f15057f28 Mon Sep 17 00:00:00 2001 From: Benjamin Quorning Date: Tue, 1 Oct 2024 12:13:00 +0200 Subject: [PATCH 24/40] Bump version to v3.1.0 --- CHANGELOG.md | 2 ++ config/default.yml | 2 +- docs/antora.yml | 2 +- docs/modules/ROOT/pages/cops_rspec.adoc | 2 +- lib/rubocop/rspec/version.rb | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf2338aee..93499ceaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +## 3.1.0 (2024-10-01) + - Add `RSpec/StringAsInstanceDoubleConstant` to check for and correct strings used as instance_doubles. ([@corsonknowles]) - Fix false-positive for `RSpec/UnspecifiedException` when a method is literally named `raise_exception`. ([@aarestad]) - Fix false-positive for `RSpec/UnspecifiedException` when `not_to raise_error` is used within a block. ([@aarestad], [@G-Rath]) diff --git a/config/default.yml b/config/default.yml index 7e6e742b4..c62b2f138 100644 --- a/config/default.yml +++ b/config/default.yml @@ -933,7 +933,7 @@ RSpec/StringAsInstanceDoubleConstant: Description: Do not use a string as `instance_double` constant. Enabled: pending Safe: false - VersionAdded: "<>" + VersionAdded: '3.1' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StringAsInstanceDoubleConstant RSpec/StubbedMock: diff --git a/docs/antora.yml b/docs/antora.yml index 51a533a15..bac2f797a 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,5 +1,5 @@ name: rubocop-rspec title: RuboCop RSpec -version: ~ +version: '3.1' nav: - modules/ROOT/nav.adoc diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 01240298c..2aff167af 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -5501,7 +5501,7 @@ spec/models/user.rb # shared_examples_for 'foo' | Pending | No | Always (Unsafe) -| <> +| 3.1 | - |=== diff --git a/lib/rubocop/rspec/version.rb b/lib/rubocop/rspec/version.rb index 554e79ce9..334b1761a 100644 --- a/lib/rubocop/rspec/version.rb +++ b/lib/rubocop/rspec/version.rb @@ -4,7 +4,7 @@ module RuboCop module RSpec # Version information for the RSpec RuboCop plugin. module Version - STRING = '3.0.5' + STRING = '3.1.0' end end end From f1bd410d926252853f5bcdd418fb0e5599894ac3 Mon Sep 17 00:00:00 2001 From: bquorning Date: Tue, 1 Oct 2024 13:43:33 +0000 Subject: [PATCH 25/40] Switch docs version back --- docs/antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/antora.yml b/docs/antora.yml index bac2f797a..51a533a15 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,5 +1,5 @@ name: rubocop-rspec title: RuboCop RSpec -version: '3.1' +version: ~ nav: - modules/ROOT/nav.adoc From a4e43cb9c338251f8b6b1d5767ce6f9de3cc1c6e Mon Sep 17 00:00:00 2001 From: Peter Leitzen Date: Tue, 8 Oct 2024 14:10:05 +0200 Subject: [PATCH 26/40] Link related style guide for RSpec/ExampleWithoutDescription --- config/default.yml | 1 + docs/modules/ROOT/pages/cops_rspec.adoc | 1 + 2 files changed, 2 insertions(+) diff --git a/config/default.yml b/config/default.yml index c62b2f138..6c09b7d72 100644 --- a/config/default.yml +++ b/config/default.yml @@ -403,6 +403,7 @@ RSpec/ExampleWithoutDescription: - single_line_only - disallow VersionAdded: '1.22' + StyleGuide: https://rspec.rubystyle.guide/#it-and-specify Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWithoutDescription RSpec/ExampleWording: diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 2aff167af..cf421a9a1 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -1775,6 +1775,7 @@ end === References +* https://rspec.rubystyle.guide/#it-and-specify * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWithoutDescription == RSpec/ExampleWording From c52269be7e13daee673feb250a66089388eee9e7 Mon Sep 17 00:00:00 2001 From: ydah Date: Mon, 14 Oct 2024 11:09:01 +0900 Subject: [PATCH 27/40] Fix a failed test in hook_spec.rb use ruby-head see: https://github.com/rubocop/rubocop-rspec/actions/runs/11319581327/job/31475851856 --- spec/rubocop/rspec/hook_spec.rb | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/spec/rubocop/rspec/hook_spec.rb b/spec/rubocop/rspec/hook_spec.rb index dffb7d63d..ad9493527 100644 --- a/spec/rubocop/rspec/hook_spec.rb +++ b/spec/rubocop/rspec/hook_spec.rb @@ -74,24 +74,32 @@ def metadata(source) hook(source).metadata.to_s end + if RUBY_VERSION >= '3.4' + let(:expected_special) { 's(:sym, :special) => true' } + let(:expected_symbol) { 's(:sym, :symbol) => true' } + else + let(:expected_special) { 's(:sym, :special)=>true' } + let(:expected_symbol) { 's(:sym, :symbol)=>true' } + end + it 'extracts symbol metadata' do expect(metadata('before(:example, :special) { foo }')) - .to eq('{s(:sym, :special)=>true}') + .to eq("{#{expected_special}}") end it 'extracts hash metadata' do expect(metadata('before(:example, special: true) { foo }')) - .to eq('{s(:sym, :special)=>true}') + .to eq("{#{expected_special}}") end it 'combines symbol and hash metadata' do expect(metadata('before(:example, :symbol, special: true) { foo }')) - .to eq('{s(:sym, :symbol)=>true, s(:sym, :special)=>true}') + .to eq("{#{expected_symbol}, #{expected_special}}") end it 'extracts hash metadata with no scope given' do expect(metadata('before(special: true) { foo }')) - .to eq('{s(:sym, :special)=>true}') + .to eq("{#{expected_special}}") end it 'withstands no arguments' do From d3e4268136201f60deba051939b5b92e6f2c3168 Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Sun, 13 Oct 2024 05:22:40 -0700 Subject: [PATCH 28/40] Complete branch coverage for VoidExpect and ContextWording --- spec/rubocop/cop/rspec/context_wording_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/spec/rubocop/cop/rspec/context_wording_spec.rb b/spec/rubocop/cop/rspec/context_wording_spec.rb index 5896110af..340d10181 100644 --- a/spec/rubocop/cop/rspec/context_wording_spec.rb +++ b/spec/rubocop/cop/rspec/context_wording_spec.rb @@ -214,4 +214,17 @@ end end end + + context 'when `AllowedPatterns:` and `Prefixes:` are both empty' do + let(:cop_config) do + { 'Prefixes' => [], 'AllowedPatterns' => [] } + end + + it 'skips any description' do + expect_no_offenses(<<~RUBY) + context 'arbitrary text' do + end + RUBY + end + end end From 5c8fef3b136e1866642b84b6690b0538b31ae341 Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Sun, 13 Oct 2024 03:46:04 -0700 Subject: [PATCH 29/40] Complete 100 line coverage for Metadata mixin This adds a final spec to cover an intentionally unimplemented method. --- spec/rubocop/cop/rspec/mixin/metadata_spec.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 spec/rubocop/cop/rspec/mixin/metadata_spec.rb diff --git a/spec/rubocop/cop/rspec/mixin/metadata_spec.rb b/spec/rubocop/cop/rspec/mixin/metadata_spec.rb new file mode 100644 index 000000000..df51b1c80 --- /dev/null +++ b/spec/rubocop/cop/rspec/mixin/metadata_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::RSpec::Metadata do + describe '#on_metadata' do + subject(:on_metadata) do + stub_class.new.on_metadata(:symbol, {}) + end + + let(:stub_class) do + Class.new do + include RuboCop::Cop::RSpec::Metadata + end + end + + it { expect { on_metadata }.to raise_error(NotImplementedError) } + end +end From 1278b73d183696e27419b203efd8872ca33da33c Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 16 Oct 2024 22:50:02 +0900 Subject: [PATCH 30/40] Fix problem with `Open3.popen3` where `confirm_documentation` task never finishes waiting for child processes see: https://github.com/rubocop/rubocop-rspec/actions/runs/11360936578/job/31599655573 --- Rakefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Rakefile b/Rakefile index a91382b68..59d02a4b6 100644 --- a/Rakefile +++ b/Rakefile @@ -72,10 +72,10 @@ end desc 'Confirm documentation is up to date' task confirm_documentation: :generate_cops_documentation do - _, _, _, process = - Open3.popen3('git diff --exit-code docs/') + _, _, status = + Open3.capture3('git diff --exit-code docs/') - unless process.value.success? + unless status.success? raise 'Please run `rake generate_cops_documentation` ' \ 'and add docs/ to the commit.' end From 5a99401f4a4490c49d9446345b82efa8ce2b1f4b Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 16 Oct 2024 22:50:45 +0900 Subject: [PATCH 31/40] Improve `confirm_documentation` task to display out-of-sync documentation --- Rakefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Rakefile b/Rakefile index 59d02a4b6..23d584ed0 100644 --- a/Rakefile +++ b/Rakefile @@ -72,12 +72,15 @@ end desc 'Confirm documentation is up to date' task confirm_documentation: :generate_cops_documentation do - _, _, status = + stdout, _stderr, status = Open3.capture3('git diff --exit-code docs/') unless status.success? - raise 'Please run `rake generate_cops_documentation` ' \ - 'and add docs/ to the commit.' + warn 'Documentation is out of sync:' + warn stdout + warn 'Please run `rake generate_cops_documentation` ' \ + 'and add docs/ to the commit.' + exit 1 end end From 9e4855ff9c0f05d711529dd3c7270b27244ebc21 Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 16 Oct 2024 22:50:52 +0900 Subject: [PATCH 32/40] bundle exec rake generate_cops_documentation --- docs/modules/ROOT/pages/cops_rspec.adoc | 459 ++++++++++++++++++++++++ 1 file changed, 459 insertions(+) diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index cf421a9a1..5556dd086 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -6,6 +6,7 @@ = RSpec +[#rspecalignleftletbrace] == RSpec/AlignLeftLetBrace |=== @@ -20,6 +21,7 @@ Checks that left braces for adjacent single line lets are aligned. +[#examples-rspecalignleftletbrace] === Examples [source,ruby] @@ -35,10 +37,12 @@ let(:baz) { bar } let(:a) { b } ---- +[#references-rspecalignleftletbrace] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AlignLeftLetBrace +[#rspecalignrightletbrace] == RSpec/AlignRightLetBrace |=== @@ -53,6 +57,7 @@ let(:a) { b } Checks that right braces for adjacent single line lets are aligned. +[#examples-rspecalignrightletbrace] === Examples [source,ruby] @@ -68,10 +73,12 @@ let(:baz) { bar } let(:a) { b } ---- +[#references-rspecalignrightletbrace] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AlignRightLetBrace +[#rspecanyinstance] == RSpec/AnyInstance |=== @@ -88,6 +95,7 @@ Check that instances are not being stubbed globally. Prefer instance doubles over stubbing any instance of a class +[#examples-rspecanyinstance] === Examples [source,ruby] @@ -108,11 +116,13 @@ describe MyClass do end ---- +[#references-rspecanyinstance] === References * https://rspec.rubystyle.guide/#any_instance_of * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AnyInstance +[#rspecaroundblock] == RSpec/AroundBlock |=== @@ -127,6 +137,7 @@ end Checks that around blocks actually run the test. +[#examples-rspecaroundblock] === Examples [source,ruby] @@ -152,10 +163,12 @@ around do |test| end ---- +[#references-rspecaroundblock] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AroundBlock +[#rspecbe] == RSpec/Be |=== @@ -174,6 +187,7 @@ The `be` matcher is too generic, as it pass on everything that is not nil or false. If that is the exact intend, use `be_truthy`. In all other cases it's better to specify what exactly is the expected value. +[#examples-rspecbe] === Examples [source,ruby] @@ -187,11 +201,13 @@ expect(foo).to be 1.0 expect(foo).to be(true) ---- +[#references-rspecbe] === References * https://rspec.rubystyle.guide/#be-matcher * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Be +[#rspecbeempty] == RSpec/BeEmpty |=== @@ -206,6 +222,7 @@ expect(foo).to be(true) Prefer using `be_empty` when checking for an empty array. +[#examples-rspecbeempty] === Examples [source,ruby] @@ -218,10 +235,12 @@ expect(array).to match_array([]) expect(array).to be_empty ---- +[#references-rspecbeempty] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEmpty +[#rspecbeeq] == RSpec/BeEq |=== @@ -240,10 +259,12 @@ The `be` matcher compares by identity while the `eq` matcher compares using `==`. Booleans and nil can be compared by identity and therefore the `be` matcher is preferable as it is a more strict test. +[#safety-rspecbeeq] === Safety This cop is unsafe because it changes how values are compared. +[#examples-rspecbeeq] === Examples [source,ruby] @@ -259,10 +280,12 @@ expect(foo).to be(false) expect(foo).to be(nil) ---- +[#references-rspecbeeq] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEq +[#rspecbeeql] == RSpec/BeEql |=== @@ -289,10 +312,12 @@ than `!equal?`. We also do not try to flag `eq` because if necessarily the same type as `b` since the `#==` operator can coerce objects for comparison. +[#safety-rspecbeeql] === Safety This cop is unsafe because it changes how values are compared. +[#examples-rspecbeeql] === Examples [source,ruby] @@ -314,10 +339,12 @@ expect(foo).to be(:bar) expect(foo).to be(nil) ---- +[#references-rspecbeeql] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEql +[#rspecbenil] == RSpec/BeNil |=== @@ -337,8 +364,10 @@ generic `be` matcher with a `nil` argument. This cop can be configured using the `EnforcedStyle` option +[#examples-rspecbenil] === Examples +[#_enforcedstyle_-be_nil_-_default_-rspecbenil] ==== `EnforcedStyle: be_nil` (default) [source,ruby] @@ -350,6 +379,7 @@ expect(foo).to be(nil) expect(foo).to be_nil ---- +[#_enforcedstyle_-be_-rspecbenil] ==== `EnforcedStyle: be` [source,ruby] @@ -361,6 +391,7 @@ expect(foo).to be_nil expect(foo).to be(nil) ---- +[#configurable-attributes-rspecbenil] === Configurable attributes |=== @@ -371,10 +402,12 @@ expect(foo).to be(nil) | `be`, `be_nil` |=== +[#references-rspecbenil] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeNil +[#rspecbeforeafterall] == RSpec/BeforeAfterAll |=== @@ -389,6 +422,7 @@ expect(foo).to be(nil) Check that before/after(:all/:context) isn't being used. +[#examples-rspecbeforeafterall] === Examples [source,ruby] @@ -406,6 +440,7 @@ describe MyClass do end ---- +[#configurable-attributes-rspecbeforeafterall] === Configurable attributes |=== @@ -416,11 +451,13 @@ end | Array |=== +[#references-rspecbeforeafterall] === References * https://rspec.rubystyle.guide/#avoid-hooks-with-context-scope * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeforeAfterAll +[#rspecchangebyzero] == RSpec/ChangeByZero |=== @@ -443,8 +480,10 @@ compound expectations, but if you set the negated matcher for `change`, e.g. `not_change` with the `NegatedMatcher` option, the cop will perform the autocorrection. +[#examples-rspecchangebyzero] === Examples +[#negatedmatcher_-_-_default_-rspecchangebyzero] ==== NegatedMatcher: ~ (default) [source,ruby] @@ -475,6 +514,7 @@ expect { run } .and not_change { Foo.baz } ---- +[#negatedmatcher_-not_change-rspecchangebyzero] ==== NegatedMatcher: not_change [source,ruby] @@ -497,6 +537,7 @@ expect { run } .and not_change { Foo.baz } ---- +[#configurable-attributes-rspecchangebyzero] === Configurable attributes |=== @@ -507,10 +548,12 @@ expect { run } | |=== +[#references-rspecchangebyzero] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ChangeByZero +[#rspecclasscheck] == RSpec/ClassCheck |=== @@ -525,8 +568,10 @@ expect { run } Enforces consistent use of `be_a` or `be_kind_of`. +[#examples-rspecclasscheck] === Examples +[#enforcedstyle_-be_a-_default_-rspecclasscheck] ==== EnforcedStyle: be_a (default) [source,ruby] @@ -540,6 +585,7 @@ expect(object).to be_a(String) expect(object).to be_an(String) ---- +[#enforcedstyle_-be_kind_of-rspecclasscheck] ==== EnforcedStyle: be_kind_of [source,ruby] @@ -553,6 +599,7 @@ expect(object).to be_kind_of(String) expect(object).to be_a_kind_of(String) ---- +[#configurable-attributes-rspecclasscheck] === Configurable attributes |=== @@ -563,11 +610,13 @@ expect(object).to be_a_kind_of(String) | `be_a`, `be_kind_of` |=== +[#references-rspecclasscheck] === References * https://rubystyle.guide#is-a-vs-kind-of * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ClassCheck +[#rspeccontainexactly] == RSpec/ContainExactly |=== @@ -586,6 +635,7 @@ This cop checks for the following: - Prefer `match_array` when matching array values. - Prefer `be_empty` when using `contain_exactly` with no arguments. +[#examples-rspeccontainexactly] === Examples [source,ruby] @@ -600,10 +650,12 @@ it { is_expected.to match_array(array1 + array2) } it { is_expected.to contain_exactly(content, *array) } ---- +[#references-rspeccontainexactly] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContainExactly +[#rspeccontextmethod] == RSpec/ContextMethod |=== @@ -618,6 +670,7 @@ it { is_expected.to contain_exactly(content, *array) } `context` should not be used for specifying methods. +[#examples-rspeccontextmethod] === Examples [source,ruby] @@ -641,11 +694,13 @@ describe '.foo_bar' do end ---- +[#references-rspeccontextmethod] === References * https://rspec.rubystyle.guide/#example-group-naming * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextMethod +[#rspeccontextwording] == RSpec/ContextWording |=== @@ -668,8 +723,10 @@ They may consist of multiple words if desired. This cop can be customized allowed context description pattern with `AllowedPatterns`. By default, there are no checking by pattern. +[#examples-rspeccontextwording] === Examples +[#_prefixes_-configuration-rspeccontextwording] ==== `Prefixes` configuration [source,ruby] @@ -698,6 +755,7 @@ context 'when the display name is not present' do end ---- +[#_allowedpatterns_-configuration-rspeccontextwording] ==== `AllowedPatterns` configuration [source,ruby] @@ -721,6 +779,7 @@ context '条件を満たすとき' do end ---- +[#configurable-attributes-rspeccontextwording] === Configurable attributes |=== @@ -735,12 +794,14 @@ end | Array |=== +[#references-rspeccontextwording] === References * https://rspec.rubystyle.guide/#context-descriptions * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording * http://www.betterspecs.org/#contexts +[#rspecdescribeclass] == RSpec/DescribeClass |=== @@ -759,8 +820,10 @@ It can be configured to ignore strings when certain metadata is passed. Ignores Rails and Aruba `type` metadata by default. +[#examples-rspecdescribeclass] === Examples +[#_ignoredmetadata_-configuration-rspecdescribeclass] ==== `IgnoredMetadata` configuration [source,ruby] @@ -792,6 +855,7 @@ describe "A feature example", type: :feature do end ---- +[#configurable-attributes-rspecdescribeclass] === Configurable attributes |=== @@ -806,10 +870,12 @@ end | |=== +[#references-rspecdescribeclass] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeClass +[#rspecdescribemethod] == RSpec/DescribeMethod |=== @@ -824,6 +890,7 @@ end Checks that the second argument to `describe` specifies a method. +[#examples-rspecdescribemethod] === Examples [source,ruby] @@ -840,10 +907,12 @@ describe MyClass, '.my_class_method' do end ---- +[#references-rspecdescribemethod] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeMethod +[#rspecdescribesymbol] == RSpec/DescribeSymbol |=== @@ -858,6 +927,7 @@ end Avoid describing symbols. +[#examples-rspecdescribesymbol] === Examples [source,ruby] @@ -873,11 +943,13 @@ describe '#my_method' do end ---- +[#references-rspecdescribesymbol] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeSymbol * https://github.com/rspec/rspec-core/issues/1610 +[#rspecdescribedclass] == RSpec/DescribedClass |=== @@ -909,8 +981,10 @@ To narrow down this setting to only a specific directory, it is possible to use an overriding configuration file local to that directory. +[#examples-rspecdescribedclass] === Examples +[#_enforcedstyle_-described_class_-_default_-rspecdescribedclass] ==== `EnforcedStyle: described_class` (default) [source,ruby] @@ -926,6 +1000,7 @@ describe MyClass do end ---- +[#_onlystaticconstants_-true_-_default_-rspecdescribedclass] ==== `OnlyStaticConstants: true` (default) [source,ruby] @@ -936,6 +1011,7 @@ describe MyClass do end ---- +[#_onlystaticconstants_-false_-rspecdescribedclass] ==== `OnlyStaticConstants: false` [source,ruby] @@ -946,6 +1022,7 @@ describe MyClass do end ---- +[#_enforcedstyle_-explicit_-rspecdescribedclass] ==== `EnforcedStyle: explicit` [source,ruby] @@ -961,6 +1038,7 @@ describe MyClass do end ---- +[#_skipblocks_-true_-rspecdescribedclass] ==== `SkipBlocks: true` [source,ruby] @@ -977,6 +1055,7 @@ describe MyConcern do end ---- +[#configurable-attributes-rspecdescribedclass] === Configurable attributes |=== @@ -995,10 +1074,12 @@ end | Boolean |=== +[#references-rspecdescribedclass] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClass +[#rspecdescribedclassmodulewrapping] == RSpec/DescribedClassModuleWrapping |=== @@ -1013,6 +1094,7 @@ end Avoid opening modules and defining specs within them. +[#examples-rspecdescribedclassmodulewrapping] === Examples [source,ruby] @@ -1030,11 +1112,13 @@ RSpec.describe MyModule::MyClass do end ---- +[#references-rspecdescribedclassmodulewrapping] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClassModuleWrapping * https://github.com/rubocop/rubocop-rspec/issues/735 +[#rspecdialect] == RSpec/Dialect |=== @@ -1088,6 +1172,7 @@ native RSpec method (e.g. are just aliases), use the following config: You can expect the following behavior: +[#examples-rspecdialect] === Examples [source,ruby] @@ -1103,6 +1188,7 @@ describe 'display name presence' do end ---- +[#configurable-attributes-rspecdialect] === Configurable attributes |=== @@ -1113,10 +1199,12 @@ end | |=== +[#references-rspecdialect] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Dialect +[#rspecduplicatedmetadata] == RSpec/DuplicatedMetadata |=== @@ -1131,6 +1219,7 @@ end Avoid duplicated metadata. +[#examples-rspecduplicatedmetadata] === Examples [source,ruby] @@ -1142,10 +1231,12 @@ describe 'Something', :a, :a describe 'Something', :a ---- +[#references-rspecduplicatedmetadata] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DuplicatedMetadata +[#rspecemptyexamplegroup] == RSpec/EmptyExampleGroup |=== @@ -1160,8 +1251,10 @@ describe 'Something', :a Checks if an example group does not include any tests. +[#examples-rspecemptyexamplegroup] === Examples +[#usage-rspecemptyexamplegroup] ==== usage [source,ruby] @@ -1196,10 +1289,12 @@ describe Bacon do end ---- +[#references-rspecemptyexamplegroup] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyExampleGroup +[#rspecemptyhook] == RSpec/EmptyHook |=== @@ -1214,6 +1309,7 @@ end Checks for empty before and after hooks. +[#examples-rspecemptyhook] === Examples [source,ruby] @@ -1236,10 +1332,12 @@ end after(:all) { cleanup_feed } ---- +[#references-rspecemptyhook] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyHook +[#rspecemptylineafterexample] == RSpec/EmptyLineAfterExample |=== @@ -1254,6 +1352,7 @@ after(:all) { cleanup_feed } Checks if there is an empty line after example blocks. +[#examples-rspecemptylineafterexample] === Examples [source,ruby] @@ -1282,6 +1381,7 @@ RSpec.describe Foo do end ---- +[#with-allowconsecutiveoneliners-configuration-rspecemptylineafterexample] ==== with AllowConsecutiveOneLiners configuration [source,ruby] @@ -1297,6 +1397,7 @@ RSpec.describe Foo do end ---- +[#configurable-attributes-rspecemptylineafterexample] === Configurable attributes |=== @@ -1307,11 +1408,13 @@ end | Boolean |=== +[#references-rspecemptylineafterexample] === References * https://rspec.rubystyle.guide/#empty-lines-around-examples * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterExample +[#rspecemptylineafterexamplegroup] == RSpec/EmptyLineAfterExampleGroup |=== @@ -1326,6 +1429,7 @@ end Checks if there is an empty line after example group blocks. +[#examples-rspecemptylineafterexamplegroup] === Examples [source,ruby] @@ -1348,11 +1452,13 @@ RSpec.describe Foo do end ---- +[#references-rspecemptylineafterexamplegroup] === References * https://rspec.rubystyle.guide/#empty-lines-between-describes * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterExampleGroup +[#rspecemptylineafterfinallet] == RSpec/EmptyLineAfterFinalLet |=== @@ -1367,6 +1473,7 @@ end Checks if there is an empty line after the last let block. +[#examples-rspecemptylineafterfinallet] === Examples [source,ruby] @@ -1383,11 +1490,13 @@ let(:something) { other } it { does_something } ---- +[#references-rspecemptylineafterfinallet] === References * https://rspec.rubystyle.guide/#empty-line-after-let * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterFinalLet +[#rspecemptylineafterhook] == RSpec/EmptyLineAfterHook |=== @@ -1405,6 +1514,7 @@ Checks if there is an empty line after hook blocks. `AllowConsecutiveOneLiners` configures whether adjacent one-line definitions are considered an offense. +[#examples-rspecemptylineafterhook] === Examples [source,ruby] @@ -1433,6 +1543,7 @@ after { do_something } it { does_something } ---- +[#with-allowconsecutiveoneliners-configuration-rspecemptylineafterhook] ==== with AllowConsecutiveOneLiners configuration [source,ruby] @@ -1455,6 +1566,7 @@ after { do_something } it { does_something } ---- +[#configurable-attributes-rspecemptylineafterhook] === Configurable attributes |=== @@ -1465,11 +1577,13 @@ it { does_something } | Boolean |=== +[#references-rspecemptylineafterhook] === References * https://rspec.rubystyle.guide/#empty-line-after-let * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterHook +[#rspecemptylineaftersubject] == RSpec/EmptyLineAfterSubject |=== @@ -1484,6 +1598,7 @@ it { does_something } Checks if there is an empty line after subject block. +[#examples-rspecemptylineaftersubject] === Examples [source,ruby] @@ -1498,11 +1613,13 @@ subject(:obj) { described_class } let(:foo) { bar } ---- +[#references-rspecemptylineaftersubject] === References * https://rspec.rubystyle.guide/#empty-line-after-let * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterSubject +[#rspecemptymetadata] == RSpec/EmptyMetadata |=== @@ -1517,8 +1634,10 @@ let(:foo) { bar } Avoid empty metadata hash. +[#examples-rspecemptymetadata] === Examples +[#enforcedstyle_-symbol-_default_-rspecemptymetadata] ==== EnforcedStyle: symbol (default) [source,ruby] @@ -1530,10 +1649,12 @@ describe 'Something', {} describe 'Something' ---- +[#references-rspecemptymetadata] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyMetadata +[#rspecemptyoutput] == RSpec/EmptyOutput |=== @@ -1548,6 +1669,7 @@ describe 'Something' Check that the `output` matcher is not called with an empty string. +[#examples-rspecemptyoutput] === Examples [source,ruby] @@ -1561,10 +1683,12 @@ expect { foo }.not_to output.to_stdout expect { bar }.to output.to_stderr ---- +[#references-rspecemptyoutput] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyOutput +[#rspeceq] == RSpec/Eq |=== @@ -1579,6 +1703,7 @@ expect { bar }.to output.to_stderr Use `eq` instead of `be ==` to compare objects. +[#examples-rspeceq] === Examples [source,ruby] @@ -1590,10 +1715,12 @@ expect(foo).to be == 42 expect(foo).to eq 42 ---- +[#references-rspeceq] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Eq +[#rspecexamplelength] == RSpec/ExampleLength |=== @@ -1617,6 +1744,7 @@ Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct will be counted as one line regardless of its actual size. +[#examples-rspecexamplelength] === Examples [source,ruby] @@ -1638,6 +1766,7 @@ it do end ---- +[#countasone_-__array__-_heredoc__-_method_call__-rspecexamplelength] ==== CountAsOne: ['array', 'heredoc', 'method_call'] [source,ruby] @@ -1664,6 +1793,7 @@ it do end # 6 points ---- +[#configurable-attributes-rspecexamplelength] === Configurable attributes |=== @@ -1678,10 +1808,12 @@ end # 6 points | Array |=== +[#references-rspecexamplelength] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleLength +[#rspecexamplewithoutdescription] == RSpec/ExampleWithoutDescription |=== @@ -1706,6 +1838,7 @@ on the configured style. This cop can be configured using the `EnforcedStyle` option +[#examples-rspecexamplewithoutdescription] === Examples [source,ruby] @@ -1717,6 +1850,7 @@ specify do end ---- +[#_enforcedstyle_-always_allow_-_default_-rspecexamplewithoutdescription] ==== `EnforcedStyle: always_allow` (default) [source,ruby] @@ -1736,6 +1870,7 @@ specify do end ---- +[#_enforcedstyle_-single_line_only_-rspecexamplewithoutdescription] ==== `EnforcedStyle: single_line_only` [source,ruby] @@ -1751,6 +1886,7 @@ end it { is_expected.to be_good } ---- +[#_enforcedstyle_-disallow_-rspecexamplewithoutdescription] ==== `EnforcedStyle: disallow` [source,ruby] @@ -1763,6 +1899,7 @@ it do end ---- +[#configurable-attributes-rspecexamplewithoutdescription] === Configurable attributes |=== @@ -1773,11 +1910,13 @@ end | `always_allow`, `single_line_only`, `disallow` |=== +[#references-rspecexamplewithoutdescription] === References * https://rspec.rubystyle.guide/#it-and-specify * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWithoutDescription +[#rspecexamplewording] == RSpec/ExampleWording |=== @@ -1802,6 +1941,7 @@ Use the DisallowedExamples setting to prevent unclear or insufficient descriptions. Please note that this config will not be treated as case sensitive. +[#examples-rspecexamplewording] === Examples [source,ruby] @@ -1829,6 +1969,7 @@ it 'does things' do end ---- +[#_disallowedexamples_-__works___-_default_-rspecexamplewording] ==== `DisallowedExamples: ['works']` (default) [source,ruby] @@ -1842,6 +1983,7 @@ it 'marks the task as done' do end ---- +[#configurable-attributes-rspecexamplewording] === Configurable attributes |=== @@ -1860,12 +2002,14 @@ end | Array |=== +[#references-rspecexamplewording] === References * https://rspec.rubystyle.guide/#should-in-example-docstrings * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWording * http://betterspecs.org/#should +[#rspecexcessivedocstringspacing] == RSpec/ExcessiveDocstringSpacing |=== @@ -1880,6 +2024,7 @@ end Checks for excessive whitespace in example descriptions. +[#examples-rspecexcessivedocstringspacing] === Examples [source,ruby] @@ -1904,10 +2049,12 @@ context 'when a condition is met' do end ---- +[#references-rspecexcessivedocstringspacing] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExcessiveDocstringSpacing +[#rspecexpectactual] == RSpec/ExpectActual |=== @@ -1924,6 +2071,7 @@ Checks for `expect(...)` calls containing literal values. Autocorrection is performed when the expected is not a literal. +[#examples-rspecexpectactual] === Examples [source,ruby] @@ -1942,6 +2090,7 @@ expect(name).to eq("John") expect(false).to eq(true) ---- +[#configurable-attributes-rspecexpectactual] === Configurable attributes |=== @@ -1952,10 +2101,12 @@ expect(false).to eq(true) | Array |=== +[#references-rspecexpectactual] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectActual +[#rspecexpectchange] == RSpec/ExpectChange |=== @@ -1975,8 +2126,10 @@ or passing a block that reads the attribute value. This cop can be configured using the `EnforcedStyle` option. +[#examples-rspecexpectchange] === Examples +[#_enforcedstyle_-method_call_-_default_-rspecexpectchange] ==== `EnforcedStyle: method_call` (default) [source,ruby] @@ -1993,6 +2146,7 @@ expect { run }.to change { Foo.bar(:count) } expect { run }.to change { user.reload.name } ---- +[#_enforcedstyle_-block_-rspecexpectchange] ==== `EnforcedStyle: block` [source,ruby] @@ -2004,6 +2158,7 @@ expect { run }.to change(Foo, :bar) expect { run }.to change { Foo.bar } ---- +[#configurable-attributes-rspecexpectchange] === Configurable attributes |=== @@ -2014,10 +2169,12 @@ expect { run }.to change { Foo.bar } | `method_call`, `block` |=== +[#references-rspecexpectchange] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectChange +[#rspecexpectinhook] == RSpec/ExpectInHook |=== @@ -2032,6 +2189,7 @@ expect { run }.to change { Foo.bar } Do not use `expect` in hooks such as `before`. +[#examples-rspecexpectinhook] === Examples [source,ruby] @@ -2052,10 +2210,12 @@ it do end ---- +[#references-rspecexpectinhook] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInHook +[#rspecexpectinlet] == RSpec/ExpectInLet |=== @@ -2070,6 +2230,7 @@ end Do not use `expect` in let. +[#examples-rspecexpectinlet] === Examples [source,ruby] @@ -2085,10 +2246,12 @@ it do end ---- +[#references-rspecexpectinlet] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInLet +[#rspecexpectoutput] == RSpec/ExpectOutput |=== @@ -2103,6 +2266,7 @@ end Checks for opportunities to use `expect { ... }.to output`. +[#examples-rspecexpectoutput] === Examples [source,ruby] @@ -2117,10 +2281,12 @@ expect($stdout.string).to eq('Hello World') expect { my_app.print_report }.to output('Hello World').to_stdout ---- +[#references-rspecexpectoutput] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectOutput +[#rspecfocus] == RSpec/Focus |=== @@ -2137,6 +2303,7 @@ Checks if examples are focused. This cop does not support autocorrection in some cases. +[#examples-rspecfocus] === Examples [source,ruby] @@ -2183,10 +2350,12 @@ shared_context 'test' do; end focus 'test' do; end ---- +[#references-rspecfocus] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Focus +[#rspechookargument] == RSpec/HookArgument |=== @@ -2206,8 +2375,10 @@ hooks which run for each example. There are three supported styles: "implicit", "each", and "example." All styles have the same behavior. +[#examples-rspechookargument] === Examples +[#_enforcedstyle_-implicit_-_default_-rspechookargument] ==== `EnforcedStyle: implicit` (default) [source,ruby] @@ -2228,6 +2399,7 @@ before do end ---- +[#_enforcedstyle_-each_-rspechookargument] ==== `EnforcedStyle: each` [source,ruby] @@ -2248,6 +2420,7 @@ before(:each) do end ---- +[#_enforcedstyle_-example_-rspechookargument] ==== `EnforcedStyle: example` [source,ruby] @@ -2268,6 +2441,7 @@ before(:example) do end ---- +[#configurable-attributes-rspechookargument] === Configurable attributes |=== @@ -2278,11 +2452,13 @@ end | `implicit`, `each`, `example` |=== +[#references-rspechookargument] === References * https://rspec.rubystyle.guide/#redundant-beforeeach * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HookArgument +[#rspechooksbeforeexamples] == RSpec/HooksBeforeExamples |=== @@ -2297,6 +2473,7 @@ end Checks for before/around/after hooks that come after an example. +[#examples-rspechooksbeforeexamples] === Examples [source,ruby] @@ -2318,10 +2495,12 @@ it 'checks what foo does' do end ---- +[#references-rspechooksbeforeexamples] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HooksBeforeExamples +[#rspecidenticalequalityassertion] == RSpec/IdenticalEqualityAssertion |=== @@ -2336,6 +2515,7 @@ end Checks for equality assertions with identical expressions on both sides. +[#examples-rspecidenticalequalityassertion] === Examples [source,ruby] @@ -2349,10 +2529,12 @@ expect(foo.bar).to eq(2) expect(foo.bar).to eql(2) ---- +[#references-rspecidenticalequalityassertion] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IdenticalEqualityAssertion +[#rspecimplicitblockexpectation] == RSpec/ImplicitBlockExpectation |=== @@ -2369,6 +2551,7 @@ Check that implicit block expectation syntax is not used. Prefer using explicit block expectations. +[#examples-rspecimplicitblockexpectation] === Examples [source,ruby] @@ -2383,11 +2566,13 @@ it 'changes something to a new value' do end ---- +[#references-rspecimplicitblockexpectation] === References * https://rspec.rubystyle.guide/#implicit-block-expectations * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitBlockExpectation +[#rspecimplicitexpect] == RSpec/ImplicitExpect |=== @@ -2405,8 +2590,10 @@ Check that a consistent implicit expectation style is used. This cop can be configured using the `EnforcedStyle` option and supports the `--auto-gen-config` flag. +[#examples-rspecimplicitexpect] === Examples +[#_enforcedstyle_-is_expected_-_default_-rspecimplicitexpect] ==== `EnforcedStyle: is_expected` (default) [source,ruby] @@ -2418,6 +2605,7 @@ it { should be_truthy } it { is_expected.to be_truthy } ---- +[#_enforcedstyle_-should_-rspecimplicitexpect] ==== `EnforcedStyle: should` [source,ruby] @@ -2429,6 +2617,7 @@ it { is_expected.to be_truthy } it { should be_truthy } ---- +[#configurable-attributes-rspecimplicitexpect] === Configurable attributes |=== @@ -2439,11 +2628,13 @@ it { should be_truthy } | `is_expected`, `should` |=== +[#references-rspecimplicitexpect] === References * https://rspec.rubystyle.guide/#use-expect * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitExpect +[#rspecimplicitsubject] == RSpec/ImplicitSubject |=== @@ -2460,8 +2651,10 @@ Checks for usage of implicit subject (`is_expected` / `should`). This cop can be configured using the `EnforcedStyle` option +[#examples-rspecimplicitsubject] === Examples +[#_enforcedstyle_-single_line_only_-_default_-rspecimplicitsubject] ==== `EnforcedStyle: single_line_only` (default) [source,ruby] @@ -2478,6 +2671,7 @@ it do end ---- +[#_enforcedstyle_-single_statement_only_-rspecimplicitsubject] ==== `EnforcedStyle: single_statement_only` [source,ruby] @@ -2498,6 +2692,7 @@ it do end ---- +[#_enforcedstyle_-disallow_-rspecimplicitsubject] ==== `EnforcedStyle: disallow` [source,ruby] @@ -2509,6 +2704,7 @@ it { is_expected.to be_truthy } it { expect(subject).to be_truthy } ---- +[#_enforcedstyle_-require_implicit_-rspecimplicitsubject] ==== `EnforcedStyle: require_implicit` [source,ruby] @@ -2533,6 +2729,7 @@ end it { expect(named_subject).to be_truthy } ---- +[#configurable-attributes-rspecimplicitsubject] === Configurable attributes |=== @@ -2543,10 +2740,12 @@ it { expect(named_subject).to be_truthy } | `single_line_only`, `single_statement_only`, `disallow`, `require_implicit` |=== +[#references-rspecimplicitsubject] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitSubject +[#rspecindexedlet] == RSpec/IndexedLet |=== @@ -2567,8 +2766,10 @@ is tested by this particular example. The configurable options `AllowedIdentifiers` and `AllowedPatterns` will also read those set in `Naming/VariableNumber`. +[#examples-rspecindexedlet] === Examples +[#_max_-1-_default__-rspecindexedlet] ==== `Max: 1 (default)` [source,ruby] @@ -2586,6 +2787,7 @@ let(:visible_item) { create(:item, visible: true) } let(:invisible_item) { create(:item, visible: false) } ---- +[#_max_-2_-rspecindexedlet] ==== `Max: 2` [source,ruby] @@ -2600,6 +2802,7 @@ let(:item_1) { create(:item) } let(:item_2) { create(:item) } ---- +[#_allowedidentifiers_-__item_1__-_item_2___-rspecindexedlet] ==== `AllowedIdentifiers: ['item_1', 'item_2']` [source,ruby] @@ -2609,6 +2812,7 @@ let(:item_1) { create(:item) } let(:item_2) { create(:item) } ---- +[#_allowedpatterns_-__item___-rspecindexedlet] ==== `AllowedPatterns: ['item']` [source,ruby] @@ -2618,6 +2822,7 @@ let(:item_1) { create(:item) } let(:item_2) { create(:item) } ---- +[#configurable-attributes-rspecindexedlet] === Configurable attributes |=== @@ -2636,10 +2841,12 @@ let(:item_2) { create(:item) } | Array |=== +[#references-rspecindexedlet] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IndexedLet +[#rspecinstancespy] == RSpec/InstanceSpy |=== @@ -2654,6 +2861,7 @@ let(:item_2) { create(:item) } Checks for `instance_double` used with `have_received`. +[#examples-rspecinstancespy] === Examples [source,ruby] @@ -2671,10 +2879,12 @@ it do end ---- +[#references-rspecinstancespy] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceSpy +[#rspecinstancevariable] == RSpec/InstanceVariable |=== @@ -2694,6 +2904,7 @@ will configure the cop to only register offenses on instance variable usage if the instance variable is also assigned within the spec +[#examples-rspecinstancevariable] === Examples [source,ruby] @@ -2711,6 +2922,7 @@ describe MyClass do end ---- +[#with-assignmentonly-configuration-rspecinstancevariable] ==== with AssignmentOnly configuration [source,ruby] @@ -2737,6 +2949,7 @@ describe MyClass do end ---- +[#configurable-attributes-rspecinstancevariable] === Configurable attributes |=== @@ -2747,11 +2960,13 @@ end | Boolean |=== +[#references-rspecinstancevariable] === References * https://rspec.rubystyle.guide/#instance-variables * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceVariable +[#rspecisexpectedspecify] == RSpec/IsExpectedSpecify |=== @@ -2766,6 +2981,7 @@ end Check for `specify` with `is_expected` and one-liner expectations. +[#examples-rspecisexpectedspecify] === Examples [source,ruby] @@ -2783,11 +2999,13 @@ end specify { expect(sqrt(4)).to eq(2) } ---- +[#references-rspecisexpectedspecify] === References * https://rspec.rubystyle.guide/#it-and-specify * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IsExpectedSpecify +[#rspecitbehaveslike] == RSpec/ItBehavesLike |=== @@ -2802,8 +3020,10 @@ specify { expect(sqrt(4)).to eq(2) } Checks that only one `it_behaves_like` style is used. +[#examples-rspecitbehaveslike] === Examples +[#_enforcedstyle_-it_behaves_like_-_default_-rspecitbehaveslike] ==== `EnforcedStyle: it_behaves_like` (default) [source,ruby] @@ -2815,6 +3035,7 @@ it_should_behave_like 'a foo' it_behaves_like 'a foo' ---- +[#_enforcedstyle_-it_should_behave_like_-rspecitbehaveslike] ==== `EnforcedStyle: it_should_behave_like` [source,ruby] @@ -2826,6 +3047,7 @@ it_behaves_like 'a foo' it_should_behave_like 'a foo' ---- +[#configurable-attributes-rspecitbehaveslike] === Configurable attributes |=== @@ -2836,10 +3058,12 @@ it_should_behave_like 'a foo' | `it_behaves_like`, `it_should_behave_like` |=== +[#references-rspecitbehaveslike] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ItBehavesLike +[#rspeciteratedexpectation] == RSpec/IteratedExpectation |=== @@ -2854,6 +3078,7 @@ it_should_behave_like 'a foo' Check that `all` matcher is used instead of iterating over an array. +[#examples-rspeciteratedexpectation] === Examples [source,ruby] @@ -2869,10 +3094,12 @@ it 'validates users' do end ---- +[#references-rspeciteratedexpectation] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IteratedExpectation +[#rspecleadingsubject] == RSpec/LeadingSubject |=== @@ -2887,6 +3114,7 @@ end Enforce that subject is the first definition in the test. +[#examples-rspecleadingsubject] === Examples [source,ruby] @@ -2916,11 +3144,13 @@ it { expect_something } it { expect_something_else } ---- +[#references-rspecleadingsubject] === References * https://rspec.rubystyle.guide/#leading-subject * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeadingSubject +[#rspecleakyconstantdeclaration] == RSpec/LeakyConstantDeclaration |=== @@ -2947,8 +3177,10 @@ Even worse when a class that exists in the codebase is reopened. Anonymous classes are fine, since they don't result in global namespace name clashes. +[#examples-rspecleakyconstantdeclaration] === Examples +[#constants-leak-between-examples-rspecleakyconstantdeclaration] ==== Constants leak between examples [source,ruby] @@ -3032,12 +3264,14 @@ describe SomeClass do end ---- +[#references-rspecleakyconstantdeclaration] === References * https://rspec.rubystyle.guide/#declare-constants * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeakyConstantDeclaration * https://rspec.info/features/3-12/rspec-mocks/mutating-constants +[#rspecletbeforeexamples] == RSpec/LetBeforeExamples |=== @@ -3052,6 +3286,7 @@ end Checks for `let` definitions that come after an example. +[#examples-rspecletbeforeexamples] === Examples [source,ruby] @@ -3082,10 +3317,12 @@ it 'checks what some does' do end ---- +[#references-rspecletbeforeexamples] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LetBeforeExamples +[#rspecletsetup] == RSpec/LetSetup |=== @@ -3100,6 +3337,7 @@ end Checks unreferenced `let!` calls being used for test setup. +[#examples-rspecletsetup] === Examples [source,ruby] @@ -3125,10 +3363,12 @@ it 'counts widgets' do end ---- +[#references-rspecletsetup] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LetSetup +[#rspecmatcharray] == RSpec/MatchArray |=== @@ -3147,6 +3387,7 @@ This cop checks for the following: - Prefer `contain_exactly` when matching an array with values. - Prefer `eq` when using `match_array` with an empty array literal. +[#examples-rspecmatcharray] === Examples [source,ruby] @@ -3164,10 +3405,12 @@ it { is_expected.to match_array([content] + array) } it { is_expected.to match_array(%w(tremble in fear foolish mortals)) } ---- +[#references-rspecmatcharray] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MatchArray +[#rspecmessagechain] == RSpec/MessageChain |=== @@ -3182,6 +3425,7 @@ it { is_expected.to match_array(%w(tremble in fear foolish mortals)) } Check that chains of messages are not being stubbed. +[#examples-rspecmessagechain] === Examples [source,ruby] @@ -3194,10 +3438,12 @@ thing = Thing.new(baz: 42) allow(foo).to receive(:bar).and_return(thing) ---- +[#references-rspecmessagechain] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageChain +[#rspecmessageexpectation] == RSpec/MessageExpectation |=== @@ -3215,8 +3461,10 @@ Checks for consistent message expectation style. This cop can be configured in your configuration using the `EnforcedStyle` option and supports `--auto-gen-config`. +[#examples-rspecmessageexpectation] === Examples +[#_enforcedstyle_-allow_-_default_-rspecmessageexpectation] ==== `EnforcedStyle: allow` (default) [source,ruby] @@ -3228,6 +3476,7 @@ expect(foo).to receive(:bar) allow(foo).to receive(:bar) ---- +[#_enforcedstyle_-expect_-rspecmessageexpectation] ==== `EnforcedStyle: expect` [source,ruby] @@ -3239,6 +3488,7 @@ allow(foo).to receive(:bar) expect(foo).to receive(:bar) ---- +[#configurable-attributes-rspecmessageexpectation] === Configurable attributes |=== @@ -3249,10 +3499,12 @@ expect(foo).to receive(:bar) | `allow`, `expect` |=== +[#references-rspecmessageexpectation] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageExpectation +[#rspecmessagespies] == RSpec/MessageSpies |=== @@ -3270,8 +3522,10 @@ Checks that message expectations are set using spies. This cop can be configured in your configuration using the `EnforcedStyle` option and supports `--auto-gen-config`. +[#examples-rspecmessagespies] === Examples +[#_enforcedstyle_-have_received_-_default_-rspecmessagespies] ==== `EnforcedStyle: have_received` (default) [source,ruby] @@ -3286,6 +3540,7 @@ do_something expect(foo).to have_received(:bar) ---- +[#_enforcedstyle_-receive_-rspecmessagespies] ==== `EnforcedStyle: receive` [source,ruby] @@ -3300,6 +3555,7 @@ expect(foo).to receive(:bar) do_something ---- +[#configurable-attributes-rspecmessagespies] === Configurable attributes |=== @@ -3310,10 +3566,12 @@ do_something | `have_received`, `receive` |=== +[#references-rspecmessagespies] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageSpies +[#rspecmetadatastyle] == RSpec/MetadataStyle |=== @@ -3332,8 +3590,10 @@ This cop does not support autocorrection in the case of `EnforcedStyle: hash` where the trailing metadata type is ambiguous. (e.g. `describe 'Something', :a, b`) +[#examples-rspecmetadatastyle] === Examples +[#enforcedstyle_-symbol-_default_-rspecmetadatastyle] ==== EnforcedStyle: symbol (default) [source,ruby] @@ -3345,6 +3605,7 @@ describe 'Something', a: true describe 'Something', :a ---- +[#enforcedstyle_-hash-rspecmetadatastyle] ==== EnforcedStyle: hash [source,ruby] @@ -3356,6 +3617,7 @@ describe 'Something', :a describe 'Something', a: true ---- +[#configurable-attributes-rspecmetadatastyle] === Configurable attributes |=== @@ -3366,10 +3628,12 @@ describe 'Something', a: true | `hash`, `symbol` |=== +[#references-rspecmetadatastyle] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MetadataStyle +[#rspecmissingexamplegroupargument] == RSpec/MissingExampleGroupArgument |=== @@ -3384,6 +3648,7 @@ describe 'Something', a: true Checks that the first argument to an example group is not empty. +[#examples-rspecmissingexamplegroupargument] === Examples [source,ruby] @@ -3403,10 +3668,12 @@ describe "A feature example" do end ---- +[#references-rspecmissingexamplegroupargument] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExampleGroupArgument +[#rspecmissingexpectationtargetmethod] == RSpec/MissingExpectationTargetMethod |=== @@ -3424,6 +3691,7 @@ Checks if `.to`, `not_to` or `to_not` are used. The RSpec::Expectations::ExpectationTarget must use `to`, `not_to` or `to_not` to run. Therefore, this cop checks if other methods are used. +[#examples-rspecmissingexpectationtargetmethod] === Examples [source,ruby] @@ -3439,10 +3707,12 @@ is_expected.to eq 42 expect{something}.to raise_error BarError ---- +[#references-rspecmissingexpectationtargetmethod] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExpectationTargetMethod +[#rspecmultipledescribes] == RSpec/MultipleDescribes |=== @@ -3460,6 +3730,7 @@ Checks for multiple top-level example groups. Multiple descriptions for the same class or module should either be nested or separated into different test files. +[#examples-rspecmultipledescribes] === Examples [source,ruby] @@ -3479,10 +3750,12 @@ describe MyClass do end ---- +[#references-rspecmultipledescribes] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleDescribes +[#rspecmultipleexpectations] == RSpec/MultipleExpectations |=== @@ -3500,6 +3773,7 @@ Checks if examples contain too many `expect` calls. This cop is configurable using the `Max` option and works with `--auto-gen-config`. +[#examples-rspecmultipleexpectations] === Examples [source,ruby] @@ -3524,6 +3798,7 @@ describe UserCreator do end ---- +[#_aggregate_failures_-true_-_default_-rspecmultipleexpectations] ==== `aggregate_failures: true` (default) [source,ruby] @@ -3537,6 +3812,7 @@ describe UserCreator do end ---- +[#_aggregate_failures_-false_-rspecmultipleexpectations] ==== `aggregate_failures: false` [source,ruby] @@ -3550,6 +3826,7 @@ describe UserCreator do end ---- +[#_max_-1_-_default_-rspecmultipleexpectations] ==== `Max: 1` (default) [source,ruby] @@ -3563,6 +3840,7 @@ describe UserCreator do end ---- +[#_max_-2_-rspecmultipleexpectations] ==== `Max: 2` [source,ruby] @@ -3576,6 +3854,7 @@ describe UserCreator do end ---- +[#configurable-attributes-rspecmultipleexpectations] === Configurable attributes |=== @@ -3586,12 +3865,14 @@ end | Integer |=== +[#references-rspecmultipleexpectations] === References * https://rspec.rubystyle.guide/#expectation-per-example * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleExpectations * http://betterspecs.org/#single +[#rspecmultiplememoizedhelpers] == RSpec/MultipleMemoizedHelpers |=== @@ -3610,6 +3891,7 @@ This cop is configurable using the `Max` option and the `AllowSubject` which will configure the cop to only register offenses on calls to `let` and not calls to `subject`. +[#examples-rspecmultiplememoizedhelpers] === Examples [source,ruby] @@ -3660,6 +3942,7 @@ describe MyClass do end ---- +[#when-disabling-allowsubject-configuration-rspecmultiplememoizedhelpers] ==== when disabling AllowSubject configuration [source,ruby] @@ -3679,6 +3962,7 @@ describe MyClass do end ---- +[#with-max-configuration-rspecmultiplememoizedhelpers] ==== with Max configuration [source,ruby] @@ -3694,6 +3978,7 @@ describe MyClass do end ---- +[#configurable-attributes-rspecmultiplememoizedhelpers] === Configurable attributes |=== @@ -3708,11 +3993,13 @@ end | Integer |=== +[#references-rspecmultiplememoizedhelpers] === References * https://rspec.rubystyle.guide/#let-blocks * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleMemoizedHelpers +[#rspecmultiplesubjects] == RSpec/MultipleSubjects |=== @@ -3743,6 +4030,7 @@ duplication: This is enough of an edge case that people can just move this to a `before` hook on their own +[#examples-rspecmultiplesubjects] === Examples [source,ruby] @@ -3774,10 +4062,12 @@ describe Foo do end ---- +[#references-rspecmultiplesubjects] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleSubjects +[#rspecnamedsubject] == RSpec/NamedSubject |=== @@ -3803,8 +4093,10 @@ This cop can be configured in your configuration using `EnforcedStyle`, and `IgnoreSharedExamples` which will not report offenses for implicit subjects in shared example groups. +[#examples-rspecnamedsubject] === Examples +[#_enforcedstyle_-always_-_default_-rspecnamedsubject] ==== `EnforcedStyle: always` (default) [source,ruby] @@ -3835,6 +4127,7 @@ RSpec.describe User do end ---- +[#_enforcedstyle_-named_only_-rspecnamedsubject] ==== `EnforcedStyle: named_only` [source,ruby] @@ -3874,6 +4167,7 @@ RSpec.describe User do end ---- +[#configurable-attributes-rspecnamedsubject] === Configurable attributes |=== @@ -3888,11 +4182,13 @@ end | Boolean |=== +[#references-rspecnamedsubject] === References * https://rspec.rubystyle.guide/#use-subject * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NamedSubject +[#rspecnestedgroups] == RSpec/NestedGroups |=== @@ -3910,6 +4206,7 @@ Checks for nested example groups. This cop is configurable using the `Max` option and supports `--auto-gen-config`. +[#examples-rspecnestedgroups] === Examples [source,ruby] @@ -3959,6 +4256,7 @@ context 'using some feature as an admin' do end ---- +[#_max_-3_-_default_-rspecnestedgroups] ==== `Max: 3` (default) [source,ruby] @@ -3974,6 +4272,7 @@ describe Foo do end ---- +[#_max_-2_-rspecnestedgroups] ==== `Max: 2` [source,ruby] @@ -3989,6 +4288,7 @@ describe Foo do end ---- +[#_allowedgroups_-__-_default__-rspecnestedgroups] ==== `AllowedGroups: [] (default)` [source,ruby] @@ -4001,6 +4301,7 @@ describe Foo do # <-- nested groups 1 end ---- +[#_allowedgroups_-_path__-rspecnestedgroups] ==== `AllowedGroups: [path]` [source,ruby] @@ -4013,6 +4314,7 @@ describe Foo do # <-- nested groups 1 end ---- +[#configurable-attributes-rspecnestedgroups] === Configurable attributes |=== @@ -4027,10 +4329,12 @@ end | Array |=== +[#references-rspecnestedgroups] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NestedGroups +[#rspecnoexpectationexample] == RSpec/NoExpectationExample |=== @@ -4061,6 +4365,7 @@ This cop can be customized with an allowed expectation methods pattern with an `AllowedPatterns` option. ^expect_ and ^assert_ are allowed by default. +[#examples-rspecnoexpectationexample] === Examples [source,ruby] @@ -4076,6 +4381,7 @@ it do end ---- +[#_allowedpatterns_-configuration-rspecnoexpectationexample] ==== `AllowedPatterns` configuration [source,ruby] @@ -4104,6 +4410,7 @@ it do end ---- +[#configurable-attributes-rspecnoexpectationexample] === Configurable attributes |=== @@ -4114,10 +4421,12 @@ end | Array |=== +[#references-rspecnoexpectationexample] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NoExpectationExample +[#rspecnottonot] == RSpec/NotToNot |=== @@ -4132,8 +4441,10 @@ end Checks for consistent method usage for negating expectations. +[#examples-rspecnottonot] === Examples +[#_enforcedstyle_-not_to_-_default_-rspecnottonot] ==== `EnforcedStyle: not_to` (default) [source,ruby] @@ -4149,6 +4460,7 @@ it '...' do end ---- +[#_enforcedstyle_-to_not_-rspecnottonot] ==== `EnforcedStyle: to_not` [source,ruby] @@ -4164,6 +4476,7 @@ it '...' do end ---- +[#configurable-attributes-rspecnottonot] === Configurable attributes |=== @@ -4174,10 +4487,12 @@ end | `not_to`, `to_not` |=== +[#references-rspecnottonot] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NotToNot +[#rspecoverwritingsetup] == RSpec/OverwritingSetup |=== @@ -4192,6 +4507,7 @@ end Checks if there is a let/subject that overwrites an existing one. +[#examples-rspecoverwritingsetup] === Examples [source,ruby] @@ -4213,10 +4529,12 @@ let(:baz) { baz } let!(:other) { other } ---- +[#references-rspecoverwritingsetup] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/OverwritingSetup +[#rspecpending] == RSpec/Pending |=== @@ -4231,6 +4549,7 @@ let!(:other) { other } Checks for any pending or skipped examples. +[#examples-rspecpending] === Examples [source,ruby] @@ -4262,10 +4581,12 @@ describe MyClass do end ---- +[#references-rspecpending] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Pending +[#rspecpendingwithoutreason] == RSpec/PendingWithoutReason |=== @@ -4280,6 +4601,7 @@ end Checks for pending or skipped examples without reason. +[#examples-rspecpendingwithoutreason] === Examples [source,ruby] @@ -4336,10 +4658,12 @@ it 'does something', skip: 'reason' do end ---- +[#references-rspecpendingwithoutreason] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/PendingWithoutReason +[#rspecpredicatematcher] == RSpec/PredicateMatcher |=== @@ -4358,8 +4682,10 @@ RSpec defines magic matchers for predicate methods. This cop recommends to use the predicate matcher instead of using predicate method directly. +[#examples-rspecpredicatematcher] === Examples +[#strict_-true_-enforcedstyle_-inflected-_default_-rspecpredicatematcher] ==== Strict: true, EnforcedStyle: inflected (default) [source,ruby] @@ -4374,6 +4700,7 @@ expect(foo).to be_something expect(foo.something?).to be(true) ---- +[#strict_-false_-enforcedstyle_-inflected-rspecpredicatematcher] ==== Strict: false, EnforcedStyle: inflected [source,ruby] @@ -4386,6 +4713,7 @@ expect(foo.something?).to be(true) expect(foo).to be_something ---- +[#strict_-true_-enforcedstyle_-explicit-rspecpredicatematcher] ==== Strict: true, EnforcedStyle: explicit [source,ruby] @@ -4408,6 +4736,7 @@ expect(foo.something?(<<~TEXT)).to be(true) TEXT ---- +[#strict_-false_-enforcedstyle_-explicit-rspecpredicatematcher] ==== Strict: false, EnforcedStyle: explicit [source,ruby] @@ -4419,6 +4748,7 @@ expect(foo).to be_something expect(foo.something?).to be_truthy ---- +[#configurable-attributes-rspecpredicatematcher] === Configurable attributes |=== @@ -4437,11 +4767,13 @@ expect(foo.something?).to be_truthy | Array |=== +[#references-rspecpredicatematcher] === References * https://rspec.rubystyle.guide/#predicate-matchers * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/PredicateMatcher +[#rspecreceivecounts] == RSpec/ReceiveCounts |=== @@ -4456,6 +4788,7 @@ expect(foo.something?).to be_truthy Check for `once` and `twice` receive counts matchers usage. +[#examples-rspecreceivecounts] === Examples [source,ruby] @@ -4477,10 +4810,12 @@ expect(foo).to receive(:bar).at_most(:once) expect(foo).to receive(:bar).at_most(:twice).times ---- +[#references-rspecreceivecounts] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveCounts +[#rspecreceivemessages] == RSpec/ReceiveMessages |=== @@ -4495,12 +4830,14 @@ expect(foo).to receive(:bar).at_most(:twice).times Checks for multiple messages stubbed on the same object. +[#safety-rspecreceivemessages] === Safety The autocorrection is marked as unsafe, because it may change the order of stubs. This in turn may cause e.g. variables to be called before they are defined. +[#examples-rspecreceivemessages] === Examples [source,ruby] @@ -4523,10 +4860,12 @@ before do end ---- +[#references-rspecreceivemessages] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveMessages +[#rspecreceivenever] == RSpec/ReceiveNever |=== @@ -4541,6 +4880,7 @@ end Prefer `not_to receive(...)` over `receive(...).never`. +[#examples-rspecreceivenever] === Examples [source,ruby] @@ -4552,10 +4892,12 @@ expect(foo).to receive(:bar).never expect(foo).not_to receive(:bar) ---- +[#references-rspecreceivenever] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveNever +[#rspecredundantaround] == RSpec/RedundantAround |=== @@ -4570,6 +4912,7 @@ expect(foo).not_to receive(:bar) Remove redundant `around` hook. +[#examples-rspecredundantaround] === Examples [source,ruby] @@ -4582,10 +4925,12 @@ end # good ---- +[#references-rspecredundantaround] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantAround +[#rspecredundantpredicatematcher] == RSpec/RedundantPredicateMatcher |=== @@ -4600,6 +4945,7 @@ end Checks for redundant predicate matcher. +[#examples-rspecredundantpredicatematcher] === Examples [source,ruby] @@ -4615,10 +4961,12 @@ expect(foo).not_to include(bar) expect(foo).to all be(bar) ---- +[#references-rspecredundantpredicatematcher] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RedundantPredicateMatcher +[#rspecremoveconst] == RSpec/RemoveConst |=== @@ -4633,6 +4981,7 @@ expect(foo).to all be(bar) Checks that `remove_const` is not used in specs. +[#examples-rspecremoveconst] === Examples [source,ruby] @@ -4647,10 +4996,12 @@ before do end ---- +[#references-rspecremoveconst] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RemoveConst +[#rspecrepeateddescription] == RSpec/RepeatedDescription |=== @@ -4665,6 +5016,7 @@ end Check for repeated description strings in example groups. +[#examples-rspecrepeateddescription] === Examples [source,ruby] @@ -4703,10 +5055,12 @@ RSpec.describe User do end ---- +[#references-rspecrepeateddescription] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedDescription +[#rspecrepeatedexample] == RSpec/RepeatedExample |=== @@ -4721,6 +5075,7 @@ end Check for repeated examples within example groups. +[#examples-rspecrepeatedexample] === Examples [source,ruby] @@ -4734,10 +5089,12 @@ it 'validates the user' do end ---- +[#references-rspecrepeatedexample] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExample +[#rspecrepeatedexamplegroupbody] == RSpec/RepeatedExampleGroupBody |=== @@ -4752,6 +5109,7 @@ end Check for repeated describe and context block body. +[#examples-rspecrepeatedexamplegroupbody] === Examples [source,ruby] @@ -4793,10 +5151,12 @@ context Hash do end ---- +[#references-rspecrepeatedexamplegroupbody] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExampleGroupBody +[#rspecrepeatedexamplegroupdescription] == RSpec/RepeatedExampleGroupDescription |=== @@ -4811,6 +5171,7 @@ end Check for repeated example group descriptions. +[#examples-rspecrepeatedexamplegroupdescription] === Examples [source,ruby] @@ -4852,10 +5213,12 @@ context 'when another case' do end ---- +[#references-rspecrepeatedexamplegroupdescription] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExampleGroupDescription +[#rspecrepeatedincludeexample] == RSpec/RepeatedIncludeExample |=== @@ -4870,6 +5233,7 @@ end Check for repeated include of shared examples. +[#examples-rspecrepeatedincludeexample] === Examples [source,ruby] @@ -4914,10 +5278,12 @@ context 'foo' do end ---- +[#references-rspecrepeatedincludeexample] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedIncludeExample +[#rspecrepeatedsubjectcall] == RSpec/RepeatedSubjectCall |=== @@ -4932,6 +5298,7 @@ end Checks for repeated calls to subject missing that it is memoized. +[#examples-rspecrepeatedsubjectcall] === Examples [source,ruby] @@ -4960,10 +5327,12 @@ it do end ---- +[#references-rspecrepeatedsubjectcall] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedSubjectCall +[#rspecreturnfromstub] == RSpec/ReturnFromStub |=== @@ -4984,8 +5353,10 @@ are the result would be different This cop can be configured using the `EnforcedStyle` option +[#examples-rspecreturnfromstub] === Examples +[#_enforcedstyle_-and_return_-_default_-rspecreturnfromstub] ==== `EnforcedStyle: and_return` (default) [source,ruby] @@ -5001,6 +5372,7 @@ expect(Foo).to receive(:bar).and_return("baz") allow(Foo).to receive(:bar) { bar.baz } ---- +[#_enforcedstyle_-block_-rspecreturnfromstub] ==== `EnforcedStyle: block` [source,ruby] @@ -5016,6 +5388,7 @@ expect(Foo).to receive(:bar) { "baz" } allow(Foo).to receive(:bar).and_return(bar.baz) ---- +[#configurable-attributes-rspecreturnfromstub] === Configurable attributes |=== @@ -5026,10 +5399,12 @@ allow(Foo).to receive(:bar).and_return(bar.baz) | `and_return`, `block` |=== +[#references-rspecreturnfromstub] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReturnFromStub +[#rspecscatteredlet] == RSpec/ScatteredLet |=== @@ -5046,6 +5421,7 @@ Checks for let scattered across the example group. Group lets together +[#examples-rspecscatteredlet] === Examples [source,ruby] @@ -5069,10 +5445,12 @@ describe Foo do end ---- +[#references-rspecscatteredlet] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ScatteredLet +[#rspecscatteredsetup] == RSpec/ScatteredSetup |=== @@ -5089,6 +5467,7 @@ Checks for setup scattered across multiple hooks in an example group. Unify `before`, `after`, and `around` hooks when possible. +[#examples-rspecscatteredsetup] === Examples [source,ruby] @@ -5108,10 +5487,12 @@ describe Foo do end ---- +[#references-rspecscatteredsetup] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ScatteredSetup +[#rspecsharedcontext] == RSpec/SharedContext |=== @@ -5129,6 +5510,7 @@ Checks for proper shared_context and shared_examples usage. If there are no examples defined, use shared_context. If there is no setup defined, use shared_examples. +[#examples-rspecsharedcontext] === Examples [source,ruby] @@ -5177,10 +5559,12 @@ RSpec.shared_context 'only setup here' do end ---- +[#references-rspecsharedcontext] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedContext +[#rspecsharedexamples] == RSpec/SharedExamples |=== @@ -5199,8 +5583,10 @@ Enforces either `string` or `symbol` for shared example names. This cop can be configured using the `EnforcedStyle` option +[#examples-rspecsharedexamples] === Examples +[#_enforcedstyle_-string_-_default_-rspecsharedexamples] ==== `EnforcedStyle: string` (default) [source,ruby] @@ -5220,6 +5606,7 @@ shared_examples_for 'foo bar baz' include_examples 'foo bar baz' ---- +[#_enforcedstyle_-symbol_-rspecsharedexamples] ==== `EnforcedStyle: symbol` [source,ruby] @@ -5239,6 +5626,7 @@ shared_examples_for :foo_bar_baz include_examples :foo_bar_baz ---- +[#configurable-attributes-rspecsharedexamples] === Configurable attributes |=== @@ -5249,10 +5637,12 @@ include_examples :foo_bar_baz | `string`, `symbol` |=== +[#references-rspecsharedexamples] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedExamples +[#rspecsingleargumentmessagechain] == RSpec/SingleArgumentMessageChain |=== @@ -5267,6 +5657,7 @@ include_examples :foo_bar_baz Checks that chains of messages contain more than one element. +[#examples-rspecsingleargumentmessagechain] === Examples [source,ruby] @@ -5282,10 +5673,12 @@ allow(foo).to receive(:bar, :baz) allow(foo).to receive("bar.baz") ---- +[#references-rspecsingleargumentmessagechain] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SingleArgumentMessageChain +[#rspecskipblockinsideexample] == RSpec/SkipBlockInsideExample |=== @@ -5300,6 +5693,7 @@ allow(foo).to receive("bar.baz") Checks for passing a block to `skip` within examples. +[#examples-rspecskipblockinsideexample] === Examples [source,ruby] @@ -5322,10 +5716,12 @@ skip 'not yet implemented' do end ---- +[#references-rspecskipblockinsideexample] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SkipBlockInsideExample +[#rspecsortmetadata] == RSpec/SortMetadata |=== @@ -5340,6 +5736,7 @@ end Sort RSpec metadata alphabetically. +[#examples-rspecsortmetadata] === Examples [source,ruby] @@ -5355,10 +5752,12 @@ context 'Something', baz: true, foo: 'bar' it 'works', :a, :b, baz: true, foo: 'bar' ---- +[#references-rspecsortmetadata] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SortMetadata +[#rspecspecfilepathformat] == RSpec/SpecFilePathFormat |=== @@ -5373,6 +5772,7 @@ it 'works', :a, :b, baz: true, foo: 'bar' Checks that spec file paths are consistent and well-formed. +[#examples-rspecspecfilepathformat] === Examples [source,ruby] @@ -5387,6 +5787,7 @@ my_class_method_spec.rb # describe MyClass, '#method' my_class/method_spec.rb # describe MyClass, '#method' ---- +[#_customtransform_-_rubocop__rubocop_-rspec__rspec__-_default_-rspecspecfilepathformat] ==== `CustomTransform: {RuboCop=>rubocop, RSpec=>rspec}` (default) [source,ruby] @@ -5396,6 +5797,7 @@ rubocop_spec.rb # describe RuboCop rspec_spec.rb # describe RSpec ---- +[#_ignoremethods_-false_-_default_-rspecspecfilepathformat] ==== `IgnoreMethods: false` (default) [source,ruby] @@ -5404,6 +5806,7 @@ rspec_spec.rb # describe RSpec my_class_spec.rb # describe MyClass, '#method' ---- +[#_ignoremethods_-true_-rspecspecfilepathformat] ==== `IgnoreMethods: true` [source,ruby] @@ -5412,6 +5815,7 @@ my_class_spec.rb # describe MyClass, '#method' my_class_spec.rb # describe MyClass, '#method' ---- +[#_ignoremetadata_-_type__routing__-_default_-rspecspecfilepathformat] ==== `IgnoreMetadata: {type=>routing}` (default) [source,ruby] @@ -5420,6 +5824,7 @@ my_class_spec.rb # describe MyClass, '#method' whatever_spec.rb # describe MyClass, type: :routing do; end ---- +[#configurable-attributes-rspecspecfilepathformat] === Configurable attributes |=== @@ -5446,10 +5851,12 @@ whatever_spec.rb # describe MyClass, type: :routing do; end | |=== +[#references-rspecspecfilepathformat] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathFormat +[#rspecspecfilepathsuffix] == RSpec/SpecFilePathSuffix |=== @@ -5464,6 +5871,7 @@ whatever_spec.rb # describe MyClass, type: :routing do; end Checks that spec file paths suffix are consistent and well-formed. +[#examples-rspecspecfilepathsuffix] === Examples [source,ruby] @@ -5480,6 +5888,7 @@ my_class_spec.rb # describe MyClass spec/models/user.rb # shared_examples_for 'foo' ---- +[#configurable-attributes-rspecspecfilepathsuffix] === Configurable attributes |=== @@ -5490,10 +5899,12 @@ spec/models/user.rb # shared_examples_for 'foo' | Array |=== +[#references-rspecspecfilepathsuffix] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathSuffix +[#rspecstringasinstancedoubleconstant] == RSpec/StringAsInstanceDoubleConstant |=== @@ -5508,12 +5919,14 @@ spec/models/user.rb # shared_examples_for 'foo' Do not use a string as `instance_double` constant. +[#safety-rspecstringasinstancedoubleconstant] === Safety This cop is unsafe because the correction requires loading the class. Loading before stubbing causes RSpec to only allow instance methods to be stubbed. +[#examples-rspecstringasinstancedoubleconstant] === Examples [source,ruby] @@ -5525,10 +5938,12 @@ instance_double('User', name: 'John') instance_double(User, name: 'John') ---- +[#references-rspecstringasinstancedoubleconstant] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StringAsInstanceDoubleConstant +[#rspecstubbedmock] == RSpec/StubbedMock |=== @@ -5543,6 +5958,7 @@ instance_double(User, name: 'John') Checks that message expectations do not have a configured response. +[#examples-rspecstubbedmock] === Examples [source,ruby] @@ -5555,10 +5971,12 @@ allow(foo).to receive(:bar).with(42).and_return("hello world") expect(foo).to receive(:bar).with(42) ---- +[#references-rspecstubbedmock] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/StubbedMock +[#rspecsubjectdeclaration] == RSpec/SubjectDeclaration |=== @@ -5573,6 +5991,7 @@ expect(foo).to receive(:bar).with(42) Ensure that subject is defined using subject helper. +[#examples-rspecsubjectdeclaration] === Examples [source,ruby] @@ -5591,10 +6010,12 @@ let(:subject, &block) subject(:test_subject) { foo } ---- +[#references-rspecsubjectdeclaration] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SubjectDeclaration +[#rspecsubjectstub] == RSpec/SubjectStub |=== @@ -5612,6 +6033,7 @@ Checks for stubbed test subjects. Checks nested subject stubs for innermost subject definition when subject is also defined in parent example groups. +[#examples-rspecsubjectstub] === Examples [source,ruby] @@ -5650,6 +6072,7 @@ describe Article do end ---- +[#references-rspecsubjectstub] === References * https://rspec.rubystyle.guide/#dont-stub-subject @@ -5657,6 +6080,7 @@ end * https://robots.thoughtbot.com/don-t-stub-the-system-under-test * https://penelope.zone/2015/12/27/introducing-rspec-smells-and-where-to-find-them.html#smell-1-stubjec +[#rspecundescriptiveliteralsdescription] == RSpec/UndescriptiveLiteralsDescription |=== @@ -5674,6 +6098,7 @@ Description should be descriptive. If example group or example contains only `execute string`, numbers and regular expressions, the description is not clear. +[#examples-rspecundescriptiveliteralsdescription] === Examples [source,ruby] @@ -5714,10 +6139,12 @@ it 'does something' do end ---- +[#references-rspecundescriptiveliteralsdescription] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/UndescriptiveLiteralsDescription +[#rspecunspecifiedexception] == RSpec/UnspecifiedException |=== @@ -5736,6 +6163,7 @@ Enforces one of an Exception type, a string, or a regular expression to match against the exception message as a parameter to `raise_error` +[#examples-rspecunspecifiedexception] === Examples [source,ruby] @@ -5761,10 +6189,12 @@ expect { expect { do_something }.not_to raise_error ---- +[#references-rspecunspecifiedexception] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/UnspecifiedException +[#rspecvariabledefinition] == RSpec/VariableDefinition |=== @@ -5779,8 +6209,10 @@ expect { do_something }.not_to raise_error Checks that memoized helpers names are symbols or strings. +[#examples-rspecvariabledefinition] === Examples +[#enforcedstyle_-symbols-_default_-rspecvariabledefinition] ==== EnforcedStyle: symbols (default) [source,ruby] @@ -5794,6 +6226,7 @@ subject(:user) { create_user } let(:user_name) { 'Adam' } ---- +[#enforcedstyle_-strings-rspecvariabledefinition] ==== EnforcedStyle: strings [source,ruby] @@ -5807,6 +6240,7 @@ subject('user') { create_user } let('user_name') { 'Adam' } ---- +[#configurable-attributes-rspecvariabledefinition] === Configurable attributes |=== @@ -5817,10 +6251,12 @@ let('user_name') { 'Adam' } | `symbols`, `strings` |=== +[#references-rspecvariabledefinition] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableDefinition +[#rspecvariablename] == RSpec/VariableName |=== @@ -5838,8 +6274,10 @@ Checks that memoized helper names use the configured style. Variables can be excluded from checking using the `AllowedPatterns` option. +[#examples-rspecvariablename] === Examples +[#enforcedstyle_-snake_case-_default_-rspecvariablename] ==== EnforcedStyle: snake_case (default) [source,ruby] @@ -5853,6 +6291,7 @@ subject(:user_name_1) { 'Adam' } let(:user_name_2) { 'Adam' } ---- +[#enforcedstyle_-camelcase-rspecvariablename] ==== EnforcedStyle: camelCase [source,ruby] @@ -5866,6 +6305,7 @@ subject(:userName1) { 'Adam' } let(:userName2) { 'Adam' } ---- +[#allowedpatterns-configuration-rspecvariablename] ==== AllowedPatterns configuration [source,ruby] @@ -5884,6 +6324,7 @@ subject(:userFood_1) { 'spaghetti' } let(:userFood_2) { 'fettuccine' } ---- +[#configurable-attributes-rspecvariablename] === Configurable attributes |=== @@ -5898,10 +6339,12 @@ let(:userFood_2) { 'fettuccine' } | Array |=== +[#references-rspecvariablename] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableName +[#rspecverifieddoublereference] == RSpec/VerifiedDoubleReference |=== @@ -5921,8 +6364,10 @@ Only investigates references that are one of the supported styles. This cop can be configured in your configuration using the `EnforcedStyle` option and supports `--auto-gen-config`. +[#examples-rspecverifieddoublereference] === Examples +[#_enforcedstyle_-constant_-_default_-rspecverifieddoublereference] ==== `EnforcedStyle: constant` (default) [source,ruby] @@ -5938,6 +6383,7 @@ let(:foo) do end ---- +[#_enforcedstyle_-string_-rspecverifieddoublereference] ==== `EnforcedStyle: string` [source,ruby] @@ -5953,6 +6399,7 @@ let(:foo) do end ---- +[#reference-is-not-in-the-supported-style-list_-no-enforcement-rspecverifieddoublereference] ==== Reference is not in the supported style list. No enforcement [source,ruby] @@ -5963,6 +6410,7 @@ let(:foo) do end ---- +[#configurable-attributes-rspecverifieddoublereference] === Configurable attributes |=== @@ -5973,11 +6421,13 @@ end | `constant`, `string` |=== +[#references-rspecverifieddoublereference] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubleReference * https://rspec.info/features/3-12/rspec-mocks/verifying-doubles +[#rspecverifieddoubles] == RSpec/VerifiedDoubles |=== @@ -5992,6 +6442,7 @@ end Prefer using verifying doubles over normal doubles. +[#examples-rspecverifieddoubles] === Examples [source,ruby] @@ -6012,6 +6463,7 @@ let(:foo) do end ---- +[#configurable-attributes-rspecverifieddoubles] === Configurable attributes |=== @@ -6026,12 +6478,14 @@ end | Boolean |=== +[#references-rspecverifieddoubles] === References * https://rspec.rubystyle.guide/#doubles * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubles * https://rspec.info/features/3-12/rspec-mocks/verifying-doubles +[#rspecvoidexpect] == RSpec/VoidExpect |=== @@ -6046,6 +6500,7 @@ end Checks void `expect()`. +[#examples-rspecvoidexpect] === Examples [source,ruby] @@ -6057,10 +6512,12 @@ expect(something) expect(something).to be(1) ---- +[#references-rspecvoidexpect] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VoidExpect +[#rspecyield] == RSpec/Yield |=== @@ -6075,6 +6532,7 @@ expect(something).to be(1) Checks for calling a block within a stub. +[#examples-rspecyield] === Examples [source,ruby] @@ -6086,6 +6544,7 @@ allow(foo).to receive(:bar) { |&block| block.call(1) } expect(foo).to receive(:bar).and_yield(1) ---- +[#references-rspecyield] === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Yield From e8fa4586e1cfdc4d14eccc50e1a73546c3d84c16 Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 16 Oct 2024 15:56:14 +0900 Subject: [PATCH 33/40] Fix typo in example_without_description_spec.rb --- spec/rubocop/cop/rspec/example_without_description_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/rubocop/cop/rspec/example_without_description_spec.rb b/spec/rubocop/cop/rspec/example_without_description_spec.rb index c3dad2ac1..1759505a6 100644 --- a/spec/rubocop/cop/rspec/example_without_description_spec.rb +++ b/spec/rubocop/cop/rspec/example_without_description_spec.rb @@ -84,7 +84,7 @@ RUBY end - it 'ignores `specify` missing decripton in multi-line examples' do + it 'ignores `specify` missing description in multi-line examples' do expect_no_offenses(<<~RUBY) specify do expect(subject).to be_good From c91e9d6a273d31d7e665a4f620c2d010a4613988 Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 16 Oct 2024 16:20:59 +0900 Subject: [PATCH 34/40] Add issue templates for bug reports and feature requests I think this will minimize the questions. --- .github/ISSUE_TEMPLATE/bug_report.md | 48 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++ 2 files changed, 68 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..e356c939e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,48 @@ +--- +name: Bug Report +about: Report an issue with RuboCop RSpec you've discovered. +--- + +*Be clear, concise and precise in your description of the problem. +Open an issue with a descriptive title and a summary in grammatically correct, +complete sentences.* + +*Use the template below when reporting bugs. Please, make sure that +you're running the latest stable RuboCop RSpec and that the problem you're reporting +hasn't been reported (and potentially fixed) already.* + +*Before filing the ticket you should replace all text above the horizontal +rule with your own words.* + +*In the case of false positive or false negative, please add the +corresponding cop name.* + +______________________________________________________________________ + +## Expected behavior + +Describe here how you expected RuboCop RSpec to behave in this particular situation. + +## Actual behavior + +Describe here what actually happened. +Please use `rubocop --debug` when pasting rubocop output as it contains additional information. + +## Steps to reproduce the problem + +This is extremely important! Providing us with a reliable way to reproduce +a problem will expedite its solution. + +## RuboCop RSpec version + +Include the output of `rubocop -V` or `bundle exec rubocop -V` if using Bundler. +If you see extension cop versions (e.g. `rubocop-performance`, `rubocop-rake`, and others) +output by `rubocop -V`, include them as well. Here's an example: + +```shell +$ [bundle exec] rubocop -V +1.67.0 (using Parser 3.3.5.0, rubocop-ast 1.32.3, analyzing as Ruby 2.7, running on ruby 3.4.0) [arm64-darwin23] + - rubocop-performance 1.22.1 + - rubocop-rake 0.6.0 + - rubocop-rspec 3.1.0 +``` diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..5c8eefd93 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature Request +about: Suggest new RuboCop RSpec features or improvements to existing features. +--- + +## Is your feature request related to a problem? Please describe. + +A clear and concise description of what the problem is. Ex. I'm always frustrated when \[...\] + +## Describe the solution you'd like + +A clear and concise description of what you want to happen. + +## Describe alternatives you've considered + +A clear and concise description of any alternative solutions or features you've considered. + +## Additional context + +Add any other context or screenshots about the feature request here. From 7e3149d7bf8e37f57970e4484d7798b4485b205e Mon Sep 17 00:00:00 2001 From: Dave Corson-Knowles Date: Mon, 14 Oct 2024 12:49:41 -0700 Subject: [PATCH 35/40] Require VoidExpect operate inside an example block --- CHANGELOG.md | 2 ++ lib/rubocop/cop/rspec/void_expect.rb | 7 ++++++- spec/rubocop/cop/rspec/void_expect_spec.rb | 22 ++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93499ceaf..a93ca6537 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Fix `RSpec/VoidExpect` to only operate inside an example block. ([@corsonknowles]) + ## 3.1.0 (2024-10-01) - Add `RSpec/StringAsInstanceDoubleConstant` to check for and correct strings used as instance_doubles. ([@corsonknowles]) diff --git a/lib/rubocop/cop/rspec/void_expect.rb b/lib/rubocop/cop/rspec/void_expect.rb index 8db6a496c..52f32147c 100644 --- a/lib/rubocop/cop/rspec/void_expect.rb +++ b/lib/rubocop/cop/rspec/void_expect.rb @@ -29,12 +29,14 @@ class VoidExpect < Base def on_send(node) return unless expect?(node) + return unless inside_example?(node) check_expect(node) end def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler return unless expect_block?(node) + return unless inside_example?(node) check_expect(node) end @@ -49,11 +51,14 @@ def check_expect(node) def void?(expect) parent = expect.parent - return true unless parent return true if parent.begin_type? parent.block_type? && parent.body == expect end + + def inside_example?(node) + node.each_ancestor(:block).any? { |ancestor| example?(ancestor) } + end end end end diff --git a/spec/rubocop/cop/rspec/void_expect_spec.rb b/spec/rubocop/cop/rspec/void_expect_spec.rb index 5791d7161..1ccf3ae74 100644 --- a/spec/rubocop/cop/rspec/void_expect_spec.rb +++ b/spec/rubocop/cop/rspec/void_expect_spec.rb @@ -44,4 +44,26 @@ end RUBY end + + it 'ignores unrelated method named expect in an example block' do + expect_no_offenses(<<~RUBY) + it 'something' do + MyObject.expect(:foo) + end + RUBY + end + + context 'when expect has no parent node' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + expect(something) + RUBY + end + + it 'does not register an offense for unrelated expect with block' do + expect_no_offenses(<<~RUBY) + expect { block_contents } + RUBY + end + end end From 5a75070cf80910788fb6523094cfa007cb27f600 Mon Sep 17 00:00:00 2001 From: ydah Date: Tue, 22 Oct 2024 13:56:33 +0900 Subject: [PATCH 36/40] Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty see: https://github.com/rubocop/rubocop-rspec/pull/1972#discussion_r1808522184 --- CHANGELOG.md | 2 ++ docs/modules/ROOT/pages/cops_rspec.adoc | 3 +++ lib/rubocop/cop/rspec/context_wording.rb | 24 ++++++++++++------- .../rubocop/cop/rspec/context_wording_spec.rb | 7 +++--- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93499ceaf..cd89a961c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty. ([@ydah]) + ## 3.1.0 (2024-10-01) - Add `RSpec/StringAsInstanceDoubleConstant` to check for and correct strings used as instance_doubles. ([@corsonknowles]) diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 5556dd086..20015bc0a 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -720,6 +720,9 @@ the configuration to meet project needs. Other acceptable prefixes may include `if`, `unless`, `for`, `before`, `after`, or `during`. They may consist of multiple words if desired. +If both `Prefixes` and `AllowedPatterns` are empty, this cop will always +report an offense. So you need to set at least one of them. + This cop can be customized allowed context description pattern with `AllowedPatterns`. By default, there are no checking by pattern. diff --git a/lib/rubocop/cop/rspec/context_wording.rb b/lib/rubocop/cop/rspec/context_wording.rb index 693c5c185..3fdba92f6 100644 --- a/lib/rubocop/cop/rspec/context_wording.rb +++ b/lib/rubocop/cop/rspec/context_wording.rb @@ -12,6 +12,9 @@ module RSpec # # @see http://www.betterspecs.org/#contexts # + # If both `Prefixes` and `AllowedPatterns` are empty, this cop will always + # report an offense. So you need to set at least one of them. + # # @example `Prefixes` configuration # # .rubocop.yml # # RSpec/ContextWording: @@ -58,7 +61,9 @@ module RSpec class ContextWording < Base include AllowedPattern - MSG = 'Context description should match %s.' + MSG_MATCH = 'Context description should match %s.' + MSG_ALWAYS = 'Current settings will always report an offense. Please ' \ + 'add allowed words to `Prefixes` or `AllowedPatterns`.' # @!method context_wording(node) def_node_matcher :context_wording, <<~PATTERN @@ -67,8 +72,7 @@ class ContextWording < Base def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler context_wording(node) do |context| - if bad_pattern?(context) - message = format(MSG, patterns: expect_patterns) + unless matches_allowed_pattern?(description(context)) add_offense(context, message: message) end end @@ -84,12 +88,6 @@ def prefix_regexes @prefix_regexes ||= prefixes.map { |pre| /^#{Regexp.escape(pre)}\b/ } end - def bad_pattern?(node) - return false if allowed_patterns.empty? - - !matches_allowed_pattern?(description(node)) - end - def description(context) if context.xstr_type? context.value.value @@ -98,6 +96,14 @@ def description(context) end end + def message + if allowed_patterns.empty? + MSG_ALWAYS + else + format(MSG_MATCH, patterns: expect_patterns) + end + end + def expect_patterns inspected = allowed_patterns.map do |pattern| pattern.inspect.gsub(/\A"|"\z/, '/') diff --git a/spec/rubocop/cop/rspec/context_wording_spec.rb b/spec/rubocop/cop/rspec/context_wording_spec.rb index 340d10181..de3394b53 100644 --- a/spec/rubocop/cop/rspec/context_wording_spec.rb +++ b/spec/rubocop/cop/rspec/context_wording_spec.rb @@ -220,9 +220,10 @@ { 'Prefixes' => [], 'AllowedPatterns' => [] } end - it 'skips any description' do - expect_no_offenses(<<~RUBY) - context 'arbitrary text' do + it 'always registers an offense' do + expect_offense(<<~RUBY) + context 'this is an incorrect context' do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Current settings will always report an offense. Please add allowed words to `Prefixes` or `AllowedPatterns`. end RUBY end From 130c5641f1a1afff88513d0a8278656d157ab88f Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 23 Oct 2024 21:28:04 +0900 Subject: [PATCH 37/40] Fix an error for `RSpec/ChangeByZero` when `change (...) .by (0)` and `change (...)`, concatenated with `and` and `or` fix: https://github.com/rubocop/rubocop-rspec/issues/1983 --- CHANGELOG.md | 1 + lib/rubocop/cop/rspec/change_by_zero.rb | 6 +++- spec/rubocop/cop/rspec/change_by_zero_spec.rb | 30 +++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd89a961c..e7dd725c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Master (Unreleased) - Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty. ([@ydah]) +- Fix an error for `RSpec/ChangeByZero` when `change (...) .by (0)` and `change (...)`, concatenated with `and` and `or`. ([@ydah]) ## 3.1.0 (2024-10-01) diff --git a/lib/rubocop/cop/rspec/change_by_zero.rb b/lib/rubocop/cop/rspec/change_by_zero.rb index 1ee9a40b7..75d442c75 100644 --- a/lib/rubocop/cop/rspec/change_by_zero.rb +++ b/lib/rubocop/cop/rspec/change_by_zero.rb @@ -118,7 +118,11 @@ def register_offense(node, change_node) # rubocop:enable Metrics/MethodLength def compound_expectations?(node) - %i[and or & |].include?(node.parent.method_name) + if node.parent.send_type? + %i[and or & |].include?(node.parent.method_name) + else + node.parent.and_type? || node.parent.or_type? + end end def message(change_node) diff --git a/spec/rubocop/cop/rspec/change_by_zero_spec.rb b/spec/rubocop/cop/rspec/change_by_zero_spec.rb index 5f313895b..4e9604768 100644 --- a/spec/rubocop/cop/rspec/change_by_zero_spec.rb +++ b/spec/rubocop/cop/rspec/change_by_zero_spec.rb @@ -68,6 +68,10 @@ expect { foo }.to change { Foo.bar }.by(0).and change { Foo.baz }.by(0) ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change(Foo, :bar).by(0).and change(Foo, :baz) + ^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change { Foo.bar }.and change { Foo.baz }.by(0) + ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. end RUBY @@ -84,6 +88,10 @@ expect { foo }.to change { Foo.bar }.by(0) & change { Foo.baz }.by(0) ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change(Foo, :bar).by(0) & change(Foo, :baz) + ^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change { Foo.bar } & change { Foo.baz }.by(0) + ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. end RUBY @@ -100,6 +108,10 @@ expect { foo }.to change { Foo.bar }.by(0).or change { Foo.baz }.by(0) ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change(Foo, :bar).by(0).or change(Foo, :baz) + ^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change { Foo.bar }.or change { Foo.baz }.by(0) + ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. end RUBY @@ -116,6 +128,10 @@ expect { foo }.to change { Foo.bar }.by(0) | change { Foo.baz }.by(0) ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change(Foo, :bar) | change(Foo, :baz).by(0) + ^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. + expect { foo }.to change { Foo.bar }.by(0) | change { Foo.baz } + ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer negated matchers with compound expectations over `change.by(0)`. end RUBY @@ -244,6 +260,14 @@ ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `not_change` with compound expectations over `change.by(0)`. .and change { Foo.baz }.by(0) ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `not_change` with compound expectations over `change.by(0)`. + expect { foo } + .to change(Foo, :bar) + .and change(Foo, :baz).by(0) + ^^^^^^^^^^^^^^^^^^^^^^^ Prefer `not_change` with compound expectations over `change.by(0)`. + expect { foo } + .to change { Foo.bar } + .and change { Foo.baz }.by(0) + ^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `not_change` with compound expectations over `change.by(0)`. end RUBY @@ -255,6 +279,12 @@ expect { foo } .to not_change { Foo.bar } .and not_change { Foo.baz } + expect { foo } + .to change(Foo, :bar) + .and not_change(Foo, :baz) + expect { foo } + .to change { Foo.bar } + .and not_change { Foo.baz } end RUBY end From eb617486819a01ad76a08f50b0aa04cae3337dca Mon Sep 17 00:00:00 2001 From: Phil Pirozhkov Date: Fri, 25 Oct 2024 17:24:09 +0300 Subject: [PATCH 38/40] Revert an change that would conceal unintentional RSpec syntax Specifically: expect { ... }.to change { ... }.by(...) and change { ... }.by(...) Here the usage of `and` is incorrect, as RSpec does not (and can't reasonably) support it. Compound should use the `and` method, not the operator, or the `&`. Same for `.or` and `|`. --- CHANGELOG.md | 1 + lib/rubocop/cop/rspec/change_by_zero.rb | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7dd725c9..f1de7a001 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty. ([@ydah]) - Fix an error for `RSpec/ChangeByZero` when `change (...) .by (0)` and `change (...)`, concatenated with `and` and `or`. ([@ydah]) +- Revert an change that would conceal unintentional RSpec syntax. ([@pirj]) ## 3.1.0 (2024-10-01) diff --git a/lib/rubocop/cop/rspec/change_by_zero.rb b/lib/rubocop/cop/rspec/change_by_zero.rb index 75d442c75..82da74193 100644 --- a/lib/rubocop/cop/rspec/change_by_zero.rb +++ b/lib/rubocop/cop/rspec/change_by_zero.rb @@ -118,11 +118,8 @@ def register_offense(node, change_node) # rubocop:enable Metrics/MethodLength def compound_expectations?(node) - if node.parent.send_type? + node.parent.send_type? && %i[and or & |].include?(node.parent.method_name) - else - node.parent.and_type? || node.parent.or_type? - end end def message(change_node) From 6cbe4238dd5a4881758b9504670fb6893bae1be8 Mon Sep 17 00:00:00 2001 From: Phil Pirozhkov Date: Fri, 25 Oct 2024 18:20:12 +0300 Subject: [PATCH 39/40] Update CHANGELOG.md --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1de7a001..14afa61bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,7 @@ ## Master (Unreleased) - Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty. ([@ydah]) -- Fix an error for `RSpec/ChangeByZero` when `change (...) .by (0)` and `change (...)`, concatenated with `and` and `or`. ([@ydah]) -- Revert an change that would conceal unintentional RSpec syntax. ([@pirj]) +- Add support for `and` and `or` compound matchers to `RSpec/ChangeByZero` cop. ([@ydah]) ## 3.1.0 (2024-10-01) From 39b0d3f8c1d6dd720cce3dd37782ee5b0d26d448 Mon Sep 17 00:00:00 2001 From: ydah Date: Sat, 26 Oct 2024 15:50:20 +0900 Subject: [PATCH 40/40] Release v3.2.0 --- CHANGELOG.md | 2 ++ docs/antora.yml | 2 +- lib/rubocop/rspec/version.rb | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2146a165d..73cb05892 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +## 3.2.0 (2024-10-26) + - Fix `RSpec/VoidExpect` to only operate inside an example block. ([@corsonknowles]) - Change `RSpec/ContextWording` cop to always report an offense when both `Prefixes` and `AllowedPatterns` are empty. ([@ydah]) - Add support for `and` and `or` compound matchers to `RSpec/ChangeByZero` cop. ([@ydah]) diff --git a/docs/antora.yml b/docs/antora.yml index 51a533a15..7cca04801 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,5 +1,5 @@ name: rubocop-rspec title: RuboCop RSpec -version: ~ +version: '3.2' nav: - modules/ROOT/nav.adoc diff --git a/lib/rubocop/rspec/version.rb b/lib/rubocop/rspec/version.rb index 334b1761a..e511c3f04 100644 --- a/lib/rubocop/rspec/version.rb +++ b/lib/rubocop/rspec/version.rb @@ -4,7 +4,7 @@ module RuboCop module RSpec # Version information for the RSpec RuboCop plugin. module Version - STRING = '3.1.0' + STRING = '3.2.0' end end end