rubocop-rspec 2.11.1 → 2.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -0
  3. data/config/default.yml +15 -0
  4. data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +77 -0
  5. data/lib/rubocop/cop/rspec/change_by_zero.rb +8 -3
  6. data/lib/rubocop/cop/rspec/described_class.rb +1 -1
  7. data/lib/rubocop/cop/rspec/empty_hook.rb +2 -4
  8. data/lib/rubocop/cop/rspec/example_length.rb +1 -1
  9. data/lib/rubocop/cop/rspec/example_without_description.rb +1 -1
  10. data/lib/rubocop/cop/rspec/expect_actual.rb +2 -0
  11. data/lib/rubocop/cop/rspec/expect_change.rb +8 -8
  12. data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +32 -9
  13. data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +1 -1
  14. data/lib/rubocop/cop/rspec/file_path.rb +2 -1
  15. data/lib/rubocop/cop/rspec/focus.rb +2 -4
  16. data/lib/rubocop/cop/rspec/hook_argument.rb +3 -3
  17. data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
  18. data/lib/rubocop/cop/rspec/it_behaves_like.rb +2 -2
  19. data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
  20. data/lib/rubocop/cop/rspec/message_expectation.rb +1 -1
  21. data/lib/rubocop/cop/rspec/message_spies.rb +7 -1
  22. data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +13 -4
  23. data/lib/rubocop/cop/rspec/multiple_expectations.rb +20 -0
  24. data/lib/rubocop/cop/rspec/not_to_not.rb +14 -1
  25. data/lib/rubocop/cop/rspec/rails/have_http_status.rb +47 -0
  26. data/lib/rubocop/cop/rspec/return_from_stub.rb +11 -11
  27. data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
  28. data/lib/rubocop/cop/rspec/yield.rb +1 -1
  29. data/lib/rubocop/cop/rspec_cops.rb +2 -0
  30. data/lib/rubocop/rspec/node.rb +1 -1
  31. data/lib/rubocop/rspec/version.rb +1 -1
  32. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 741b2b87f823e6fab2b693b917568362674a686183a1d00e11fbc24fecf8ae53
4
- data.tar.gz: '089bcc60333425fe0469071f12b52f92671a442274b179f50c716fce1e0a1064'
3
+ metadata.gz: a543787a865d7e8062e0b746c1b5dd641214bd17b17d25182a58b4a646c4bfb6
4
+ data.tar.gz: 57ddde6cfed19062929b00c729dd7403955bf3c92a8b5354cb3704bd7382c5ef
5
5
  SHA512:
6
- metadata.gz: 4f32ff6a813bcb2b427f13541c519d1da616cd051b7fbfbf4d8100fecf4e120e6626271623bd35833555061ef0c19e858934e07c6a8ed72a24cade03b1a59fee
7
- data.tar.gz: 29929728390c1ff9d6804c5babb614649966a60faccacc140f626e4eb78154eff39bb91fc38162fcfcdcdcbbb9593bdad8256f8471867e0dcb5b00abc047c544
6
+ metadata.gz: d4a03f557f7f2e7a7a24f01e14db9e7599ce08c7921618d877b807fd37ef065d97556b428931c4129b19ef1d791e072828fd0f3705797d1ec98c69eb7f25cf45
7
+ data.tar.gz: 0d7bacaeb99c2c60594d507158434e8740c5b2a96032f73db4247cd16ff0963b46de2313d3bf76cf6bb0ed3d33b1751f663062e00cef095ab4310642a4e5153c
data/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 2.12.1 (2022-07-03)
6
+
7
+ * Fix a false positive for `RSpec/Capybara/SpecificMatcher`. ([@ydah][])
8
+
9
+ ## 2.12.0 (2022-07-02)
10
+
11
+ * Fix incorrect path suggested by `RSpec/FilePath` cop when second argument contains spaces. ([@tejasbubane][])
12
+ * Fix autocorrect for EmptyLineSeparation. ([@johnny-miyake][])
13
+ * Add new `RSpec/Capybara/SpecificMatcher` cop. ([@ydah][])
14
+ * Fixed false offense detection in `FactoryBot/CreateList` when a n.times block is including method calls in the factory create arguments. ([@ngouy][])
15
+ * Fix error in `RSpec/RSpec/FactoryBot/CreateList` cop for empty block. ([@tejasbubane][])
16
+ * Update `RSpec/MultipleExpectations` cop documentation with examples of aggregate_failures use. ([@edgibbs][])
17
+ * Declare autocorrect as unsafe for `RSpec/VerifiedDoubleReference`. ([@Drowze][])
18
+ * Add new `RSpec/Rails/HaveHttpStatus` cop. ([@akiomik][])
19
+
5
20
  ## 2.11.1 (2022-05-18)
