rubocop-rspec 2.29.1 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +92 -3
  3. data/README.md +21 -5
  4. data/config/default.yml +64 -269
  5. data/config/obsoletion.yml +20 -21
  6. data/lib/rubocop/cop/rspec/around_block.rb +2 -4
  7. data/lib/rubocop/cop/rspec/base.rb +0 -1
  8. data/lib/rubocop/cop/rspec/be_eq.rb +1 -1
  9. data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
  10. data/lib/rubocop/cop/rspec/be_nil.rb +4 -0
  11. data/lib/rubocop/cop/rspec/change_by_zero.rb +4 -5
  12. data/lib/rubocop/cop/rspec/contain_exactly.rb +1 -0
  13. data/lib/rubocop/cop/rspec/context_wording.rb +15 -9
  14. data/lib/rubocop/cop/rspec/dialect.rb +13 -0
  15. data/lib/rubocop/cop/rspec/empty_example_group.rb +2 -0
  16. data/lib/rubocop/cop/rspec/empty_metadata.rb +1 -0
  17. data/lib/rubocop/cop/rspec/example_wording.rb +3 -5
  18. data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +1 -1
  19. data/lib/rubocop/cop/rspec/expect_actual.rb +3 -3
  20. data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
  21. data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
  22. data/lib/rubocop/cop/rspec/focus.rb +14 -16
  23. data/lib/rubocop/cop/rspec/implicit_expect.rb +3 -3
  24. data/lib/rubocop/cop/rspec/implicit_subject.rb +8 -0
  25. data/lib/rubocop/cop/rspec/indexed_let.rb +6 -3
  26. data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
  27. data/lib/rubocop/cop/rspec/match_array.rb +1 -0
  28. data/lib/rubocop/cop/rspec/message_spies.rb +4 -0
  29. data/lib/rubocop/cop/rspec/metadata_style.rb +1 -6
  30. data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
  31. data/lib/rubocop/cop/rspec/mixin/metadata.rb +5 -8
  32. data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +7 -0
  33. data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
  34. data/lib/rubocop/cop/rspec/multiple_expectations.rb +4 -4
  35. data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +4 -5
  36. data/lib/rubocop/cop/rspec/named_subject.rb +5 -2
  37. data/lib/rubocop/cop/rspec/nested_groups.rb +2 -1
  38. data/lib/rubocop/cop/rspec/pending_without_reason.rb +0 -5
  39. data/lib/rubocop/cop/rspec/predicate_matcher.rb +25 -11
  40. data/lib/rubocop/cop/rspec/remove_const.rb +0 -1
  41. data/lib/rubocop/cop/rspec/repeated_subject_call.rb +1 -0
  42. data/lib/rubocop/cop/rspec/return_from_stub.rb +5 -4
  43. data/lib/rubocop/cop/rspec/scattered_setup.rb +7 -1
  44. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +3 -4
  45. data/lib/rubocop/cop/rspec/sort_metadata.rb +22 -8
  46. data/lib/rubocop/cop/rspec/stubbed_mock.rb +15 -10
  47. data/lib/rubocop/cop/rspec/subject_stub.rb +2 -2
  48. data/lib/rubocop/cop/rspec/unspecified_exception.rb +21 -14
  49. data/lib/rubocop/cop/rspec/verified_double_reference.rb +14 -53
  50. data/lib/rubocop/cop/rspec/void_expect.rb +6 -1
  51. data/lib/rubocop/cop/rspec_cops.rb +2 -25
  52. data/lib/rubocop/rspec/concept.rb +0 -1
  53. data/lib/rubocop/rspec/config_formatter.rb +4 -32
  54. data/lib/rubocop/rspec/cop/generator.rb +25 -0
  55. data/lib/rubocop/rspec/description_extractor.rb +2 -2
  56. data/lib/rubocop/rspec/hook.rb +1 -1
  57. data/lib/rubocop/rspec/language.rb +0 -1
  58. data/lib/rubocop/rspec/node.rb +1 -1
  59. data/lib/rubocop/rspec/plugin.rb +37 -0
  60. data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +1 -1
  61. data/lib/rubocop/rspec/version.rb +1 -1
  62. data/lib/rubocop/rspec/wording.rb +2 -4
  63. data/lib/rubocop/rspec.rb +0 -7
  64. data/lib/rubocop-rspec.rb +2 -20
  65. metadata +18 -62
  66. data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +0 -39
  67. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +0 -104
  68. data/lib/rubocop/cop/rspec/capybara/match_style.rb +0 -38
  69. data/lib/rubocop/cop/rspec/capybara/negation_matcher.rb +0 -33
  70. data/lib/rubocop/cop/rspec/capybara/specific_actions.rb +0 -29
  71. data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +0 -24
  72. data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +0 -35
  73. data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +0 -36
  74. data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +0 -35
  75. data/lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb +0 -50
  76. data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +0 -40
  77. data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +0 -29
  78. data/lib/rubocop/cop/rspec/factory_bot/factory_name_style.rb +0 -33
  79. data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +0 -55
  80. data/lib/rubocop/cop/rspec/file_path.rb +0 -179
  81. data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +0 -27
  82. data/lib/rubocop/cop/rspec/rails/have_http_status.rb +0 -35
  83. data/lib/rubocop/cop/rspec/rails/http_status.rb +0 -61
  84. data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +0 -62
  85. data/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +0 -39
  86. data/lib/rubocop/cop/rspec/rails/negation_be_valid.rb +0 -39
  87. data/lib/rubocop/cop/rspec/rails/travel_around.rb +0 -34
  88. data/lib/rubocop/rspec/inject.rb +0 -18
  89. data/lib/rubocop/rspec/language/node_pattern.rb +0 -48
