rubocop-rspec 2.29.1 → 3.5.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +92 -3
- data/README.md +21 -5
- data/config/default.yml +64 -269
- data/config/obsoletion.yml +20 -21
- data/lib/rubocop/cop/rspec/around_block.rb +2 -4
- data/lib/rubocop/cop/rspec/base.rb +0 -1
- data/lib/rubocop/cop/rspec/be_eq.rb +1 -1
- data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
- data/lib/rubocop/cop/rspec/be_nil.rb +4 -0
- data/lib/rubocop/cop/rspec/change_by_zero.rb +4 -5
- data/lib/rubocop/cop/rspec/contain_exactly.rb +1 -0
- data/lib/rubocop/cop/rspec/context_wording.rb +15 -9
- data/lib/rubocop/cop/rspec/dialect.rb +13 -0
- data/lib/rubocop/cop/rspec/empty_example_group.rb +2 -0
- data/lib/rubocop/cop/rspec/empty_metadata.rb +1 -0
- data/lib/rubocop/cop/rspec/example_wording.rb +3 -5
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_actual.rb +3 -3
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
- data/lib/rubocop/cop/rspec/focus.rb +14 -16
- data/lib/rubocop/cop/rspec/implicit_expect.rb +3 -3
- data/lib/rubocop/cop/rspec/implicit_subject.rb +8 -0
- data/lib/rubocop/cop/rspec/indexed_let.rb +6 -3
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
- data/lib/rubocop/cop/rspec/match_array.rb +1 -0
- data/lib/rubocop/cop/rspec/message_spies.rb +4 -0
- data/lib/rubocop/cop/rspec/metadata_style.rb +1 -6
- data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/metadata.rb +5 -8
- data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +7 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +4 -4
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +4 -5
- data/lib/rubocop/cop/rspec/named_subject.rb +5 -2
- data/lib/rubocop/cop/rspec/nested_groups.rb +2 -1
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +0 -5
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +25 -11
- data/lib/rubocop/cop/rspec/remove_const.rb +0 -1
- data/lib/rubocop/cop/rspec/repeated_subject_call.rb +1 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +5 -4
- data/lib/rubocop/cop/rspec/scattered_setup.rb +7 -1
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +3 -4
- data/lib/rubocop/cop/rspec/sort_metadata.rb +22 -8
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +15 -10
- data/lib/rubocop/cop/rspec/subject_stub.rb +2 -2
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +21 -14
- data/lib/rubocop/cop/rspec/verified_double_reference.rb +14 -53
- data/lib/rubocop/cop/rspec/void_expect.rb +6 -1
- data/lib/rubocop/cop/rspec_cops.rb +2 -25
- data/lib/rubocop/rspec/concept.rb +0 -1
- data/lib/rubocop/rspec/config_formatter.rb +4 -32
- data/lib/rubocop/rspec/cop/generator.rb +25 -0
- data/lib/rubocop/rspec/description_extractor.rb +2 -2
- data/lib/rubocop/rspec/hook.rb +1 -1
- data/lib/rubocop/rspec/language.rb +0 -1
- data/lib/rubocop/rspec/node.rb +1 -1
- data/lib/rubocop/rspec/plugin.rb +37 -0
- data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +1 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop/rspec/wording.rb +2 -4
- data/lib/rubocop/rspec.rb +0 -7
- data/lib/rubocop-rspec.rb +2 -20
- metadata +18 -62
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +0 -39
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +0 -104
- data/lib/rubocop/cop/rspec/capybara/match_style.rb +0 -38
- data/lib/rubocop/cop/rspec/capybara/negation_matcher.rb +0 -33
- data/lib/rubocop/cop/rspec/capybara/specific_actions.rb +0 -29
- data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +0 -24
- data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +0 -35
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +0 -36
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +0 -35
- data/lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb +0 -50
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +0 -40
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +0 -29
- data/lib/rubocop/cop/rspec/factory_bot/factory_name_style.rb +0 -33
- data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +0 -55
- data/lib/rubocop/cop/rspec/file_path.rb +0 -179
- data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +0 -27
- data/lib/rubocop/cop/rspec/rails/have_http_status.rb +0 -35
- data/lib/rubocop/cop/rspec/rails/http_status.rb +0 -61
- data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +0 -62
- data/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +0 -39
- data/lib/rubocop/cop/rspec/rails/negation_be_valid.rb +0 -39
- data/lib/rubocop/cop/rspec/rails/travel_around.rb +0 -34
- data/lib/rubocop/rspec/inject.rb +0 -18
- 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 {
|
48
|
+
(send _ :to $(send nil? :eql {boolean int float sym nil}))
|
49
49
|
PATTERN
|
50
50
|
|
51
51
|
def on_send(node)
|
@@ -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
|
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
|
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
|
-
|
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)
|
@@ -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
|
-
|
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
|
-
|
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) }
|
@@ -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
|
-
|
129
|
+
else
|
132
130
|
node.source
|
133
131
|
end
|
134
132
|
end
|
@@ -65,11 +65,11 @@ module RuboCop
|
|
65
65
|
)
|
66
66
|
PATTERN
|
67
67
|
|
68
|
-
def on_send(node)
|
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
|
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?
|
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)
|
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
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
98
|
-
|
89
|
+
def on_focused_block(node)
|
90
|
+
add_offense(node) do |corrector|
|
91
|
+
correct_send(corrector, node)
|
92
|
+
end
|
93
|
+
end
|
99
94
|
|
100
|
-
|
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)
|
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
|
-
|
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
|
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.
|
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
|
-
|
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
|
@@ -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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
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
|
-
|
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,
|
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
|
-
|
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
|
-
|
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
|