6
21
 
7
22
  * Fix a regression in `RSpec/ExpectChange` flagging chained method calls. ([@pirj][])
@@ -694,3 +709,8 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
694
709
  [@t3h2mas]: https://github.com/t3h2mas
695
710
  [@M-Yamashita01]: https://github.com/M-Yamashita01
696
711
  [@luke-hill]: https://github.com/luke-hill
712
+ [@johnny-miyake]: https://github.com/johnny-miyake
713
+ [@ngouy]: https://github.com/ngouy
714
+ [@edgibbs]: https://github.com/edgibbs
715
+ [@Drowze]: https://github.com/Drowze
716
+ [@akiomik]: https://github.com/akiomik
data/config/default.yml CHANGED
@@ -783,11 +783,13 @@ RSpec/VariableName:
783
783
  RSpec/VerifiedDoubleReference:
784
784
  Description: Checks for consistent verified double reference style.
785
785
  Enabled: pending
786
+ SafeAutoCorrect: false
786
787
  EnforcedStyle: constant
787
788
  SupportedStyles:
788
789
  - constant
789
790
  - string
790
791
  VersionAdded: 2.10.0
792
+ VersionChanged: '2.12'
791
793
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubleReference
792
794
 
793
795
  RSpec/VerifiedDoubles:
@@ -832,6 +834,12 @@ RSpec/Capybara/FeatureMethods:
832
834
  VersionChanged: '2.0'
833
835
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/FeatureMethods
834
836
 
837
+ RSpec/Capybara/SpecificMatcher:
838
+ Description: Checks for there is a more specific matcher offered by Capybara.
839
+ Enabled: pending
840
+ VersionAdded: '2.12'
841
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/SpecificMatcher
842
+
835
843
  RSpec/Capybara/VisibilityMatcher:
836
844
  Description: Checks for boolean visibility in Capybara finders.
837
845
  Enabled: true
@@ -901,6 +909,13 @@ RSpec/Rails/AvoidSetupHook:
901
909
  VersionAdded: '2.4'
902
910
  Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/AvoidSetupHook
903
911
 
912
+ RSpec/Rails/HaveHttpStatus:
913
+ Description: Checks that tests use `have_http_status` instead of equality matchers.
914
+ Enabled: pending
915
+ SafeAutoCorrect: false
916
+ VersionAdded: '2.12'
917
+ Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HaveHttpStatus
918
+
904
919
  RSpec/Rails/HttpStatus:
905
920
  Description: Enforces use of symbolic or numeric value to describe HTTP status.