@@ -45,7 +45,7 @@ module RuboCop
45
45
 
46
46
  # @!method eql_type_with_identity(node)
47
47
  def_node_matcher :eql_type_with_identity, <<~PATTERN
48
- (send _ :to $(send nil? :eql {true false int float sym nil}))
48
+ (send _ :to $(send nil? :eql {boolean int float sym nil}))
49
49
  PATTERN
50
50
 
51
51
  def on_send(node)
@@ -48,6 +48,10 @@ module RuboCop
48
48
  check_be_style(node)
49
49
  when :be_nil
50
50
  check_be_nil_style(node)
51
+ else
52
+ # :nocov:
53
+ :noop
54
+ # :nocov:
51
55
  end
52
56
  end
53
57
 
@@ -101,24 +101,23 @@ module RuboCop
101
101
 
102
102
  private
103
103
 
104
- # rubocop:disable Metrics/MethodLength
105
104
  def register_offense(node, change_node)
106
105
  if compound_expectations?(node)
107
- add_offense(node.source_range,
106
+ add_offense(node,
108
107
  message: message_compound(change_node)) do |corrector|
109
108
  autocorrect_compound(corrector, node)
110
109
  end
111
110
  else
112
- add_offense(node.source_range,
111
+ add_offense(node,
113
112
  message: message(change_node)) do |corrector|
114
113
  autocorrect(corrector, node, change_node)
115
114
  end
116
115
  end
117
116
  end
118
- # rubocop:enable Metrics/MethodLength
119
117
 
120
118
  def compound_expectations?(node)
121
- %i[and or & |].include?(node.parent.method_name)
119
+ node.parent.send_type? &&
120
+ %i[and or & |].include?(node.parent.method_name)
122
121
  end
123
122
 
124
123
  def message(change_node)
@@ -6,6 +6,7 @@ module RuboCop
6
6
  # Checks where `contain_exactly` is used.
7
7
  #
8
8
  # This cop checks for the following:
9
+ #
9
10
  # - Prefer `match_array` when matching array values.
10
11
  # - Prefer `be_empty` when using `contain_exactly` with no arguments.
11
12
  #
@@ -12,6 +12,9 @@ module RuboCop
12
12
  #
13
13
  # @see http://www.betterspecs.org/#contexts
14
14
  #
15
+ # If both `Prefixes` and `AllowedPatterns` are empty, this cop will always
16
+ # report an offense. So you need to set at least one of them.
17
+ #
15
18
  # @example `Prefixes` configuration
16
19
  # # .rubocop.yml
17
20
  # # RSpec/ContextWording:
@@ -58,7 +61,9 @@ module RuboCop
58
61
  class ContextWording < Base
59
62
  include AllowedPattern
60
63
 
61
- MSG = 'Context description should match %<patterns>s.'
64
+ MSG_MATCH = 'Context description should match %<patterns>s.'
65
+ MSG_ALWAYS = 'Current settings will always report an offense. Please ' \
66
+ 'add allowed words to `Prefixes` or `AllowedPatterns`.'
62
67
 
63
68
  # @!method context_wording(node)
64
69
  def_node_matcher :context_wording, <<~PATTERN
@@ -67,8 +72,7 @@ module RuboCop
67
72
 
68
73
  def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
69
74
  context_wording(node) do |context|
70
- if bad_pattern?(context)
71
- message = format(MSG, patterns: expect_patterns)
75
+ unless matches_allowed_pattern?(description(context))
72
76
  add_offense(context, message: message)
73
77
  end
74
78
  end
@@ -84,12 +88,6 @@ module RuboCop
84
88
  @prefix_regexes ||= prefixes.map { |pre| /^#{Regexp.escape(pre)}\b/ }
85
89
  end
86
90
 
87
- def bad_pattern?(node)
88
- return false if allowed_patterns.empty?
89
-
90
- !matches_allowed_pattern?(description(node))
91
- end
92
-
93
91
  def description(context)
94
92
  if context.xstr_type?
95
93
  context.value.value
@@ -98,6 +96,14 @@ module RuboCop
98
96
  end
99
97
  end
100
98
 
99
+ def message
100
+ if allowed_patterns.empty?
101
+ MSG_ALWAYS
102
+ else
103
+ format(MSG_MATCH, patterns: expect_patterns)
104
+ end
105
+ end
106
+
101
107
  def expect_patterns
102
108
  inspected = allowed_patterns.map do |pattern|
103
109
  pattern.inspect.gsub(/\A"|"\z/, '/')
@@ -29,6 +29,19 @@ module RuboCop
29
29
  # PreferredMethods:
30
30
  # context: describe
31
31
  #
32
+ # If you were previously using the `RSpec/Capybara/FeatureMethods` cop and
33
+ # want to keep disabling all Capybara-specific methods that have the same
34
+ # native RSpec method (e.g. are just aliases), use the following config:
35
+ #
36
+ # RSpec/Dialect:
37
+ # PreferredMethods:
38
+ # background: :before
39
+ # scenario: :it
40
+ # xscenario: :xit
41
+ # given: :let
42
+ # given!: :let!
43
+ # feature: :describe
44
+ #
32
45
  # You can expect the following behavior:
33
46
  #
34
47
  # @example
@@ -130,6 +130,7 @@ module RuboCop
130
130
  def_node_matcher :examples?, <<~PATTERN
131
131
  {
132
132
  #examples_directly_or_in_block?
133
+ #examples_in_branches?
133
134
  (begin <#examples_directly_or_in_block? ...>)
134
135
  (begin <#examples_in_branches? ...>)
135
136
  }
@@ -170,6 +171,7 @@ module RuboCop
170
171
  end
171
172
 
172
173
  def examples_in_branches?(condition_node)
174
+ return false unless condition_node
173
175
  return false if !condition_node.if_type? && !condition_node.case_type?
174
176
 
175
177
  condition_node.branches.any? { |branch| examples?(branch) }
@@ -21,6 +21,7 @@ module RuboCop
21
21
 
22
22
  def on_metadata(_symbols, hash)
23
23
  return unless hash&.pairs&.empty?
24
+ return if hash.children.any?(&:kwsplat_type?)
24
25
 
25
26
  add_offense(hash) do |corrector|
26
27
  remove_empty_metadata(corrector, hash)
@@ -55,8 +55,8 @@ module RuboCop
55
55
  MSG_INSUFFICIENT_DESCRIPTION = 'Your example description is ' \
56
56
  'insufficient.'
57
57
 
58
- SHOULD_PREFIX = /\Ashould(?:n't)?\b/i.freeze
59
- WILL_PREFIX = /\A(?:will|won't)\b/i.freeze
58
+ SHOULD_PREFIX = /\Ashould(?:n't|n’t)?\b/i.freeze
59
+ WILL_PREFIX = /\A(?:will|won't|won’t)\b/i.freeze
60
60
  IT_PREFIX = /\Ait /i.freeze
61
61
 
62
62
  # @!method it_description(node)
@@ -67,7 +67,6 @@ module RuboCop
67
67
  } ...) ...)
68
68
  PATTERN
69
69
 
70
- # rubocop:disable Metrics/MethodLength
71
70
  def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
72
71
  it_description(node) do |description_node, message|
73
72
  if message.match?(SHOULD_PREFIX)
@@ -82,7 +81,6 @@ module RuboCop
82
81
  end
83
82
  end
84
83
  end
85
- # rubocop:enable Metrics/MethodLength
86
84
 
87
85
  private
88
86
 
@@ -128,7 +126,7 @@ module RuboCop
128
126
  node.node_parts.map { |child_node| text(child_node) }.join
129
127
  when :str
130
128
  node.value
131
- when :begin
129
+ else
132
130
  node.source
133
131
  end
134
132
  end
@@ -100,7 +100,7 @@ module RuboCop
100
100
  node.node_parts.map { |child_node| text(child_node) }.join
101
101
  when :str, :sym
102
102
  node.value
103
- when :begin
103
+ else
104
104
  node.source
105
105
  end
106
106
  end
@@ -65,11 +65,11 @@ module RuboCop
65
65
  )
66
66
  PATTERN
67
67
 
68
- def on_send(node) # rubocop:disable Metrics/MethodLength
68
+ def on_send(node)
69
69
  expect_literal(node) do |actual, send_node, matcher, expected|
70
70
  next if SKIPPED_MATCHERS.include?(matcher)
71
71
 
72
- add_offense(actual.source_range) do |corrector|
72
+ add_offense(actual) do |corrector|
73
73
  next unless CORRECTABLE_MATCHERS.include?(matcher)
74
74
  next if literal?(expected)
75
75
 
@@ -97,7 +97,7 @@ module RuboCop
97
97
 
98
98
  def complex_literal?(node)
99
99
  COMPLEX_LITERALS.include?(node.type) &&
100
- node.each_child_node.all?(&method(:literal?))
100
+ node.each_child_node.all? { |child_node| literal?(child_node) }
101
101
  end
102
102
  end
103
103
  end
@@ -27,7 +27,7 @@ module RuboCop
27
27
  # @!method expectation(node)
28
28
  def_node_search :expectation, '(send nil? #Expectations.all ...)'
29
29
 
30
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
30
+ def on_block(node)
31
31
  return unless hook?(node)
32
32
  return if node.body.nil?
33
33
 
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Do not use `expect` in let.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # let(:foo) do
11
+ # expect(something).to eq 'foo'
12
+ # end
13
+ #
14
+ # # good
15
+ # it do
16
+ # expect(something).to eq 'foo'
17
+ # end
18
+ #
19
+ class ExpectInLet < Base
20
+ MSG = 'Do not use `%<expect>s` in let'
21
+
22
+ # @!method expectation(node)
23
+ def_node_search :expectation, '(send nil? #Expectations.all ...)'
24
+
25
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
26
+ return unless let?(node)
27
+ return if node.body.nil?
28
+
29
+ expectation(node.body) do |expect|
30
+ add_offense(expect.loc.selector, message: message(expect))
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def message(expect)
37
+ format(MSG, expect: expect.method_name)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -29,12 +29,6 @@ module RuboCop
29
29
  # describe 'test' do; end
30
30
  #
31
31
  # # bad
32
- # fdescribe 'test' do; end
33
- #
34
- # # good
35
- # describe 'test' do; end
36
- #
37
- # # bad
38
32
  # shared_examples 'test', focus: true do; end
39
33
  #
40
34
  # # good
@@ -81,23 +75,27 @@ module RuboCop
81
75
  def on_send(node)
82
76
  return if node.chained? || node.each_ancestor(:def, :defs).any?
83
77
 
84
- focus_metadata(node) do |focus|
85
- add_offense(focus) do |corrector|
86
- if focus.pair_type? || focus.str_type? || focus.sym_type?
87
- corrector.remove(with_surrounding(focus))
88
- elsif focus.send_type?
89
- correct_send(corrector, focus)
90
- end
78
+ if focused_block?(node)
79
+ on_focused_block(node)
80
+ else
81
+ metadata(node) do |focus|
82
+ on_metadata(focus)
91
83
  end
92
84
  end
93
85
  end
94
86
 
95
87
  private
96
88
 
97
- def focus_metadata(node, &block)
98
- yield(node) if focused_block?(node)
89
+ def on_focused_block(node)
90
+ add_offense(node) do |corrector|
91
+ correct_send(corrector, node)
92
+ end
93
+ end
99
94
 
100
- metadata(node, &block)
95
+ def on_metadata(node)
96
+ add_offense(node) do |corrector|
97
+ corrector.remove(with_surrounding(node))
98
+ end
101
99
  end
102
100
 
103
101
  def with_surrounding(focus)
@@ -46,7 +46,7 @@ module RuboCop
46
46
 
47
47
  ENFORCED_REPLACEMENTS = alternatives.merge(alternatives.invert).freeze
48
48
 
49
- def on_send(node) # rubocop:disable Metrics/MethodLength
49
+ def on_send(node)
50
50
  return unless (source_range = offending_expect(node))
51
51
 
52
52
  expectation_source = source_range.source
@@ -69,13 +69,13 @@ module RuboCop
69
69
  def offending_expect(node)
70
70
  case implicit_expect(node)
71
71
  when :is_expected
72
- is_expected_range(node.loc)
72
+ range_for_is_expected(node.loc)
73
73
  when :should, :should_not
74
74
  node.loc.selector
75
75
  end
76
76
  end
77
77
 
78
- def is_expected_range(source_map) # rubocop:disable Naming/PredicateName
78
+ def range_for_is_expected(source_map)
79
79
  Parser::Source::Range.new(
80
80
  source_map.expression.source_buffer,
81
81
  source_map.expression.begin_pos,
@@ -107,6 +107,10 @@ module RuboCop
107
107
  corrector.replace(node.location.selector, 'expect(subject).to')
108
108
  when :should_not
109
109
  corrector.replace(node.location.selector, 'expect(subject).not_to')
110
+ else
111
+ # :nocov:
112
+ :noop
113
+ # :nocov:
110
114
  end
111
115
  end
112
116
 
@@ -129,6 +133,10 @@ module RuboCop
129
133
  implicit_subject_in_non_its_and_non_single_line?(node)
130
134
  when :single_statement_only
131
135
  implicit_subject_in_non_its_and_non_single_statement?(node)
136
+ else
137
+ # :nocov:
138
+ :noop
139
+ # :nocov:
132
140
  end
133
141
  end
134
142
 
@@ -48,8 +48,8 @@ module RuboCop
48
48
  include AllowedIdentifiers
49
49
  include AllowedPattern
50
50
 
51
- MSG = 'This `let` statement uses index in its name. Please give it ' \
52
- 'a meaningful name.'
51
+ MSG = 'This `let` statement uses `%<index>s` in its name. ' \
52
+ 'Please give it a meaningful name.'
53
53
 
54
54
  # @!method let_name(node)
55
55
  def_node_matcher :let_name, <<~PATTERN
@@ -66,14 +66,17 @@ module RuboCop
66
66
  return unless children
67
67
 
68
68
  filter_indexed_lets(children).each do |let_node|
69
- add_offense(let_node)
69
+ index = let_name(let_node)[INDEX_REGEX]
70
+ add_offense(let_node, message: format(MSG, index: index))
70
71
  end
71
72
  end
72
73
 
73
74
  private
74
75
 
75
76
  SUFFIX_INDEX_REGEX = /_?\d+$/.freeze
77
+ private_constant :SUFFIX_INDEX_REGEX
76
78
  INDEX_REGEX = /\d+/.freeze
79
+ private_constant :INDEX_REGEX
77
80
 
78
81
  def filter_indexed_lets(candidates)
79
82
  candidates
@@ -119,7 +119,7 @@ module RuboCop
119
119
  private
120
120
 
121
121
  def inside_describe_block?(node)
122
- node.each_ancestor(:block).any?(&method(:spec_group?))
122
+ node.each_ancestor(:block).any? { |ancestor| spec_group?(ancestor) }
123
123
  end
124
124
  end
125
125
  end
@@ -6,6 +6,7 @@ module RuboCop
6
6
  # Checks where `match_array` is used.
7
7
  #
8
8
  # This cop checks for the following:
9
+ #
9
10
  # - Prefer `contain_exactly` when matching an array with values.
10
11
  # - Prefer `eq` when using `match_array` with an empty array literal.
11
12
  #
@@ -80,6 +80,10 @@ module RuboCop
80
80
  MSG_RECEIVE
81
81
  when :have_received
82
82
  format(MSG_HAVE_RECEIVED, source: receiver.source)
83
+ else
84
+ # :nocov:
85
+ :noop
86
+ # :nocov:
83
87
  end
84
88
  end
85
89
  end
@@ -45,13 +45,8 @@ module RuboCop
45
45
  PATTERN
46
46
 
47
47
  def on_metadata(symbols, hash)
48
- # RSpec example groups accept two string arguments. In such a case,
49
- # the rspec_metadata matcher will interpret the second string
50
- # argument as a metadata symbol.
51
- symbols.shift if symbols.first&.str_type?
52
-
53
48
  symbols.each do |symbol|
54
- on_metadata_symbol(symbol)
49
+ on_metadata_symbol(symbol) if symbol.sym_type?
55
50
  end
56
51
 
57
52
  return unless hash
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks if `.to`, `not_to` or `to_not` are used.
7
+ #
8
+ # The RSpec::Expectations::ExpectationTarget must use `to`, `not_to` or
9
+ # `to_not` to run. Therefore, this cop checks if other methods are used.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # expect(something).kind_of? Foo
14
+ # is_expected == 42
15
+ # expect{something}.eq? BarError
16
+ #
17
+ # # good
18
+ # expect(something).to be_a Foo
19
+ # is_expected.to eq 42
20
+ # expect{something}.to raise_error BarError
21
+ #
22
+ class MissingExpectationTargetMethod < Base
23
+ MSG = 'Use `.to`, `.not_to` or `.to_not` to set an expectation.'
24
+ RESTRICT_ON_SEND = %i[expect is_expected].freeze
25
+
26
+ # @!method expect?(node)
27
+ def_node_matcher :expect?, <<~PATTERN
28
+ {
29
+ (send nil? :expect ...)
30
+ (send nil? :is_expected)
31
+ }
32
+ PATTERN
33
+
34
+ # @!method expect_block?(node)
35
+ def_node_matcher :expect_block?, <<~PATTERN
36
+ (block #expect? (args) _body)
37
+ PATTERN
38
+
39
+ # @!method expectation_without_runner?(node)
40
+ def_node_matcher :expectation_without_runner?, <<~PATTERN
41
+ (send {#expect? #expect_block?} !#Runners.all ...)
42
+ PATTERN
43
+
44
+ def on_send(node)
45
+ node = node.parent if node.parent&.block_type?
46
+
47
+ expectation_without_runner?(node.parent) do
48
+ add_offense(node.parent.loc.selector)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -47,15 +47,12 @@ module RuboCop
47
47
  private
48
48
 
49
49
  def on_metadata_arguments(metadata_arguments)
50
- *symbols, last = metadata_arguments
51
- hash = nil
52
- case last&.type
53
- when :hash
54
- hash = last
55
- when :sym
56
- symbols << last
50
+ if metadata_arguments.last&.hash_type?
51
+ *metadata_arguments, hash = metadata_arguments
52
+ on_metadata(metadata_arguments, hash)
53
+ else
54
+ on_metadata(metadata_arguments, nil)
57
55
  end
58
- on_metadata(symbols, hash)
59
56
  end
60
57
  end
61
58
  end
@@ -7,6 +7,10 @@ module RuboCop
7
7
  module TopLevelGroup
8
8
  extend RuboCop::NodePattern::Macros
9
9
 
10
+ DEPRECATED_MODULE_METHOD_WARNING =
11
+ 'top_level_group? is deprecated and will be ' \
12
+ 'removed in the next major version of rubocop_rspec.'
13
+
10
14
  def on_new_investigation
11
15
  super
12
16
 
@@ -28,7 +32,10 @@ module RuboCop
28
32
 
29
33
  def on_top_level_group(_node); end
30
34
 
35
+ # @private
36
+ # @deprecated All callers of this method have been removed.
31
37
  def top_level_group?(node)
38
+ warn DEPRECATED_MODULE_METHOD_WARNING, uplevel: 1
32
39
  top_level_groups.include?(node)
33
40
  end
34
41
 
@@ -30,7 +30,7 @@ module RuboCop
30
30
 
31
31
  def on_top_level_group(node)
32
32
  top_level_example_groups =
33
- top_level_groups.select(&method(:example_group?))
33
+ top_level_groups.select { |group| example_group?(group) }
34
34
 
35
35
  return if top_level_example_groups.one?
36
36
  return unless top_level_example_groups.first.equal?(node)
@@ -67,12 +67,12 @@ module RuboCop
67
67
  # end
68
68
  #
69
69
  class MultipleExpectations < Base
70
- include ConfigurableMax
71
-
72
70
  MSG = 'Example has too many expectations [%<total>d/%<max>d].'
73
71
 
74
72
  ANYTHING = ->(_node) { true }
75
- TRUE = ->(node) { node.true_type? }
73
+ TRUE_NODE = lambda(&:true_type?)
74
+
75
+ exclude_limit 'Max'
76
76
 
77
77
  # @!method aggregate_failures?(node)
78
78
  def_node_matcher :aggregate_failures?, <<~PATTERN
@@ -110,7 +110,7 @@ module RuboCop
110
110
  node_with_aggregate_failures = find_aggregate_failures(example_node)
111
111
  return false unless node_with_aggregate_failures
112
112
 
113
- aggregate_failures?(node_with_aggregate_failures, TRUE)
113
+ aggregate_failures?(node_with_aggregate_failures, TRUE_NODE)
114
114
  end
115
115
 
116
116
  def find_aggregate_failures(example_node)
@@ -82,11 +82,12 @@ module RuboCop
82
82
  # end
83
83
  #
84
84
  class MultipleMemoizedHelpers < Base
85
- include ConfigurableMax
86
85
  include Variable
87
86
 
88
87
  MSG = 'Example group has too many memoized helpers [%<count>d/%<max>d]'
89
88
 
89
+ exclude_limit 'Max'
90
+
90
91
  def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
91
92
  return unless spec_group?(node)
92
93
 
@@ -108,10 +109,8 @@ module RuboCop
108
109
  attr_reader :example_group_memoized_helpers
109
110
 
110
111
  def all_helpers(node)
111
- [
112
- *helpers(node),
113
- *node.each_ancestor(:block).flat_map(&method(:helpers))
114
- ]
112
+ helpers(node) +
113
+ node.each_ancestor(:block).flat_map { |ancestor| helpers(ancestor) }
115
114
  end
116
115
 
117
116
  def helpers(node)
@@ -107,8 +107,11 @@ module RuboCop
107
107
  private
108
108
 
109
109
  def ignored_shared_example?(node)
110
- cop_config['IgnoreSharedExamples'] &&
111
- node.each_ancestor(:block).any?(&method(:shared_example?))
110
+ return false unless cop_config['IgnoreSharedExamples']
111
+
112
+ node.each_ancestor(:block).any? do |ancestor|
113
+ shared_example?(ancestor)
114
+ end
112
115
  end
113
116
 
114
117
  def check_explicit_subject(node)
@@ -92,7 +92,6 @@ module RuboCop
92
92
  # end
93
93
  #
94
94
  class NestedGroups < Base
95
- include ConfigurableMax
96
95
  include TopLevelGroup
97
96
 
98
97
  MSG = 'Maximum example group nesting exceeded [%<total>d/%<max>d].'
@@ -103,6 +102,8 @@ module RuboCop
103
102
  "Configuration key `#{DEPRECATED_MAX_KEY}` for #{cop_name} is " \
104
103
  'deprecated in favor of `Max`. Please use that instead.'
105
104
 
105
+ exclude_limit 'Max'
106
+
106
107
  def on_top_level_group(node)
107
108
  find_nested_example_groups(node) do |example_group, nesting|
108
109
  self.max = nesting