rubocop-rspec 2.16.0 → 2.24.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +124 -9
- data/README.md +3 -3
- data/config/default.yml +145 -18
- data/config/obsoletion.yml +15 -0
- data/lib/rubocop/cop/rspec/be_empty.rb +44 -0
- data/lib/rubocop/cop/rspec/be_nil.rb +2 -2
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +29 -115
- data/lib/rubocop/cop/rspec/capybara/match_style.rb +38 -0
- data/lib/rubocop/cop/rspec/capybara/negation_matcher.rb +23 -96
- data/lib/rubocop/cop/rspec/capybara/specific_actions.rb +19 -75
- data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +14 -83
- data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +25 -69
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +26 -63
- data/lib/rubocop/cop/rspec/change_by_zero.rb +33 -23
- data/lib/rubocop/cop/rspec/contain_exactly.rb +56 -0
- data/lib/rubocop/cop/rspec/context_method.rb +5 -1
- data/lib/rubocop/cop/rspec/context_wording.rb +13 -6
- data/lib/rubocop/cop/rspec/describe_method.rb +16 -8
- data/lib/rubocop/cop/rspec/described_class.rb +2 -1
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +7 -5
- data/lib/rubocop/cop/rspec/dialect.rb +1 -1
- data/lib/rubocop/cop/rspec/duplicated_metadata.rb +2 -2
- data/lib/rubocop/cop/rspec/empty_example_group.rb +10 -7
- data/lib/rubocop/cop/rspec/empty_hook.rb +2 -2
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_metadata.rb +46 -0
- data/lib/rubocop/cop/rspec/eq.rb +47 -0
- data/lib/rubocop/cop/rspec/example_wording.rb +1 -1
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +14 -5
- data/lib/rubocop/cop/rspec/expect_actual.rb +4 -4
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +25 -118
- data/lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb +40 -107
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +30 -250
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +19 -46
- data/lib/rubocop/cop/rspec/factory_bot/factory_name_style.rb +23 -64
- data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +45 -79
- data/lib/rubocop/cop/rspec/file_path.rb +8 -2
- data/lib/rubocop/cop/rspec/focus.rb +19 -5
- data/lib/rubocop/cop/rspec/hook_argument.rb +12 -9
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +5 -3
- data/lib/rubocop/cop/rspec/indexed_let.rb +112 -0
- data/lib/rubocop/cop/rspec/instance_variable.rb +1 -1
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
- data/lib/rubocop/cop/rspec/let_before_examples.rb +8 -4
- data/lib/rubocop/cop/rspec/let_setup.rb +6 -8
- data/lib/rubocop/cop/rspec/match_array.rb +59 -0
- data/lib/rubocop/cop/rspec/metadata_style.rb +197 -0
- data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +1 -2
- data/lib/rubocop/cop/rspec/mixin/file_help.rb +14 -0
- data/lib/rubocop/cop/rspec/mixin/location_help.rb +37 -0
- data/lib/rubocop/cop/rspec/mixin/metadata.rb +21 -7
- data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +20 -4
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +2 -1
- data/lib/rubocop/cop/rspec/named_subject.rb +7 -5
- data/lib/rubocop/cop/rspec/no_expectation_example.rb +2 -5
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +3 -1
- data/lib/rubocop/cop/rspec/pending.rb +23 -13
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +72 -36
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +49 -40
- data/lib/rubocop/cop/rspec/rails/have_http_status.rb +11 -6
- data/lib/rubocop/cop/rspec/rails/http_status.rb +107 -34
- data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +4 -4
- data/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +60 -0
- data/lib/rubocop/cop/rspec/rails/negation_be_valid.rb +102 -0
- data/lib/rubocop/cop/rspec/rails/travel_around.rb +92 -0
- 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_around.rb +65 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +3 -6
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +3 -6
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +3 -4
- data/lib/rubocop/cop/rspec/scattered_setup.rb +23 -6
- data/lib/rubocop/cop/rspec/shared_context.rb +12 -13
- data/lib/rubocop/cop/rspec/shared_examples.rb +6 -4
- data/lib/rubocop/cop/rspec/skip_block_inside_example.rb +46 -0
- data/lib/rubocop/cop/rspec/sort_metadata.rb +4 -3
- 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 +1 -1
- data/lib/rubocop/cop/rspec/subject_stub.rb +0 -1
- data/lib/rubocop/cop/rspec/variable_definition.rb +5 -2
- data/lib/rubocop/cop/rspec/variable_name.rb +4 -1
- data/lib/rubocop/cop/rspec/verified_double_reference.rb +7 -7
- data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -1
- data/lib/rubocop/cop/rspec/void_expect.rb +2 -1
- data/lib/rubocop/cop/rspec_cops.rb +16 -0
- data/lib/rubocop/rspec/config_formatter.rb +16 -0
- data/lib/rubocop/rspec/example_group.rb +6 -8
- data/lib/rubocop/rspec/language/node_pattern.rb +26 -0
- data/lib/rubocop/rspec/language.rb +25 -16
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop-rspec.rb +4 -5
- metadata +50 -8
- data/lib/rubocop/cop/rspec/mixin/capybara_help.rb +0 -80
- data/lib/rubocop/cop/rspec/mixin/css_selector.rb +0 -146
- data/lib/rubocop/rspec/factory_bot/language.rb +0 -37
- data/lib/rubocop/rspec/factory_bot.rb +0 -64
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks where `match_array` is used.
|
7
|
+
#
|
8
|
+
# This cop checks for the following:
|
9
|
+
# - Prefer `contain_exactly` when matching an array with values.
|
10
|
+
# - Prefer `eq` when using `match_array` with an empty array literal.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # bad
|
14
|
+
# it { is_expected.to match_array([content1, content2]) }
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# it { is_expected.to contain_exactly(content1, content2) }
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# it { is_expected.to match_array([content] + array) }
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# it { is_expected.to match_array(%w(tremble in fear foolish mortals)) }
|
24
|
+
#
|
25
|
+
class MatchArray < Base
|
26
|
+
extend AutoCorrector
|
27
|
+
|
28
|
+
MSG = 'Prefer `contain_exactly` when matching an array literal.'
|
29
|
+
RESTRICT_ON_SEND = %i[match_array].freeze
|
30
|
+
|
31
|
+
# @!method match_array_with_empty_array?(node)
|
32
|
+
def_node_matcher :match_array_with_empty_array?, <<~PATTERN
|
33
|
+
(send nil? :match_array (array))
|
34
|
+
PATTERN
|
35
|
+
|
36
|
+
def on_send(node)
|
37
|
+
return unless node.first_argument&.array_type?
|
38
|
+
return if match_array_with_empty_array?(node)
|
39
|
+
|
40
|
+
check_populated_array(node)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def check_populated_array(node)
|
46
|
+
return if node.first_argument.percent_literal?
|
47
|
+
|
48
|
+
add_offense(node) do |corrector|
|
49
|
+
array_contents = node.arguments.flat_map(&:to_a)
|
50
|
+
corrector.replace(
|
51
|
+
node,
|
52
|
+
"contain_exactly(#{array_contents.map(&:source).join(', ')})"
|
53
|
+
)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,197 @@
|
|
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
|
+
symbols.each do |symbol|
|
49
|
+
on_metadata_symbol(symbol)
|
50
|
+
end
|
51
|
+
|
52
|
+
return unless hash
|
53
|
+
|
54
|
+
hash.pairs.each do |pair|
|
55
|
+
on_metadata_pair(pair)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def autocorrect_pair(corrector, node)
|
62
|
+
remove_pair(corrector, node)
|
63
|
+
insert_symbol(corrector, node)
|
64
|
+
end
|
65
|
+
|
66
|
+
def autocorrect_symbol(corrector, node)
|
67
|
+
return if match_ambiguous_trailing_metadata?(node.parent)
|
68
|
+
|
69
|
+
remove_symbol(corrector, node)
|
70
|
+
insert_pair(corrector, node)
|
71
|
+
end
|
72
|
+
|
73
|
+
def bad_metadata_pair?(node)
|
74
|
+
style == :symbol && match_boolean_metadata_pair?(node)
|
75
|
+
end
|
76
|
+
|
77
|
+
def bad_metadata_symbol?(_node)
|
78
|
+
style == :hash
|
79
|
+
end
|
80
|
+
|
81
|
+
def format_symbol_to_pair_source(node)
|
82
|
+
"#{node.value}: true"
|
83
|
+
end
|
84
|
+
|
85
|
+
def insert_pair(corrector, node)
|
86
|
+
hash_node = extract_metadata_hash(node.parent)
|
87
|
+
if hash_node.nil?
|
88
|
+
insert_pair_as_last_argument(corrector, node)
|
89
|
+
elsif hash_node.pairs.any?
|
90
|
+
insert_pair_to_non_empty_hash_metadata(corrector, node, hash_node)
|
91
|
+
else
|
92
|
+
insert_pair_to_empty_hash_metadata(corrector, node, hash_node)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def insert_pair_as_last_argument(corrector, node)
|
97
|
+
corrector.insert_before(
|
98
|
+
node.parent.location.end || node.parent.source_range.with(
|
99
|
+
begin_pos: node.parent.source_range.end_pos
|
100
|
+
),
|
101
|
+
", #{format_symbol_to_pair_source(node)}"
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
def insert_pair_to_empty_hash_metadata(corrector, node, hash_node)
|
106
|
+
corrector.insert_after(
|
107
|
+
hash_node.location.begin,
|
108
|
+
" #{format_symbol_to_pair_source(node)} "
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
def insert_pair_to_non_empty_hash_metadata(corrector, node, hash_node)
|
113
|
+
corrector.insert_after(
|
114
|
+
hash_node.children.last,
|
115
|
+
", #{format_symbol_to_pair_source(node)}"
|
116
|
+
)
|
117
|
+
end
|
118
|
+
|
119
|
+
def insert_symbol(corrector, node)
|
120
|
+
corrector.insert_after(
|
121
|
+
node.parent.left_sibling,
|
122
|
+
", #{node.key.value.inspect}"
|
123
|
+
)
|
124
|
+
end
|
125
|
+
|
126
|
+
def message_for_style
|
127
|
+
format(
|
128
|
+
'Use %<style>s style for metadata.',
|
129
|
+
style: style
|
130
|
+
)
|
131
|
+
end
|
132
|
+
|
133
|
+
def on_metadata_pair(node)
|
134
|
+
return unless bad_metadata_pair?(node)
|
135
|
+
|
136
|
+
add_offense(node, message: message_for_style) do |corrector|
|
137
|
+
autocorrect_pair(corrector, node)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def on_metadata_symbol(node)
|
142
|
+
return unless bad_metadata_symbol?(node)
|
143
|
+
|
144
|
+
add_offense(node, message: message_for_style) do |corrector|
|
145
|
+
autocorrect_symbol(corrector, node)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def remove_pair(corrector, node)
|
150
|
+
if !node.parent.braces? || node.left_siblings.any?
|
151
|
+
remove_pair_following(corrector, node)
|
152
|
+
elsif node.right_siblings.any?
|
153
|
+
remove_pair_preceding(corrector, node)
|
154
|
+
else
|
155
|
+
corrector.remove(node)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def remove_pair_following(corrector, node)
|
160
|
+
corrector.remove(
|
161
|
+
range_with_surrounding_comma(
|
162
|
+
range_with_surrounding_space(
|
163
|
+
node.source_range,
|
164
|
+
side: :left
|
165
|
+
),
|
166
|
+
:left
|
167
|
+
)
|
168
|
+
)
|
169
|
+
end
|
170
|
+
|
171
|
+
def remove_pair_preceding(corrector, node)
|
172
|
+
corrector.remove(
|
173
|
+
range_with_surrounding_space(
|
174
|
+
range_with_surrounding_comma(
|
175
|
+
node.source_range,
|
176
|
+
:right
|
177
|
+
),
|
178
|
+
side: :right
|
179
|
+
)
|
180
|
+
)
|
181
|
+
end
|
182
|
+
|
183
|
+
def remove_symbol(corrector, node)
|
184
|
+
corrector.remove(
|
185
|
+
range_with_surrounding_comma(
|
186
|
+
range_with_surrounding_space(
|
187
|
+
node.source_range,
|
188
|
+
side: :left
|
189
|
+
),
|
190
|
+
:left
|
191
|
+
)
|
192
|
+
)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -25,8 +25,7 @@ module RuboCop
|
|
25
25
|
|
26
26
|
def missing_separating_line(node)
|
27
27
|
line = final_end_line = final_end_location(node).line
|
28
|
-
|
29
|
-
while comment_line?(processed_source[line])
|
28
|
+
while processed_source.line_with_comment?(line + 1)
|
30
29
|
line += 1
|
31
30
|
comment = processed_source.comment_at_line(line)
|
32
31
|
if DirectiveComment.new(comment).enabled?
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helper methods to location.
|
7
|
+
module LocationHelp
|
8
|
+
module_function
|
9
|
+
|
10
|
+
# @param node [RuboCop::AST::SendNode]
|
11
|
+
# @return [Parser::Source::Range]
|
12
|
+
# @example
|
13
|
+
# foo 1, 2
|
14
|
+
# ^^^^^
|
15
|
+
def arguments_with_whitespace(node)
|
16
|
+
node.loc.selector.end.with(
|
17
|
+
end_pos: node.source_range.end_pos
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param node [RuboCop::AST::SendNode]
|
22
|
+
# @return [Parser::Source::Range]
|
23
|
+
# @example
|
24
|
+
# foo { bar }
|
25
|
+
# ^^^^^^^^
|
26
|
+
def block_with_whitespace(node)
|
27
|
+
return unless (parent = node.parent)
|
28
|
+
return unless parent.block_type?
|
29
|
+
|
30
|
+
node.source_range.end.with(
|
31
|
+
end_pos: parent.source_range.end_pos
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
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_matadata_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_matadata_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_matadata_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
|
@@ -10,13 +10,29 @@ module RuboCop
|
|
10
10
|
# @!method skipped_in_metadata?(node)
|
11
11
|
def_node_matcher :skipped_in_metadata?, <<-PATTERN
|
12
12
|
{
|
13
|
-
(send _ _
|
14
|
-
(send _ _ ... (hash <(pair
|
13
|
+
(send _ _ <(sym {:skip :pending}) ...>)
|
14
|
+
(send _ _ ... (hash <(pair (sym {:skip :pending}) { true str dstr }) ...>))
|
15
15
|
}
|
16
16
|
PATTERN
|
17
17
|
|
18
|
-
# @!method
|
19
|
-
|
18
|
+
# @!method skip_or_pending_inside_block?(node)
|
19
|
+
# Match skip/pending statements inside a block (e.g. `context`)
|
20
|
+
#
|
21
|
+
# @example source that matches
|
22
|
+
# context 'when color is blue' do
|
23
|
+
# skip 'not implemented yet'
|
24
|
+
# pending 'not implemented yet'
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# @example source that does not match
|
28
|
+
# skip 'not implemented yet'
|
29
|
+
# pending 'not implemented yet'
|
30
|
+
#
|
31
|
+
# @param node [RuboCop::AST::Node]
|
32
|
+
# @return [Array<RuboCop::AST::Node>] matching nodes
|
33
|
+
def_node_matcher :skip_or_pending_inside_block?, <<-PATTERN
|
34
|
+
(block <(send nil? {:skip :pending} ...) ...>)
|
35
|
+
PATTERN
|
20
36
|
end
|
21
37
|
end
|
22
38
|
end
|
@@ -78,7 +78,8 @@ module RuboCop
|
|
78
78
|
PATTERN
|
79
79
|
|
80
80
|
# @!method expect?(node)
|
81
|
-
def_node_matcher :expect?,
|
81
|
+
def_node_matcher :expect?, '(send nil? #Expectations.all ...)'
|
82
|
+
|
82
83
|
# @!method aggregate_failures_block?(node)
|
83
84
|
def_node_matcher :aggregate_failures_block?, <<-PATTERN
|
84
85
|
(block (send nil? :aggregate_failures ...) ...)
|
@@ -82,12 +82,14 @@ module RuboCop
|
|
82
82
|
MSG = 'Name your test subject if you need to reference it explicitly.'
|
83
83
|
|
84
84
|
# @!method example_or_hook_block?(node)
|
85
|
-
def_node_matcher :example_or_hook_block?,
|
86
|
-
|
85
|
+
def_node_matcher :example_or_hook_block?, <<~PATTERN
|
86
|
+
(block (send nil? {#Examples.all #Hooks.all} ...) ...)
|
87
|
+
PATTERN
|
87
88
|
|
88
89
|
# @!method shared_example?(node)
|
89
|
-
def_node_matcher :shared_example?,
|
90
|
-
|
90
|
+
def_node_matcher :shared_example?, <<~PATTERN
|
91
|
+
(block (send #rspec? #SharedGroups.examples ...) ...)
|
92
|
+
PATTERN
|
91
93
|
|
92
94
|
# @!method subject_usage(node)
|
93
95
|
def_node_search :subject_usage, '$(send nil? :subject)'
|
@@ -143,7 +145,7 @@ module RuboCop
|
|
143
145
|
end
|
144
146
|
|
145
147
|
def find_subject(block_node)
|
146
|
-
block_node.body
|
148
|
+
block_node.body&.child_nodes&.find { |send_node| subject?(send_node) }
|
147
149
|
end
|
148
150
|
end
|
149
151
|
end
|
@@ -65,10 +65,7 @@ module RuboCop
|
|
65
65
|
# @param [RuboCop::AST::Node] node
|
66
66
|
# @return [Boolean]
|
67
67
|
def_node_matcher :regular_or_focused_example?, <<~PATTERN
|
68
|
-
{
|
69
|
-
#{block_pattern('{#Examples.regular | #Examples.focused}')}
|
70
|
-
#{numblock_pattern('{#Examples.regular | #Examples.focused}')}
|
71
|
-
}
|
68
|
+
({block numblock} (send nil? {#Examples.regular #Examples.focused} ...) ...)
|
72
69
|
PATTERN
|
73
70
|
|
74
71
|
# @!method includes_expectation?(node)
|
@@ -76,7 +73,7 @@ module RuboCop
|
|
76
73
|
# @return [Boolean]
|
77
74
|
def_node_search :includes_expectation?, <<~PATTERN
|
78
75
|
{
|
79
|
-
|
76
|
+
(send nil? #Expectations.all ...)
|
80
77
|
(send nil? `#matches_allowed_pattern? ...)
|
81
78
|
}
|
82
79
|
PATTERN
|
@@ -26,7 +26,9 @@ module RuboCop
|
|
26
26
|
MSG = '`%<name>s` is already defined.'
|
27
27
|
|
28
28
|
# @!method setup?(node)
|
29
|
-
def_node_matcher :setup?,
|
29
|
+
def_node_matcher :setup?, <<~PATTERN
|
30
|
+
(block (send nil? {#Helpers.all #Subjects.all} ...) ...)
|
31
|
+
PATTERN
|
30
32
|
|
31
33
|
# @!method first_argument_name(node)
|
32
34
|
def_node_matcher :first_argument_name, '(send _ _ ({str sym} $_))'
|
@@ -38,20 +38,25 @@ module RuboCop
|
|
38
38
|
MSG = 'Pending spec found.'
|
39
39
|
|
40
40
|
# @!method skippable?(node)
|
41
|
-
def_node_matcher :skippable?,
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
def_node_matcher :skippable?, <<~PATTERN
|
42
|
+
{
|
43
|
+
(send #rspec? #ExampleGroups.regular ...)
|
44
|
+
#skippable_example?
|
45
|
+
}
|
46
|
+
PATTERN
|
47
|
+
|
48
|
+
# @!method skippable_example?(node)
|
49
|
+
def_node_matcher :skippable_example?, <<~PATTERN
|
50
|
+
(send nil? #Examples.regular ...)
|
51
|
+
PATTERN
|
45
52
|
|
46
53
|
# @!method pending_block?(node)
|
47
|
-
def_node_matcher :pending_block?,
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
}
|
54
|
-
PATTERN
|
54
|
+
def_node_matcher :pending_block?, <<~PATTERN
|
55
|
+
{
|
56
|
+
(send #rspec? #ExampleGroups.skipped ...)
|
57
|
+
(send nil? {#Examples.skipped #Examples.pending} ...)
|
58
|
+
}
|
59
|
+
PATTERN
|
55
60
|
|
56
61
|
def on_send(node)
|
57
62
|
return unless pending_block?(node) || skipped?(node)
|
@@ -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
|
@@ -59,63 +59,99 @@ module RuboCop
|
|
59
59
|
class PendingWithoutReason < Base
|
60
60
|
MSG = 'Give the reason for pending or skip.'
|
61
61
|
|
62
|
-
# @!method
|
63
|
-
def_node_matcher :
|
64
|
-
|
62
|
+
# @!method skipped_in_example?(node)
|
63
|
+
def_node_matcher :skipped_in_example?, <<~PATTERN
|
64
|
+
{
|
65
|
+
(send nil? ${#Examples.skipped #Examples.pending})
|
66
|
+
(block (send nil? ${#Examples.skipped}) ...)
|
67
|
+
(numblock (send nil? ${#Examples.skipped}) ...)
|
68
|
+
}
|
65
69
|
PATTERN
|
66
70
|
|
67
|
-
# @!method
|
68
|
-
def_node_matcher :
|
69
|
-
(send
|
71
|
+
# @!method skipped_by_example_method?(node)
|
72
|
+
def_node_matcher :skipped_by_example_method?, <<~PATTERN
|
73
|
+
(send nil? ${#Examples.skipped #Examples.pending})
|
70
74
|
PATTERN
|
71
75
|
|
72
|
-
# @!method
|
73
|
-
def_node_matcher :
|
74
|
-
#Examples.skipped
|
76
|
+
# @!method skipped_by_example_method_with_block?(node)
|
77
|
+
def_node_matcher :skipped_by_example_method_with_block?, <<~PATTERN
|
78
|
+
({block numblock} (send nil? ${#Examples.skipped #Examples.pending} ...) ...)
|
79
|
+
PATTERN
|
80
|
+
|
81
|
+
# @!method metadata_without_reason?(node)
|
82
|
+
def_node_matcher :metadata_without_reason?, <<~PATTERN
|
83
|
+
(send #rspec?
|
84
|
+
{#ExampleGroups.all #Examples.all} ...
|
85
|
+
{
|
86
|
+
<(sym ${:pending :skip}) ...>
|
87
|
+
(hash <(pair (sym ${:pending :skip}) true) ...>)
|
88
|
+
}
|
89
|
+
)
|
75
90
|
PATTERN
|
76
91
|
|
77
92
|
# @!method skipped_by_example_group_method?(node)
|
78
|
-
def_node_matcher
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
# @!method skipped_by_metadata_without_reason?(node)
|
86
|
-
def_node_matcher :skipped_by_metadata_without_reason?, <<~PATTERN
|
87
|
-
(send #rspec? {#ExampleGroups.all #Examples.all} ... {<(sym :skip) ...> (hash <(pair (sym :skip) true) ...>)})
|
93
|
+
def_node_matcher :skipped_by_example_group_method?, <<~PATTERN
|
94
|
+
(send #rspec? ${#ExampleGroups.skipped} ...)
|
95
|
+
PATTERN
|
96
|
+
|
97
|
+
# @!method pending_step_without_reason?(node)
|
98
|
+
def_node_matcher :pending_step_without_reason?, <<~PATTERN
|
99
|
+
(send nil? {:skip :pending})
|
88
100
|
PATTERN
|
89
101
|
|
90
102
|
def on_send(node)
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
103
|
+
on_pending_by_metadata(node)
|
104
|
+
return unless (parent = parent_node(node))
|
105
|
+
|
106
|
+
if example_group?(parent) || block_node_example_group?(node)
|
107
|
+
on_skipped_by_example_method(node)
|
108
|
+
on_skipped_by_example_group_method(node)
|
109
|
+
elsif example?(parent)
|
110
|
+
on_skipped_by_in_example_method(node)
|
95
111
|
end
|
96
112
|
end
|
97
113
|
|
98
114
|
private
|
99
115
|
|
100
|
-
def
|
101
|
-
node.
|
116
|
+
def parent_node(node)
|
117
|
+
node_or_block = node.block_node || node
|
118
|
+
return unless (parent = node_or_block.parent)
|
119
|
+
|
120
|
+
parent.begin_type? && parent.parent ? parent.parent : parent
|
121
|
+
end
|
122
|
+
|
123
|
+
def block_node_example_group?(node)
|
124
|
+
node.block_node &&
|
125
|
+
example_group?(node.block_node) &&
|
126
|
+
explicit_rspec?(node.receiver)
|
102
127
|
end
|
103
128
|
|
104
|
-
def
|
105
|
-
|
106
|
-
|
107
|
-
|
129
|
+
def on_skipped_by_in_example_method(node)
|
130
|
+
skipped_in_example?(node) do |pending|
|
131
|
+
add_offense(node, message: "Give the reason for #{pending}.")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def on_pending_by_metadata(node)
|
136
|
+
metadata_without_reason?(node) do |pending|
|
137
|
+
add_offense(node, message: "Give the reason for #{pending}.")
|
138
|
+
end
|
108
139
|
end
|
109
140
|
|
110
|
-
def
|
111
|
-
|
141
|
+
def on_skipped_by_example_method(node)
|
142
|
+
skipped_by_example_method?(node) do |pending|
|
143
|
+
add_offense(node, message: "Give the reason for #{pending}.")
|
144
|
+
end
|
145
|
+
|
146
|
+
skipped_by_example_method_with_block?(node.parent) do |pending|
|
147
|
+
add_offense(node, message: "Give the reason for #{pending}.")
|
148
|
+
end
|
112
149
|
end
|
113
150
|
|
114
|
-
def
|
115
|
-
skipped_by_example_group_method?(node
|
116
|
-
|
117
|
-
|
118
|
-
skipped_by_skip_step_without_reason?(node)
|
151
|
+
def on_skipped_by_example_group_method(node)
|
152
|
+
skipped_by_example_group_method?(node) do
|
153
|
+
add_offense(node, message: 'Give the reason for skip.')
|
154
|
+
end
|
119
155
|
end
|
120
156
|
end
|
121
157
|
end
|