906
921
  Enabled: true
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ module Capybara
7
+ # Checks for there is a more specific matcher offered by Capybara.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # expect(page).to have_selector('button')
13
+ # expect(page).to have_no_selector('button.cls')
14
+ # expect(page).to have_css('button')
15
+ # expect(page).to have_no_css('a.cls', exact_text: 'foo')
16
+ # expect(page).to have_css('table.cls')
17
+ # expect(page).to have_css('select')
18
+ #
19
+ # # good
20
+ # expect(page).to have_button
21
+ # expect(page).to have_no_button(class: 'cls')
22
+ # expect(page).to have_button
23
+ # expect(page).to have_no_link('foo', class: 'cls')
24
+ # expect(page).to have_table(class: 'cls')
25
+ # expect(page).to have_select
26
+ #
27
+ class SpecificMatcher < Base
28
+ MSG = 'Prefer `%<good_matcher>s` over `%<bad_matcher>s`.'
29
+ RESTRICT_ON_SEND = %i[have_selector have_no_selector have_css
30
+ have_no_css].freeze
31
+ SPECIFIC_MATCHER = {
32
+ 'button' => 'button',
33
+ 'a' => 'link',
34
+ 'table' => 'table',
35
+ 'select' => 'select'
36
+ }.freeze
37
+
38
+ # @!method first_argument(node)
39
+ def_node_matcher :first_argument, <<-PATTERN
40
+ (send nil? _ (str $_) ... )
41
+ PATTERN
42
+
43
+ def on_send(node)
44
+ return unless (arg = first_argument(node))
45
+ return unless (matcher = specific_matcher(arg))
46
+ return if acceptable_pattern?(arg)
47
+
48
+ add_offense(node, message: message(node, matcher))
49
+ end
50
+
51
+ private
52
+
53
+ def specific_matcher(arg)
54
+ splitted_arg = arg[/^\w+/, 0]
55
+ SPECIFIC_MATCHER[splitted_arg]
56
+ end
57
+
58
+ def acceptable_pattern?(arg)
59
+ arg.match?(/\[.+=\w+\]/) || arg.match?(/[ >,+]/)
60
+ end
61
+
62
+ def message(node, matcher)
63
+ format(MSG,
64
+ good_matcher: good_matcher(node, matcher),
65
+ bad_matcher: node.method_name)
66
+ end
67
+
68
+ def good_matcher(node, matcher)
69
+ node.method_name
70
+ .to_s
71
+ .gsub(/selector|css/, matcher.to_s)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -9,6 +9,8 @@ module RuboCop
9
9
  # # bad
10
10
  # expect { run }.to change(Foo, :bar).by(0)
11
11
  # expect { run }.to change { Foo.bar }.by(0)
12
+ #
13
+ # # bad - compound expectations
12
14
  # expect { run }
13
15
  # .to change(Foo, :bar).by(0)
14
16
  # .and change(Foo, :baz).by(0)
@@ -19,6 +21,9 @@ module RuboCop
19
21
  # # good
20
22
  # expect { run }.not_to change(Foo, :bar)
21
23
  # expect { run }.not_to change { Foo.bar }
24
+ #
25
+ # # good - compound expectations
26
+ # define_negated_matcher :not_change, :change
22
27
  # expect { run }
23
28
  # .to not_change(Foo, :bar)
24
29
  # .and not_change(Foo, :baz)
@@ -52,17 +57,17 @@ module RuboCop
52
57
 
53
58
  def on_send(node)
54
59
  expect_change_with_arguments(node.parent) do
55
- check_offence(node.parent)
60
+ check_offense(node.parent)
56
61
  end
57
62
 
58
63
  expect_change_with_block(node.parent.parent) do
59
- check_offence(node.parent.parent)
64
+ check_offense(node.parent.parent)
60
65
  end
61
66
  end
62
67
 
63
68
  private
64
69
 
65
- def check_offence(node)
70
+ def check_offense(node)
66
71
  expression = node.loc.expression
67
72
  if compound_expectations?(node)
68
73
  add_offense(expression, message: MSG_COMPOUND)
@@ -11,7 +11,7 @@ module RuboCop
11
11
  # This cop can be configured using the `EnforcedStyle` and `SkipBlocks`
12
12
  # options.
13
13
  #
14
- # @example `EnforcedStyle: described_class`
14
+ # @example `EnforcedStyle: described_class` (default)
15
15
  # # bad
16
16
  # describe MyClass do
17
17
  # subject { MyClass.do_something }
@@ -36,11 +36,9 @@ module RuboCop
36
36
  def on_block(node)
37
37
  empty_hook?(node) do |hook|
38
38
  add_offense(hook) do |corrector|
