rubocop-rspec 2.16.0 → 2.24.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 +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
|