rubocop-rspec 2.21.0 → 3.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +147 -9
- data/README.md +2 -2
- data/config/default.yml +159 -244
- data/config/obsoletion.yml +24 -0
- data/lib/rubocop/cop/rspec/around_block.rb +3 -3
- data/lib/rubocop/cop/rspec/base.rb +0 -1
- data/lib/rubocop/cop/rspec/be.rb +1 -1
- data/lib/rubocop/cop/rspec/be_empty.rb +1 -0
- 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 +2 -2
- data/lib/rubocop/cop/rspec/before_after_all.rb +7 -13
- data/lib/rubocop/cop/rspec/change_by_zero.rb +30 -4
- data/lib/rubocop/cop/rspec/context_method.rb +2 -2
- data/lib/rubocop/cop/rspec/context_wording.rb +1 -1
- data/lib/rubocop/cop/rspec/describe_symbol.rb +1 -1
- data/lib/rubocop/cop/rspec/described_class.rb +33 -11
- data/lib/rubocop/cop/rspec/dialect.rb +13 -0
- data/lib/rubocop/cop/rspec/duplicated_metadata.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_example_group.rb +4 -1
- data/lib/rubocop/cop/rspec/empty_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +2 -2
- data/lib/rubocop/cop/rspec/empty_metadata.rb +46 -0
- data/lib/rubocop/cop/rspec/empty_output.rb +47 -0
- data/lib/rubocop/cop/rspec/eq.rb +47 -0
- data/lib/rubocop/cop/rspec/example_length.rb +11 -5
- data/lib/rubocop/cop/rspec/example_without_description.rb +11 -2
- data/lib/rubocop/cop/rspec/example_wording.rb +11 -2
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +14 -5
- data/lib/rubocop/cop/rspec/expect_actual.rb +17 -14
- data/lib/rubocop/cop/rspec/expect_change.rb +2 -2
- 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/expect_output.rb +1 -4
- data/lib/rubocop/cop/rspec/focus.rb +17 -2
- data/lib/rubocop/cop/rspec/hook_argument.rb +2 -2
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +1 -1
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +2 -2
- data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
- data/lib/rubocop/cop/rspec/implicit_subject.rb +2 -2
- data/lib/rubocop/cop/rspec/indexed_let.rb +32 -1
- data/lib/rubocop/cop/rspec/instance_spy.rb +2 -2
- data/lib/rubocop/cop/rspec/instance_variable.rb +4 -4
- data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +3 -3
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +2 -2
- data/lib/rubocop/cop/rspec/let_before_examples.rb +5 -1
- data/lib/rubocop/cop/rspec/let_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/message_expectation.rb +1 -2
- data/lib/rubocop/cop/rspec/message_spies.rb +0 -2
- data/lib/rubocop/cop/rspec/metadata_style.rb +202 -0
- data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/file_help.rb +14 -0
- data/lib/rubocop/cop/rspec/mixin/metadata.rb +21 -7
- data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +2 -2
- data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +16 -11
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +2 -4
- data/lib/rubocop/cop/rspec/named_subject.rb +6 -3
- data/lib/rubocop/cop/rspec/pending.rb +12 -2
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +1 -1
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +10 -10
- data/lib/rubocop/cop/rspec/receive_counts.rb +1 -1
- data/lib/rubocop/cop/rspec/receive_messages.rb +161 -0
- data/lib/rubocop/cop/rspec/redundant_predicate_matcher.rb +67 -0
- data/lib/rubocop/cop/rspec/remove_const.rb +39 -0
- data/lib/rubocop/cop/rspec/repeated_example.rb +6 -6
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +2 -2
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_subject_call.rb +125 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +1 -1
- data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_context.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_examples.rb +66 -20
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +2 -3
- data/lib/rubocop/cop/rspec/sort_metadata.rb +3 -2
- data/lib/rubocop/cop/rspec/spec_file_path_format.rb +133 -0
- data/lib/rubocop/cop/rspec/spec_file_path_suffix.rb +40 -0
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +4 -2
- data/lib/rubocop/cop/rspec/subject_stub.rb +6 -6
- data/lib/rubocop/cop/rspec/undescriptive_literals_description.rb +69 -0
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +2 -2
- data/lib/rubocop/cop/rspec/variable_definition.rb +4 -4
- data/lib/rubocop/cop/rspec/verified_double_reference.rb +6 -6
- data/lib/rubocop/cop/rspec/verified_doubles.rb +2 -2
- data/lib/rubocop/cop/rspec/void_expect.rb +4 -3
- data/lib/rubocop/cop/rspec_cops.rb +14 -28
- data/lib/rubocop/rspec/concept.rb +0 -1
- data/lib/rubocop/rspec/config_formatter.rb +1 -11
- data/lib/rubocop/rspec/cop/generator.rb +25 -0
- data/lib/rubocop/rspec/language.rb +8 -9
- data/lib/rubocop/rspec/node.rb +1 -1
- 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 +8 -0
- data/lib/rubocop-rspec.rb +2 -16
- metadata +27 -49
- 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 -128
- data/lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb +0 -117
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +0 -260
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +0 -56
- data/lib/rubocop/cop/rspec/factory_bot/factory_name_style.rb +0 -74
- data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +0 -89
- data/lib/rubocop/cop/rspec/file_path.rb +0 -173
- data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +0 -43
- data/lib/rubocop/cop/rspec/rails/have_http_status.rb +0 -55
- data/lib/rubocop/cop/rspec/rails/http_status.rb +0 -203
- data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +0 -145
- data/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +0 -60
- data/lib/rubocop/cop/rspec/rails/travel_around.rb +0 -92
- data/lib/rubocop/rspec/factory_bot/language.rb +0 -37
- data/lib/rubocop/rspec/factory_bot.rb +0 -64
- data/lib/rubocop/rspec/language/node_pattern.rb +0 -48
@@ -0,0 +1,202 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Use consistent metadata style.
|
7
|
+
#
|
8
|
+
# This cop does not support autocorrection in the case of
|
9
|
+
# `EnforcedStyle: hash` where the trailing metadata type is ambiguous.
|
10
|
+
# (e.g. `describe 'Something', :a, b`)
|
11
|
+
#
|
12
|
+
# @example EnforcedStyle: symbol (default)
|
13
|
+
# # bad
|
14
|
+
# describe 'Something', a: true
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# describe 'Something', :a
|
18
|
+
#
|
19
|
+
# @example EnforcedStyle: hash
|
20
|
+
# # bad
|
21
|
+
# describe 'Something', :a
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# describe 'Something', a: true
|
25
|
+
class MetadataStyle < Base # rubocop:disable Metrics/ClassLength
|
26
|
+
extend AutoCorrector
|
27
|
+
|
28
|
+
include ConfigurableEnforcedStyle
|
29
|
+
include Metadata
|
30
|
+
include RangeHelp
|
31
|
+
|
32
|
+
# @!method extract_metadata_hash(node)
|
33
|
+
def_node_matcher :extract_metadata_hash, <<~PATTERN
|
34
|
+
(send _ _ _ ... $hash)
|
35
|
+
PATTERN
|
36
|
+
|
37
|
+
# @!method match_boolean_metadata_pair?(node)
|
38
|
+
def_node_matcher :match_boolean_metadata_pair?, <<~PATTERN
|
39
|
+
(pair sym true)
|
40
|
+
PATTERN
|
41
|
+
|
42
|
+
# @!method match_ambiguous_trailing_metadata?(node)
|
43
|
+
def_node_matcher :match_ambiguous_trailing_metadata?, <<~PATTERN
|
44
|
+
(send _ _ _ ... !{hash sym})
|
45
|
+
PATTERN
|
46
|
+
|
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
|
+
symbols.each do |symbol|
|
54
|
+
on_metadata_symbol(symbol)
|
55
|
+
end
|
56
|
+
|
57
|
+
return unless hash
|
58
|
+
|
59
|
+
hash.pairs.each do |pair|
|
60
|
+
on_metadata_pair(pair)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def autocorrect_pair(corrector, node)
|
67
|
+
remove_pair(corrector, node)
|
68
|
+
insert_symbol(corrector, node)
|
69
|
+
end
|
70
|
+
|
71
|
+
def autocorrect_symbol(corrector, node)
|
72
|
+
return if match_ambiguous_trailing_metadata?(node.parent)
|
73
|
+
|
74
|
+
remove_symbol(corrector, node)
|
75
|
+
insert_pair(corrector, node)
|
76
|
+
end
|
77
|
+
|
78
|
+
def bad_metadata_pair?(node)
|
79
|
+
style == :symbol && match_boolean_metadata_pair?(node)
|
80
|
+
end
|
81
|
+
|
82
|
+
def bad_metadata_symbol?(_node)
|
83
|
+
style == :hash
|
84
|
+
end
|
85
|
+
|
86
|
+
def format_symbol_to_pair_source(node)
|
87
|
+
"#{node.value}: true"
|
88
|
+
end
|
89
|
+
|
90
|
+
def insert_pair(corrector, node)
|
91
|
+
hash_node = extract_metadata_hash(node.parent)
|
92
|
+
if hash_node.nil?
|
93
|
+
insert_pair_as_last_argument(corrector, node)
|
94
|
+
elsif hash_node.pairs.any?
|
95
|
+
insert_pair_to_non_empty_hash_metadata(corrector, node, hash_node)
|
96
|
+
else
|
97
|
+
insert_pair_to_empty_hash_metadata(corrector, node, hash_node)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def insert_pair_as_last_argument(corrector, node)
|
102
|
+
corrector.insert_before(
|
103
|
+
node.parent.location.end || node.parent.source_range.with(
|
104
|
+
begin_pos: node.parent.source_range.end_pos
|
105
|
+
),
|
106
|
+
", #{format_symbol_to_pair_source(node)}"
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
def insert_pair_to_empty_hash_metadata(corrector, node, hash_node)
|
111
|
+
corrector.insert_after(
|
112
|
+
hash_node.location.begin,
|
113
|
+
" #{format_symbol_to_pair_source(node)} "
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
def insert_pair_to_non_empty_hash_metadata(corrector, node, hash_node)
|
118
|
+
corrector.insert_after(
|
119
|
+
hash_node.children.last,
|
120
|
+
", #{format_symbol_to_pair_source(node)}"
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
def insert_symbol(corrector, node)
|
125
|
+
corrector.insert_after(
|
126
|
+
node.parent.left_sibling,
|
127
|
+
", #{node.key.value.inspect}"
|
128
|
+
)
|
129
|
+
end
|
130
|
+
|
131
|
+
def message_for_style
|
132
|
+
format(
|
133
|
+
'Use %<style>s style for metadata.',
|
134
|
+
style: style
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
138
|
+
def on_metadata_pair(node)
|
139
|
+
return unless bad_metadata_pair?(node)
|
140
|
+
|
141
|
+
add_offense(node, message: message_for_style) do |corrector|
|
142
|
+
autocorrect_pair(corrector, node)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def on_metadata_symbol(node)
|
147
|
+
return unless bad_metadata_symbol?(node)
|
148
|
+
|
149
|
+
add_offense(node, message: message_for_style) do |corrector|
|
150
|
+
autocorrect_symbol(corrector, node)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def remove_pair(corrector, node)
|
155
|
+
if !node.parent.braces? || node.left_siblings.any?
|
156
|
+
remove_pair_following(corrector, node)
|
157
|
+
elsif node.right_siblings.any?
|
158
|
+
remove_pair_preceding(corrector, node)
|
159
|
+
else
|
160
|
+
corrector.remove(node)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def remove_pair_following(corrector, node)
|
165
|
+
corrector.remove(
|
166
|
+
range_with_surrounding_comma(
|
167
|
+
range_with_surrounding_space(
|
168
|
+
node.source_range,
|
169
|
+
side: :left
|
170
|
+
),
|
171
|
+
:left
|
172
|
+
)
|
173
|
+
)
|
174
|
+
end
|
175
|
+
|
176
|
+
def remove_pair_preceding(corrector, node)
|
177
|
+
corrector.remove(
|
178
|
+
range_with_surrounding_space(
|
179
|
+
range_with_surrounding_comma(
|
180
|
+
node.source_range,
|
181
|
+
:right
|
182
|
+
),
|
183
|
+
side: :right
|
184
|
+
)
|
185
|
+
)
|
186
|
+
end
|
187
|
+
|
188
|
+
def remove_symbol(corrector, node)
|
189
|
+
corrector.remove(
|
190
|
+
range_with_surrounding_comma(
|
191
|
+
range_with_surrounding_space(
|
192
|
+
node.source_range,
|
193
|
+
side: :left
|
194
|
+
),
|
195
|
+
:left
|
196
|
+
)
|
197
|
+
)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -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
|
@@ -13,7 +13,7 @@ module RuboCop
|
|
13
13
|
def_node_matcher :rspec_metadata, <<~PATTERN
|
14
14
|
(block
|
15
15
|
(send
|
16
|
-
#rspec? {#Examples.all #ExampleGroups.all #SharedGroups.all #Hooks.all} _
|
16
|
+
#rspec? {#Examples.all #ExampleGroups.all #SharedGroups.all #Hooks.all} _ $...)
|
17
17
|
...)
|
18
18
|
PATTERN
|
19
19
|
|
@@ -24,25 +24,39 @@ module RuboCop
|
|
24
24
|
|
25
25
|
# @!method metadata_in_block(node)
|
26
26
|
def_node_search :metadata_in_block, <<~PATTERN
|
27
|
-
(send (lvar %) #Hooks.all _
|
27
|
+
(send (lvar %) #Hooks.all _ $...)
|
28
28
|
PATTERN
|
29
29
|
|
30
30
|
def on_block(node)
|
31
31
|
rspec_configure(node) do |block_var|
|
32
|
-
metadata_in_block(node, block_var) do |
|
33
|
-
|
32
|
+
metadata_in_block(node, block_var) do |metadata_arguments|
|
33
|
+
on_metadata_arguments(metadata_arguments)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
rspec_metadata(node) do |
|
38
|
-
|
37
|
+
rspec_metadata(node) do |metadata_arguments|
|
38
|
+
on_metadata_arguments(metadata_arguments)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
alias on_numblock on_block
|
42
42
|
|
43
|
-
def on_metadata(_symbols,
|
43
|
+
def on_metadata(_symbols, _hash)
|
44
44
|
raise ::NotImplementedError
|
45
45
|
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
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
|
57
|
+
end
|
58
|
+
on_metadata(symbols, hash)
|
59
|
+
end
|
46
60
|
end
|
47
61
|
end
|
48
62
|
end
|
@@ -8,7 +8,7 @@ module RuboCop
|
|
8
8
|
extend RuboCop::NodePattern::Macros
|
9
9
|
|
10
10
|
# @!method skipped_in_metadata?(node)
|
11
|
-
def_node_matcher :skipped_in_metadata?,
|
11
|
+
def_node_matcher :skipped_in_metadata?, <<~PATTERN
|
12
12
|
{
|
13
13
|
(send _ _ <(sym {:skip :pending}) ...>)
|
14
14
|
(send _ _ ... (hash <(pair (sym {:skip :pending}) { true str dstr }) ...>))
|
@@ -30,7 +30,7 @@ module RuboCop
|
|
30
30
|
#
|
31
31
|
# @param node [RuboCop::AST::Node]
|
32
32
|
# @return [Array<RuboCop::AST::Node>] matching nodes
|
33
|
-
def_node_matcher :skip_or_pending_inside_block?,
|
33
|
+
def_node_matcher :skip_or_pending_inside_block?, <<~PATTERN
|
34
34
|
(block <(send nil? {:skip :pending} ...) ...>)
|
35
35
|
PATTERN
|
36
36
|
end
|
@@ -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)
|
@@ -31,7 +31,7 @@ module RuboCop
|
|
31
31
|
# end
|
32
32
|
#
|
33
33
|
# @example `aggregate_failures: true` (default)
|
34
|
-
#
|
34
|
+
# # good - the cop ignores when RSpec aggregates failures
|
35
35
|
# describe UserCreator do
|
36
36
|
# it 'builds a user', :aggregate_failures do
|
37
37
|
# expect(user.name).to eq("John")
|
@@ -40,7 +40,7 @@ module RuboCop
|
|
40
40
|
# end
|
41
41
|
#
|
42
42
|
# @example `aggregate_failures: false`
|
43
|
-
#
|
43
|
+
# # Detected as an offense
|
44
44
|
# describe UserCreator do
|
45
45
|
# it 'builds a user', aggregate_failures: false do
|
46
46
|
# expect(user.name).to eq("John")
|
@@ -48,12 +48,17 @@ module RuboCop
|
|
48
48
|
# end
|
49
49
|
# end
|
50
50
|
#
|
51
|
-
# @example
|
52
|
-
# #
|
53
|
-
#
|
54
|
-
#
|
51
|
+
# @example `Max: 1` (default)
|
52
|
+
# # bad
|
53
|
+
# describe UserCreator do
|
54
|
+
# it 'builds a user' do
|
55
|
+
# expect(user.name).to eq("John")
|
56
|
+
# expect(user.age).to eq(22)
|
57
|
+
# end
|
58
|
+
# end
|
55
59
|
#
|
56
|
-
#
|
60
|
+
# @example `Max: 2`
|
61
|
+
# # good
|
57
62
|
# describe UserCreator do
|
58
63
|
# it 'builds a user' do
|
59
64
|
# expect(user.name).to eq("John")
|
@@ -67,10 +72,10 @@ module RuboCop
|
|
67
72
|
MSG = 'Example has too many expectations [%<total>d/%<max>d].'
|
68
73
|
|
69
74
|
ANYTHING = ->(_node) { true }
|
70
|
-
|
75
|
+
TRUE_NODE = lambda(&:true_type?)
|
71
76
|
|
72
77
|
# @!method aggregate_failures?(node)
|
73
|
-
def_node_matcher :aggregate_failures?,
|
78
|
+
def_node_matcher :aggregate_failures?, <<~PATTERN
|
74
79
|
(block {
|
75
80
|
(send _ _ <(sym :aggregate_failures) ...>)
|
76
81
|
(send _ _ ... (hash <(pair (sym :aggregate_failures) %1) ...>))
|
@@ -81,7 +86,7 @@ module RuboCop
|
|
81
86
|
def_node_matcher :expect?, '(send nil? #Expectations.all ...)'
|
82
87
|
|
83
88
|
# @!method aggregate_failures_block?(node)
|
84
|
-
def_node_matcher :aggregate_failures_block?,
|
89
|
+
def_node_matcher :aggregate_failures_block?, <<~PATTERN
|
85
90
|
(block (send nil? :aggregate_failures ...) ...)
|
86
91
|
PATTERN
|
87
92
|
|
@@ -105,7 +110,7 @@ module RuboCop
|
|
105
110
|
node_with_aggregate_failures = find_aggregate_failures(example_node)
|
106
111
|
return false unless node_with_aggregate_failures
|
107
112
|
|
108
|
-
aggregate_failures?(node_with_aggregate_failures,
|
113
|
+
aggregate_failures?(node_with_aggregate_failures, TRUE_NODE)
|
109
114
|
end
|
110
115
|
|
111
116
|
def find_aggregate_failures(example_node)
|
@@ -108,10 +108,8 @@ module RuboCop
|
|
108
108
|
attr_reader :example_group_memoized_helpers
|
109
109
|
|
110
110
|
def all_helpers(node)
|
111
|
-
|
112
|
-
|
113
|
-
*node.each_ancestor(:block).flat_map(&method(:helpers))
|
114
|
-
]
|
111
|
+
helpers(node) +
|
112
|
+
node.each_ancestor(:block).flat_map { |ancestor| helpers(ancestor) }
|
115
113
|
end
|
116
114
|
|
117
115
|
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)
|
@@ -145,7 +148,7 @@ module RuboCop
|
|
145
148
|
end
|
146
149
|
|
147
150
|
def find_subject(block_node)
|
148
|
-
block_node.body
|
151
|
+
block_node.body&.child_nodes&.find { |send_node| subject?(send_node) }
|
149
152
|
end
|
150
153
|
end
|
151
154
|
end
|
@@ -41,10 +41,15 @@ module RuboCop
|
|
41
41
|
def_node_matcher :skippable?, <<~PATTERN
|
42
42
|
{
|
43
43
|
(send #rspec? #ExampleGroups.regular ...)
|
44
|
-
|
44
|
+
#skippable_example?
|
45
45
|
}
|
46
46
|
PATTERN
|
47
47
|
|
48
|
+
# @!method skippable_example?(node)
|
49
|
+
def_node_matcher :skippable_example?, <<~PATTERN
|
50
|
+
(send nil? #Examples.regular ...)
|
51
|
+
PATTERN
|
52
|
+
|
48
53
|
# @!method pending_block?(node)
|
49
54
|
def_node_matcher :pending_block?, <<~PATTERN
|
50
55
|
{
|
@@ -62,7 +67,12 @@ module RuboCop
|
|
62
67
|
private
|
63
68
|
|
64
69
|
def skipped?(node)
|
65
|
-
skippable?(node) && skipped_in_metadata?(node)
|
70
|
+
(skippable?(node) && skipped_in_metadata?(node)) ||
|
71
|
+
skipped_regular_example_without_body?(node)
|
72
|
+
end
|
73
|
+
|
74
|
+
def skipped_regular_example_without_body?(node)
|
75
|
+
skippable_example?(node) && !node.block_node
|
66
76
|
end
|
67
77
|
end
|
68
78
|
end
|
@@ -103,7 +103,7 @@ module RuboCop
|
|
103
103
|
on_pending_by_metadata(node)
|
104
104
|
return unless (parent = parent_node(node))
|
105
105
|
|
106
|
-
if
|
106
|
+
if spec_group?(parent) || block_node_example_group?(node)
|
107
107
|
on_skipped_by_example_method(node)
|
108
108
|
on_skipped_by_example_group_method(node)
|
109
109
|
elsif example?(parent)
|
@@ -26,7 +26,7 @@ module RuboCop
|
|
26
26
|
end
|
27
27
|
|
28
28
|
# @!method predicate_in_actual?(node)
|
29
|
-
def_node_matcher :predicate_in_actual?,
|
29
|
+
def_node_matcher :predicate_in_actual?, <<~PATTERN
|
30
30
|
(send
|
31
31
|
(send nil? :expect {
|
32
32
|
(block $(send !nil? #predicate? ...) ...)
|
@@ -36,12 +36,12 @@ module RuboCop
|
|
36
36
|
PATTERN
|
37
37
|
|
38
38
|
# @!method be_bool?(node)
|
39
|
-
def_node_matcher :be_bool?,
|
39
|
+
def_node_matcher :be_bool?, <<~PATTERN
|
40
40
|
(send nil? {:be :eq :eql :equal} {true false})
|
41
41
|
PATTERN
|
42
42
|
|
43
43
|
# @!method be_boolthy?(node)
|
44
|
-
def_node_matcher :be_boolthy?,
|
44
|
+
def_node_matcher :be_boolthy?, <<~PATTERN
|
45
45
|
(send nil? {:be_truthy :be_falsey :be_falsy :a_truthy_value :a_falsey_value :a_falsy_value})
|
46
46
|
PATTERN
|
47
47
|
|
@@ -74,7 +74,7 @@ module RuboCop
|
|
74
74
|
name[0..-2]
|
75
75
|
when 'exist?', 'exists?'
|
76
76
|
'exist'
|
77
|
-
when
|
77
|
+
when /\Ahas_/
|
78
78
|
name.sub('has_', 'have_')[0..-2]
|
79
79
|
else
|
80
80
|
"be_#{name[0..-2]}"
|
@@ -174,12 +174,12 @@ module RuboCop
|
|
174
174
|
|
175
175
|
def heredoc_argument?(matcher)
|
176
176
|
matcher.arguments.select do |arg|
|
177
|
-
|
177
|
+
arg.str_type? || arg.dstr_type? || arg.xstr_type?
|
178
178
|
end.any?(&:heredoc?)
|
179
179
|
end
|
180
180
|
|
181
181
|
# @!method predicate_matcher?(node)
|
182
|
-
def_node_matcher :predicate_matcher?,
|
182
|
+
def_node_matcher :predicate_matcher?, <<~PATTERN
|
183
183
|
(send
|
184
184
|
(send nil? :expect $!nil?)
|
185
185
|
#Runners.all
|
@@ -188,7 +188,7 @@ module RuboCop
|
|
188
188
|
PATTERN
|
189
189
|
|
190
190
|
# @!method predicate_matcher_block?(node)
|
191
|
-
def_node_matcher :predicate_matcher_block?,
|
191
|
+
def_node_matcher :predicate_matcher_block?, <<~PATTERN
|
192
192
|
(block
|
193
193
|
(send
|
194
194
|
(send nil? :expect $!nil?)
|
@@ -202,7 +202,7 @@ module RuboCop
|
|
202
202
|
|
203
203
|
return false if allowed_explicit_matchers.include?(name)
|
204
204
|
|
205
|
-
name.start_with?('be_', 'have_') && !name.end_with?('?') ||
|
205
|
+
(name.start_with?('be_', 'have_') && !name.end_with?('?')) ||
|
206
206
|
%w[include respond_to].include?(name)
|
207
207
|
end
|
208
208
|
|
@@ -240,10 +240,10 @@ module RuboCop
|
|
240
240
|
'include?'
|
241
241
|
when 'respond_to'
|
242
242
|
'respond_to?'
|
243
|
-
when
|
243
|
+
when /\Ahave_(.+)/
|
244
244
|
"has_#{Regexp.last_match(1)}?"
|
245
245
|
else
|
246
|
-
"#{matcher[
|
246
|
+
"#{matcher[/\Abe_(.+)/, 1]}?"
|
247
247
|
end
|
248
248
|
end
|
249
249
|
# rubocop:enable Metrics/MethodLength
|
@@ -30,7 +30,7 @@ module RuboCop
|
|
30
30
|
RESTRICT_ON_SEND = %i[times].freeze
|
31
31
|
|
32
32
|
# @!method receive_counts(node)
|
33
|
-
def_node_matcher :receive_counts,
|
33
|
+
def_node_matcher :receive_counts, <<~PATTERN
|
34
34
|
(send $(send _ {:exactly :at_least :at_most} (int {1 2})) :times)
|
35
35
|
PATTERN
|
36
36
|
|