39
- range = range_with_surrounding_space(
40
- range: node.loc.expression,
41
- side: :left
39
+ corrector.remove(
40
+ range_with_surrounding_space(node.loc.expression, side: :left)
42
41
  )
43
- corrector.remove(range)
44
42
  end
45
43
  end
46
44
  end
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Checks for long examples.
7
7
  #
8
8
  # A long example is usually more difficult to understand. Consider
9
- # extracting out some behaviour, e.g. with a `let` block, or a helper
9
+ # extracting out some behavior, e.g. with a `let` block, or a helper
10
10
  # method.
11
11
  #
12
12
  # @example
@@ -14,7 +14,7 @@ module RuboCop
14
14
  #
15
15
  # This cop can be configured using the `EnforcedStyle` option
16
16
  #
17
- # @example `EnforcedStyle: always_allow`
17
+ # @example `EnforcedStyle: always_allow` (default)
18
18
  # # bad
19
19
  # it('') { is_expected.to be_good }
20
20
  # it '' do
@@ -5,6 +5,8 @@ module RuboCop
5
5
  module RSpec
6
6
  # Checks for `expect(...)` calls containing literal values.
7
7
  #
8
+ # Autocorrection is performed when the expected is not a literal.
9
+ #
8
10
  # @example
9
11
  # # bad
10
12
  # expect(5).to eq(price)
@@ -10,14 +10,7 @@ module RuboCop
10
10
  #
11
11
  # This cop can be configured using the `EnforcedStyle` option.
12
12
  #
13
- # @example `EnforcedStyle: block`
14
- # # bad
15
- # expect { run }.to change(Foo, :bar)
16
- #
17
- # # good
18
- # expect { run }.to change { Foo.bar }
19
- #
20
- # @example `EnforcedStyle: method_call`
13
+ # @example `EnforcedStyle: method_call` (default)
21
14
  # # bad
22
15
  # expect { run }.to change { Foo.bar }
23
16
  # expect { run }.to change { foo.baz }
@@ -29,6 +22,13 @@ module RuboCop
29
22
  # expect { run }.to change { Foo.bar(:count) }
30
23
  # expect { run }.to change { user.reload.name }
31
24
  #
25
+ # @example `EnforcedStyle: block`
26
+ # # bad
27
+ # expect { run }.to change(Foo, :bar)
28
+ #
29
+ # # good
30
+ # expect { run }.to change { Foo.bar }
31
+ #
32
32
  class ExpectChange < Base
33
33
  extend AutoCorrector
34
34
  include ConfigurableEnforcedStyle
@@ -8,15 +8,21 @@ module RuboCop
8
8
  #
9
9
  # This cop can be configured using the `EnforcedStyle` option
10
10
  #
11
- # @example `EnforcedStyle: create_list`
11
+ # @example `EnforcedStyle: create_list` (default)
12
12
  # # bad
13
13
  # 3.times { create :user }
14
14
  #
15
15
  # # good
16
16
  # create_list :user, 3
17
17
  #
18
- # # good
19
- # 3.times { |n| create :user, created_at: n.months.ago }
18
+ # # bad
19
+ # 3.times { create :user, age: 18 }
20
+ #
21
+ # # good - index is used to alter the created models attributes
22
+ # 3.times { |n| create :user, age: n }
23
+ #
24
+ # # good - contains a method call, may return different values
25
+ # 3.times { create :user, age: rand }
20
26
  #
21
27
  # @example `EnforcedStyle: n_times`
22
28
  # # bad
@@ -33,15 +39,28 @@ module RuboCop
33
39
  MSG_N_TIMES = 'Prefer %<number>s.times.'
34
40
  RESTRICT_ON_SEND = %i[create_list].freeze
35
41
 
36
- # @!method n_times_block_without_arg?(node)
37
- def_node_matcher :n_times_block_without_arg?, <<-PATTERN
42
+ # @!method n_times_block?(node)
43
+ def_node_matcher :n_times_block?, <<-PATTERN
38
44
  (block
39
45
  (send (int _) :times)
40
- (args)
41
46
  ...
42
47
  )
43
48
  PATTERN
44
49
 
50
+ # @!method n_times_block_with_arg_and_used?(node)
51
+ def_node_matcher :n_times_block_with_arg_and_used?, <<-PATTERN
52
+ (block
53
+ (send (int _) :times)
54
+ (args (arg _value))
55
+ `_value
56
+ )
57
+ PATTERN
58
+
59
+ # @!method arguments_include_method_call?(node)
60
+ def_node_matcher :arguments_include_method_call?, <<-PATTERN
61
+ (send ${nil? #factory_bot?} :create (sym $_) `$(send ...))
62
+ PATTERN
63
+
45
64
  # @!method factory_call(node)
46
65
  def_node_matcher :factory_call, <<-PATTERN
47
66
  (send ${nil? #factory_bot?} :create (sym $_) $...)
@@ -54,7 +73,11 @@ module RuboCop
54
73
 
55
74
  def on_block(node)
56
75
  return unless style == :create_list
57
- return unless n_times_block_without_arg?(node)
76
+
77
+ return unless n_times_block?(node)
78
+ return if n_times_block_with_arg_and_used?(node)
79
+ return unless node.body
80
+ return if arguments_include_method_call?(node.body)
58
81
  return unless contains_only_factory?(node.body)
59
82
 
60
83
  add_offense(node.send_node, message: MSG_CREATE_LIST) do |corrector|
@@ -193,7 +216,7 @@ module RuboCop
193
216
  if node.body.begin_type?
194
217
  format_multiline_block(node)
195
218
  else
196
- format_singeline_block(node)
219
+ format_singleline_block(node)
197
220
  end
198
221
  end
199
222
 
@@ -205,7 +228,7 @@ module RuboCop
205
228
  "#{indent_end}end"
206
229
  end
207
230
 
208
- def format_singeline_block(node)
231
+ def format_singleline_block(node)
209
232
  " { #{node.arguments.source} #{node.body.source} }"
210
233
  end
211
234
  end
@@ -7,7 +7,7 @@ module RuboCop
7
7
  # Use shorthands from `FactoryBot::Syntax::Methods` in your specs.
8
8
  #
9
9
  # @safety
10
- # The auto-correction is marked as unsafe because the cop
10
+ # The autocorrection is marked as unsafe because the cop
11
11
  # cannot verify whether you already include
12
12
  # `FactoryBot::Syntax::Methods` in your test suite.
13
13
  #
@@ -117,8 +117,9 @@ module RuboCop
117
117
 
118
118
  def name_pattern(method_name)
119
119
  return unless method_name&.str_type?
120
+ return if ignore_methods?
120
121
 
121
- ".*#{method_name.str_content.gsub(/\W/, '')}" unless ignore_methods?
122
+ ".*#{method_name.str_content.gsub(/\s/, '_').gsub(/\W/, '')}"
122
123
  end
123
124
 
124
125
  def expected_path(constant)
@@ -69,10 +69,8 @@ module RuboCop
69
69
  end
70
70
 
71
71
  def with_surrounding(focus)
72
- range_with_space = range_with_surrounding_space(
73
- range: focus.loc.expression,
74
- side: :left
75
- )
72
+ range_with_space =
73
+ range_with_surrounding_space(focus.loc.expression, side: :left)
76
74
 
77
75
  range_with_surrounding_comma(range_with_space, :left)
78
76
  end
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # styles: "implicit", "each", and "example." All styles have
11
11
  # the same behavior.
12
12
  #
13
- # @example when configuration is `EnforcedStyle: implicit`
13
+ # @example `EnforcedStyle: implicit` (default)
14
14
  # # bad
15
15
  # before(:each) do
16
16
  # # ...
@@ -26,7 +26,7 @@ module RuboCop
26
26
  # # ...
27
27
  # end
28
28
  #
29
- # @example when configuration is `EnforcedStyle: each`
29
+ # @example `EnforcedStyle: each`
30
30
  # # bad
31
31
  # before(:example) do
32
32
  # # ...
@@ -42,7 +42,7 @@ module RuboCop
42
42
  # # ...
43
43
  # end
44
44
  #
45
- # @example when configuration is `EnforcedStyle: example`
45
+ # @example `EnforcedStyle: example`
46
46
  # # bad
47
47
  # before(:each) do
48
48
  # # ...
@@ -8,7 +8,7 @@ module RuboCop
8
8
  # This cop can be configured using the `EnforcedStyle` option
9
9
  # and supports the `--auto-gen-config` flag.
10
10
  #
11
- # @example `EnforcedStyle: is_expected`
11
+ # @example `EnforcedStyle: is_expected` (default)
12
12
  #
13
13
  # # bad
14
14
  # it { should be_truthy }
@@ -5,14 +5,14 @@ module RuboCop
5
5
  module RSpec
6
6
  # Checks that only one `it_behaves_like` style is used.
7
7
  #
8
- # @example when configuration is `EnforcedStyle: it_behaves_like`
8
+ # @example `EnforcedStyle: it_behaves_like` (default)
9
9
  # # bad
10
10
  # it_should_behave_like 'a foo'
11
11
  #
12
12
  # # good
13
13
  # it_behaves_like 'a foo'
14
14
  #
15
- # @example when configuration is `EnforcedStyle: it_should_behave_like`
15
+ # @example `EnforcedStyle: it_should_behave_like`
16
16
  # # bad
17
17
  # it_behaves_like 'a foo'
18
18
  #
@@ -10,7 +10,7 @@ module RuboCop
10
10
  #
11
11
  # If several examples may define a `DummyClass`, instead of being a
12
12
  # blank slate class as it will be in the first example, subsequent
13
- # examples will be reopening it and modifying its behaviour in
13
+ # examples will be reopening it and modifying its behavior in
14
14
  # unpredictable ways.
15
15
  # Even worse when a class that exists in the codebase is reopened.
16
16
  #
@@ -8,7 +8,7 @@ module RuboCop
8
8
  # This cop can be configured in your configuration using the
9
9
  # `EnforcedStyle` option and supports `--auto-gen-config`.
10
10
  #
11
- # @example `EnforcedStyle: allow`
11
+ # @example `EnforcedStyle: allow` (default)
12
12
  #
13
13
  # # bad
14
14
  # expect(foo).to receive(:bar)
@@ -8,21 +8,27 @@ module RuboCop
8
8
  # This cop can be configured in your configuration using the
9
9
  # `EnforcedStyle` option and supports `--auto-gen-config`.
10
10
  #
11
- # @example `EnforcedStyle: have_received`
11
+ # @example `EnforcedStyle: have_received` (default)
12
12
  #
13
13
  # # bad
14
14
  # expect(foo).to receive(:bar)
15
+ # do_something
15
16
  #
16
17
  # # good
18
+ # allow(foo).to receive(:bar) # or use instance_spy
19
+ # do_something
17
20
  # expect(foo).to have_received(:bar)
18
21
  #
19
22
  # @example `EnforcedStyle: receive`
20
23
  #
21
24
  # # bad
25
+ # allow(foo).to receive(:bar)
26
+ # do_something
22
27
  # expect(foo).to have_received(:bar)
23
28
  #
24
29
  # # good
25
30
  # expect(foo).to receive(:bar)
31
+ # do_something
26
32
  #
27
33
  class MessageSpies < Base
28
34
  include ConfigurableEnforcedStyle
@@ -4,7 +4,10 @@ module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
6
  # Helps determine the offending location if there is not an empty line
7
- # following the node. Allows comments to follow directly after.
7
+ # following the node. Allows comments to follow directly after
8
+ # in the following cases.
9
+ # - `rubocop:enable` directive
10
+ # - followed by empty line(s)
8
11
  module EmptyLineSeparation
9
12
  include FinalEndLocation
10
13
  include RangeHelp
@@ -21,13 +24,19 @@ module RuboCop
21
24
  end
22
25
 
23
26
  def missing_separating_line(node)
24
- line = final_end_location(node).line
27
+ line = final_end_line = final_end_location(node).line
25
28
 
26
- line += 1 while comment_line?(processed_source[line])
29
+ while comment_line?(processed_source[line])
30
+ line += 1
31
+ comment = processed_source.comment_at_line(line)
32
+ if DirectiveComment.new(comment).enabled?
33
+ enable_directive_line = line
34
+ end
35
+ end
27
36
 
28
37
  return if processed_source[line].blank?
29
38
 
30
- yield offending_loc(line)
39
+ yield offending_loc(enable_directive_line || final_end_line)
31
40
  end
32
41
 
33
42
  def offending_loc(last_line)
@@ -31,6 +31,26 @@ module RuboCop
31
31
  # end
32
32
  # end
33
33
  #
34
+ # @example `aggregate_failures: true` (default)
35
+ #
36
+ # # good - the cop ignores when RSpec aggregates failures
37
+ # describe UserCreator do
38
+ # it 'builds a user', :aggregate_failures do
39
+ # expect(user.name).to eq("John")
40
+ # expect(user.age).to eq(22)
41
+ # end
42
+ # end
43
+ #
44
+ # @example `aggregate_failures: false`
45
+ #
46
+ # # Detected as an offense
47
+ # describe UserCreator do
48
+ # it 'builds a user', aggregate_failures: false do
49
+ # expect(user.name).to eq("John")
50
+ # expect(user.age).to eq(22)
51
+ # end
52
+ # end
53
+ #
34
54
  # @example configuration
35
55
  #
36
56
  # # .rubocop.yml
@@ -5,7 +5,8 @@ module RuboCop
5
5
  module RSpec
6
6
  # Checks for consistent method usage for negating expectations.
7
7
  #
8
- # @example
8
+ # @example `EnforcedStyle: not_to` (default)
9
+ #
9
10
  # # bad
10
11
  # it '...' do
11
12
  # expect(false).to_not be_true
@@ -15,6 +16,18 @@ module RuboCop
15
16
  # it '...' do
16
17
  # expect(false).not_to be_true
17
18
  # end
19
+ #
20
+ # @example `EnforcedStyle: to_not`
21
+ #
22
+ # # bad
23
+ # it '...' do
24
+ # expect(false).not_to be_true
25
+ # end
26
+ #
27
+ # # good
28
+ # it '...' do
29
+ # expect(false).to_not be_true
30
+ # end
18
31
  class NotToNot < Base
19
32
  extend AutoCorrector
20
33
  include ConfigurableEnforcedStyle
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ module Rails
7
+ # Checks that tests use `have_http_status` instead of equality matchers.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # expect(response.status).to be(200)
12
+ #
13
+ # # good
14
+ # expect(response).to have_http_status(200)
15
+ #
16
+ class HaveHttpStatus < Base
17
+ extend AutoCorrector
18
+
19
+ MSG =
20
+ 'Prefer `expect(response).%<to>s have_http_status(%<status>i)` ' \
21
+ 'over `expect(response.status).%<to>s %<match>s`.'
22
+
23
+ # @!method match_status(node)
24
+ def_node_matcher :match_status, <<-PATTERN
25
+ (send
26
+ (send nil? :expect
27
+ $(send (send nil? :response) :status)
28
+ )
29
+ $#Runners.all
30
+ $(send nil? {:be :eq :eql :equal} (int $_))
31
+ )
32
+ PATTERN
33
+
34
+ def on_send(node)
35
+ match_status(node) do |response_status, to, match, status|
36
+ message = format(MSG, to: to, match: match.source, status: status)
37
+ add_offense(node, message: message) do |corrector|
38
+ corrector.replace(response_status.source_range, 'response')
39
+ corrector.replace(match.loc.selector, 'have_http_status')
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -11,6 +11,17 @@ module RuboCop
11
11
  #
12
12
  # This cop can be configured using the `EnforcedStyle` option
13
13
  #
14
+ # @example `EnforcedStyle: and_return` (default)
15
+ # # bad
16
+ # allow(Foo).to receive(:bar) { "baz" }
17
+ # expect(Foo).to receive(:bar) { "baz" }
18
+ #
19
+ # # good
20
+ # allow(Foo).to receive(:bar).and_return("baz")
21
+ # expect(Foo).to receive(:bar).and_return("baz")
22
+ # # also good as the returned value is dynamic
23
+ # allow(Foo).to receive(:bar) { bar.baz }
24
+ #
14
25
  # @example `EnforcedStyle: block`
15
26
  # # bad
16
27
  # allow(Foo).to receive(:bar).and_return("baz")
@@ -22,17 +33,6 @@ module RuboCop
22
33
  # # also good as the returned value is dynamic
23
34
  # allow(Foo).to receive(:bar).and_return(bar.baz)
24
35
  #
25
- # @example `EnforcedStyle: and_return`
26
- # # bad
27
- # allow(Foo).to receive(:bar) { "baz" }
28
- # expect(Foo).to receive(:bar) { "baz" }
29
- #
30
- # # good
31
- # allow(Foo).to receive(:bar).and_return("baz")
32
- # expect(Foo).to receive(:bar).and_return("baz")
33
- # # also good as the returned value is dynamic
34
- # allow(Foo).to receive(:bar) { bar.baz }
35
- #
36
36
  class ReturnFromStub < Base
37
37
  extend AutoCorrector
38
38
  include ConfigurableEnforcedStyle
@@ -35,7 +35,7 @@ module RuboCop
35
35
  occurrences.each do |occurrence|
36
36
  lines_except_current = lines - [occurrence.first_line]
37
37
  message = format(MSG, hook_name: occurrences.first.method_name,
38
- lines: lines_msg(lines_except_current))
38
+ lines: lines_msg(lines_except_current))
39
39
  add_offense(occurrence, message: message)
40
40
  end
41
41
  end
@@ -44,7 +44,7 @@ module RuboCop
44
44
 
45
45
  def autocorrect(corrector, node, range)
46
46
  corrector.replace(
47
- range_with_surrounding_space(range: range, side: :left),
47
+ range_with_surrounding_space(range, side: :left),
48
48
  generate_replacement(node.body)
49
49
  )
50
50
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'rspec/capybara/current_path_expectation'
4
4
  require_relative 'rspec/capybara/feature_methods'
5
+ require_relative 'rspec/capybara/specific_matcher'
5
6
  require_relative 'rspec/capybara/visibility_matcher'
6
7
 
7
8
  require_relative 'rspec/factory_bot/attribute_defined_statically'
@@ -10,6 +11,7 @@ require_relative 'rspec/factory_bot/factory_class_name'
10
11
  require_relative 'rspec/factory_bot/syntax_methods'
11
12
 
12
13
  require_relative 'rspec/rails/avoid_setup_hook'
14
+ require_relative 'rspec/rails/have_http_status'
13
15
  begin
14
16
  require_relative 'rspec/rails/http_status'
15
17
  rescue LoadError
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module RSpec
5
5
  # RuboCop RSpec specific extensions of RuboCop::AST::Node
6
6
  module Node
7
- # In various cops we want to regard const as literal althought it's not
7
+ # In various cops we want to regard const as literal although it's not
8
8
  # strictly literal.
9
9
  def recursive_literal_or_const?
10
10
  case type
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module RSpec
5
5
  # Version information for the RSpec RuboCop plugin.
6
6
  module Version
7
- STRING = '2.11.1'
7
+ STRING = '2.12.1'
8
8
  end
9
9
  end
10
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.11.1
4
+ version: 2.12.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Backus
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-05-18 00:00:00.000000000 Z
13
+ date: 2022-07-03 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubocop
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - "~>"
20
20
  - !ruby/object:Gem::Version
21
- version: '1.19'
21
+ version: '1.31'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
- version: '1.19'
28
+ version: '1.31'
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: rack
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -141,6 +141,7 @@ files:
141
141
  - lib/rubocop/cop/rspec/before_after_all.rb
142
142
  - lib/rubocop/cop/rspec/capybara/current_path_expectation.rb
143
143
  - lib/rubocop/cop/rspec/capybara/feature_methods.rb
144
+ - lib/rubocop/cop/rspec/capybara/specific_matcher.rb
144
145
  - lib/rubocop/cop/rspec/capybara/visibility_matcher.rb
145
146
  - lib/rubocop/cop/rspec/change_by_zero.rb
146
147
  - lib/rubocop/cop/rspec/context_method.rb
@@ -207,6 +208,7 @@ files:
207
208
  - lib/rubocop/cop/rspec/pending.rb
208
209
  - lib/rubocop/cop/rspec/predicate_matcher.rb
209
210
  - lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb
211
+ - lib/rubocop/cop/rspec/rails/have_http_status.rb
210
212
  - lib/rubocop/cop/rspec/rails/http_status.rb
211
213
  - lib/rubocop/cop/rspec/receive_counts.rb
212
214
  - lib/rubocop/cop/rspec/receive_never.rb