rubocop-rspec 1.44.1 → 2.2.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 +33 -1
- data/README.md +5 -1
- data/config/default.yml +171 -81
- data/lib/rubocop-rspec.rb +8 -8
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +7 -3
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +7 -3
- data/lib/rubocop/cop/rspec/any_instance.rb +6 -10
- data/lib/rubocop/cop/rspec/around_block.rb +1 -1
- data/lib/rubocop/cop/rspec/base.rb +6 -55
- data/lib/rubocop/cop/rspec/be.rb +2 -2
- data/lib/rubocop/cop/rspec/be_eql.rb +1 -0
- data/lib/rubocop/cop/rspec/before_after_all.rb +5 -3
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +4 -2
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +3 -2
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +2 -0
- data/lib/rubocop/cop/rspec/describe_class.rb +2 -2
- data/lib/rubocop/cop/rspec/describe_method.rb +2 -2
- data/lib/rubocop/cop/rspec/describe_symbol.rb +1 -0
- data/lib/rubocop/cop/rspec/described_class.rb +1 -2
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -2
- data/lib/rubocop/cop/rspec/dialect.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_example_group.rb +6 -45
- data/lib/rubocop/cop/rspec/empty_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +2 -2
- data/lib/rubocop/cop/rspec/expect_actual.rb +2 -1
- data/lib/rubocop/cop/rspec/expect_change.rb +1 -0
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_output.rb +1 -1
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +1 -0
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +1 -0
- data/lib/rubocop/cop/rspec/file_path.rb +24 -17
- data/lib/rubocop/cop/rspec/focus.rb +43 -8
- data/lib/rubocop/cop/rspec/hook_argument.rb +2 -4
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +2 -2
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +1 -0
- data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
- data/lib/rubocop/cop/rspec/implicit_subject.rb +1 -0
- data/lib/rubocop/cop/rspec/instance_spy.rb +1 -1
- data/lib/rubocop/cop/rspec/instance_variable.rb +1 -1
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +2 -1
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/let_before_examples.rb +2 -2
- data/lib/rubocop/cop/rspec/let_setup.rb +7 -4
- data/lib/rubocop/cop/rspec/message_chain.rb +4 -10
- data/lib/rubocop/cop/rspec/message_expectation.rb +1 -0
- data/lib/rubocop/cop/rspec/message_spies.rb +3 -3
- data/lib/rubocop/cop/rspec/mixin/comments_help.rb +38 -0
- data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +51 -0
- data/lib/rubocop/cop/rspec/mixin/final_end_location.rb +19 -0
- data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/variable.rb +20 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +2 -3
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +3 -1
- data/lib/rubocop/cop/rspec/named_subject.rb +8 -12
- data/lib/rubocop/cop/rspec/nested_groups.rb +1 -1
- data/lib/rubocop/cop/rspec/not_to_not.rb +1 -0
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +2 -1
- data/lib/rubocop/cop/rspec/pending.rb +13 -5
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +3 -3
- data/lib/rubocop/cop/rspec/rails/http_status.rb +1 -0
- data/lib/rubocop/cop/rspec/receive_counts.rb +2 -0
- data/lib/rubocop/cop/rspec/receive_never.rb +1 -0
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +3 -2
- data/lib/rubocop/cop/rspec/return_from_stub.rb +1 -0
- data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_context.rb +18 -11
- data/lib/rubocop/cop/rspec/shared_examples.rb +3 -1
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +2 -1
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +1 -1
- data/lib/rubocop/cop/rspec/subject_stub.rb +16 -6
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +1 -0
- data/lib/rubocop/cop/rspec/variable_definition.rb +1 -1
- data/lib/rubocop/cop/rspec/variable_name.rb +1 -1
- data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -0
- data/lib/rubocop/cop/rspec/void_expect.rb +1 -0
- data/lib/rubocop/cop/rspec_cops.rb +0 -1
- data/lib/rubocop/rspec/align_let_brace.rb +1 -1
- data/lib/rubocop/rspec/concept.rb +2 -2
- data/lib/rubocop/rspec/config_formatter.rb +5 -3
- data/lib/rubocop/rspec/corrector/move_node.rb +7 -10
- data/lib/rubocop/rspec/example_group.rb +15 -5
- data/lib/rubocop/rspec/hook.rb +1 -1
- data/lib/rubocop/rspec/inject.rb +4 -2
- data/lib/rubocop/rspec/language.rb +143 -109
- data/lib/rubocop/rspec/language/node_pattern.rb +7 -24
- data/lib/rubocop/rspec/node.rb +1 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- metadata +12 -15
- data/lib/rubocop/cop/rspec/cop.rb +0 -10
- data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +0 -41
- data/lib/rubocop/rspec.rb +0 -12
- data/lib/rubocop/rspec/empty_line_separation.rb +0 -48
- data/lib/rubocop/rspec/final_end_location.rb +0 -17
- data/lib/rubocop/rspec/top_level_describe.rb +0 -52
- data/lib/rubocop/rspec/top_level_group.rb +0 -57
- data/lib/rubocop/rspec/variable.rb +0 -16
@@ -16,7 +16,7 @@ module RuboCop
|
|
16
16
|
# let(:foo) { bar }
|
17
17
|
class EmptyLineAfterSubject < Base
|
18
18
|
extend AutoCorrector
|
19
|
-
include
|
19
|
+
include EmptyLineSeparation
|
20
20
|
|
21
21
|
MSG = 'Add an empty line after `%<subject>s`.'
|
22
22
|
|
@@ -32,7 +32,7 @@ module RuboCop
|
|
32
32
|
|
33
33
|
def in_spec_block?(node)
|
34
34
|
node.each_ancestor(:block).any? do |ancestor|
|
35
|
-
Examples
|
35
|
+
Examples.all(ancestor.method_name)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -48,7 +48,7 @@ module RuboCop
|
|
48
48
|
def_node_matcher :expect_literal, <<~PATTERN
|
49
49
|
(send
|
50
50
|
(send nil? :expect $#literal?)
|
51
|
-
#
|
51
|
+
#Runners.all
|
52
52
|
{
|
53
53
|
(send (send nil? $:be) :== $_)
|
54
54
|
(send nil? $_ $_ ...)
|
@@ -60,6 +60,7 @@ module RuboCop
|
|
60
60
|
expect_literal(node) do |actual, matcher, expected|
|
61
61
|
add_offense(actual.source_range) do |corrector|
|
62
62
|
next unless SUPPORTED_MATCHERS.include?(matcher)
|
63
|
+
next if literal?(expected)
|
63
64
|
|
64
65
|
swap(corrector, actual, expected)
|
65
66
|
end
|
@@ -35,6 +35,7 @@ module RuboCop
|
|
35
35
|
|
36
36
|
MSG_BLOCK = 'Prefer `change(%<obj>s, :%<attr>s)`.'
|
37
37
|
MSG_CALL = 'Prefer `change { %<obj>s.%<attr>s }`.'
|
38
|
+
RESTRICT_ON_SEND = %i[change].freeze
|
38
39
|
|
39
40
|
def_node_matcher :expect_change_with_arguments, <<-PATTERN
|
40
41
|
(send nil? :change ({const send} nil? $_) (sym $_))
|
@@ -23,7 +23,7 @@ module RuboCop
|
|
23
23
|
class ExpectInHook < Base
|
24
24
|
MSG = 'Do not use `%<expect>s` in `%<hook>s` hook'
|
25
25
|
|
26
|
-
def_node_search :expectation, Expectations
|
26
|
+
def_node_search :expectation, send_pattern('#Expectations.all')
|
27
27
|
|
28
28
|
def on_block(node)
|
29
29
|
return unless hook?(node)
|
@@ -15,7 +15,7 @@ module RuboCop
|
|
15
15
|
# # good
|
16
16
|
# expect { my_app.print_report }.to output('Hello World').to_stdout
|
17
17
|
class ExpectOutput < Base
|
18
|
-
MSG = 'Use `expect { ... }.to output(...).to_%<name>s` '\
|
18
|
+
MSG = 'Use `expect { ... }.to output(...).to_%<name>s` ' \
|
19
19
|
'instead of mutating $%<name>s.'
|
20
20
|
|
21
21
|
def on_gvasgn(node)
|
@@ -25,6 +25,7 @@ module RuboCop
|
|
25
25
|
MSG = "Pass '%<class_name>s' string instead of `%<class_name>s` " \
|
26
26
|
'constant.'
|
27
27
|
ALLOWED_CONSTANTS = %w[Hash OpenStruct].freeze
|
28
|
+
RESTRICT_ON_SEND = %i[factory].freeze
|
28
29
|
|
29
30
|
def_node_matcher :class_name, <<~PATTERN
|
30
31
|
(send _ :factory _ (hash <(pair (sym :class) $(const ...)) ...>))
|
@@ -57,7 +57,7 @@ module RuboCop
|
|
57
57
|
# my_class_spec.rb # describe MyClass, '#method'
|
58
58
|
#
|
59
59
|
class FilePath < Base
|
60
|
-
include
|
60
|
+
include TopLevelGroup
|
61
61
|
|
62
62
|
MSG = 'Spec path should end with `%<suffix>s`.'
|
63
63
|
|
@@ -82,30 +82,39 @@ module RuboCop
|
|
82
82
|
private
|
83
83
|
|
84
84
|
def ensure_correct_file_path(send_node, described_class, arguments)
|
85
|
-
|
86
|
-
return if filename_ends_with?(
|
87
|
-
|
88
|
-
|
85
|
+
pattern = pattern_for(described_class, arguments.first)
|
86
|
+
return if filename_ends_with?(pattern)
|
87
|
+
|
88
|
+
# For the suffix shown in the offense message, modify the regular
|
89
|
+
# expression pattern to resemble a glob pattern for clearer error
|
90
|
+
# messages.
|
91
|
+
offense_suffix = pattern.gsub('.*', '*').sub('[^/]', '')
|
92
|
+
.sub('\.', '.')
|
93
|
+
add_offense(send_node, message: format(MSG, suffix: offense_suffix))
|
89
94
|
end
|
90
95
|
|
91
96
|
def routing_spec?(args)
|
92
97
|
args.any?(&method(:routing_metadata?))
|
93
98
|
end
|
94
99
|
|
95
|
-
def
|
96
|
-
return
|
100
|
+
def pattern_for(described_class, method_name)
|
101
|
+
return pattern_for_spec_suffix_only? if spec_suffix_only?
|
97
102
|
|
98
|
-
|
103
|
+
[
|
104
|
+
expected_path(described_class),
|
105
|
+
name_pattern(method_name),
|
106
|
+
'[^/]*_spec\.rb'
|
107
|
+
].join
|
99
108
|
end
|
100
109
|
|
101
|
-
def
|
102
|
-
'
|
110
|
+
def pattern_for_spec_suffix_only?
|
111
|
+
'.*_spec\.rb'
|
103
112
|
end
|
104
113
|
|
105
|
-
def
|
114
|
+
def name_pattern(method_name)
|
106
115
|
return unless method_name&.str_type?
|
107
116
|
|
108
|
-
"
|
117
|
+
".*#{method_name.str_content.gsub(/\W/, '')}" unless ignore_methods?
|
109
118
|
end
|
110
119
|
|
111
120
|
def expected_path(constant)
|
@@ -131,11 +140,9 @@ module RuboCop
|
|
131
140
|
cop_config['IgnoreMethods']
|
132
141
|
end
|
133
142
|
|
134
|
-
def filename_ends_with?(
|
135
|
-
filename =
|
136
|
-
|
137
|
-
.gsub('../', '')
|
138
|
-
File.fnmatch?("*#{glob}", filename)
|
143
|
+
def filename_ends_with?(pattern)
|
144
|
+
filename = File.expand_path(processed_source.buffer.name)
|
145
|
+
filename.match?("#{pattern}$")
|
139
146
|
end
|
140
147
|
|
141
148
|
def relevant_rubocop_rspec_file?(_file)
|
@@ -20,25 +20,40 @@ module RuboCop
|
|
20
20
|
# describe MyClass do
|
21
21
|
# end
|
22
22
|
class Focus < Base
|
23
|
-
|
23
|
+
extend AutoCorrector
|
24
|
+
include RangeHelp
|
24
25
|
|
25
|
-
|
26
|
+
MSG = 'Focused spec found.'
|
26
27
|
|
27
|
-
def_node_matcher :focusable_selector?,
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
def_node_matcher :focusable_selector?, <<-PATTERN
|
29
|
+
{
|
30
|
+
#ExampleGroups.regular
|
31
|
+
#ExampleGroups.skipped
|
32
|
+
#Examples.regular
|
33
|
+
#Examples.skipped
|
34
|
+
#Examples.pending
|
35
|
+
}
|
36
|
+
PATTERN
|
31
37
|
|
32
38
|
def_node_matcher :metadata, <<-PATTERN
|
33
39
|
{(send #rspec? #focusable_selector? <$(sym :focus) ...>)
|
34
40
|
(send #rspec? #focusable_selector? ... (hash <$(pair (sym :focus) true) ...>))}
|
35
41
|
PATTERN
|
36
42
|
|
37
|
-
def_node_matcher :focused_block?,
|
43
|
+
def_node_matcher :focused_block?,
|
44
|
+
send_pattern(<<~PATTERN)
|
45
|
+
{#ExampleGroups.focused #Examples.focused}
|
46
|
+
PATTERN
|
38
47
|
|
39
48
|
def on_send(node)
|
40
49
|
focus_metadata(node) do |focus|
|
41
|
-
add_offense(focus)
|
50
|
+
add_offense(focus) do |corrector|
|
51
|
+
if focus.pair_type? || focus.str_type? || focus.sym_type?
|
52
|
+
corrector.remove(with_surrounding(focus))
|
53
|
+
elsif focus.send_type?
|
54
|
+
correct_send(corrector, focus)
|
55
|
+
end
|
56
|
+
end
|
42
57
|
end
|
43
58
|
end
|
44
59
|
|
@@ -49,6 +64,26 @@ module RuboCop
|
|
49
64
|
|
50
65
|
metadata(node, &block)
|
51
66
|
end
|
67
|
+
|
68
|
+
def with_surrounding(focus)
|
69
|
+
range_with_space = range_with_surrounding_space(
|
70
|
+
range: focus.loc.expression,
|
71
|
+
side: :left
|
72
|
+
)
|
73
|
+
|
74
|
+
range_with_surrounding_comma(range_with_space, :left)
|
75
|
+
end
|
76
|
+
|
77
|
+
def correct_send(corrector, focus)
|
78
|
+
range = focus.loc.selector
|
79
|
+
unfocused = focus.method_name.to_s.sub(/^f/, '')
|
80
|
+
unless Examples.regular(unfocused) || ExampleGroups.regular(unfocused)
|
81
|
+
return
|
82
|
+
end
|
83
|
+
|
84
|
+
corrector.replace(range,
|
85
|
+
range.source.sub(focus.method_name.to_s, unfocused))
|
86
|
+
end
|
52
87
|
end
|
53
88
|
end
|
54
89
|
end
|
@@ -64,13 +64,11 @@ module RuboCop
|
|
64
64
|
IMPLICIT_MSG = 'Omit the default `%<scope>p` argument for RSpec hooks.'
|
65
65
|
EXPLICIT_MSG = 'Use `%<scope>p` for RSpec hooks.'
|
66
66
|
|
67
|
-
def_node_matcher :hook?, Hooks::ALL.node_pattern_union
|
68
|
-
|
69
67
|
def_node_matcher :scoped_hook, <<-PATTERN
|
70
|
-
(block $(send _ #
|
68
|
+
(block $(send _ #Hooks.all (sym ${:each :example})) ...)
|
71
69
|
PATTERN
|
72
70
|
|
73
|
-
def_node_matcher :unscoped_hook, '(block $(send _ #
|
71
|
+
def_node_matcher :unscoped_hook, '(block $(send _ #Hooks.all) ...)'
|
74
72
|
|
75
73
|
def on_block(node)
|
76
74
|
hook(node) do |method_send, scope_name|
|
@@ -30,8 +30,8 @@ module RuboCop
|
|
30
30
|
|
31
31
|
def_node_matcher :example_or_group?, <<-PATTERN
|
32
32
|
{
|
33
|
-
#{(
|
34
|
-
#{Includes
|
33
|
+
#{block_pattern('{#ExampleGroups.all #Examples.all}')}
|
34
|
+
#{send_pattern('#Includes.examples')}
|
35
35
|
}
|
36
36
|
PATTERN
|
37
37
|
|
@@ -31,6 +31,7 @@ module RuboCop
|
|
31
31
|
include ConfigurableEnforcedStyle
|
32
32
|
|
33
33
|
MSG = "Don't use implicit subject."
|
34
|
+
RESTRICT_ON_SEND = %i[is_expected should should_not].freeze
|
34
35
|
|
35
36
|
def_node_matcher :implicit_subject?, <<-PATTERN
|
36
37
|
(send nil? {:should :should_not :is_expected} ...)
|
@@ -21,7 +21,7 @@ module RuboCop
|
|
21
21
|
class InstanceSpy < Base
|
22
22
|
extend AutoCorrector
|
23
23
|
|
24
|
-
MSG = 'Use `instance_spy` when you check your double '\
|
24
|
+
MSG = 'Use `instance_spy` when you check your double ' \
|
25
25
|
'with `have_received`.'
|
26
26
|
|
27
27
|
def_node_search :null_double, <<-PATTERN
|
@@ -22,8 +22,9 @@ module RuboCop
|
|
22
22
|
extend AutoCorrector
|
23
23
|
include ConfigurableEnforcedStyle
|
24
24
|
|
25
|
-
MSG = 'Prefer `%<replacement>s` over `%<original>s` when including '\
|
25
|
+
MSG = 'Prefer `%<replacement>s` over `%<original>s` when including ' \
|
26
26
|
'examples in a nested context.'
|
27
|
+
RESTRICT_ON_SEND = %i[it_behaves_like it_should_behave_like].freeze
|
27
28
|
|
28
29
|
def_node_matcher :example_inclusion_offense, '(send _ % ...)'
|
29
30
|
|
@@ -37,8 +37,8 @@ module RuboCop
|
|
37
37
|
|
38
38
|
def_node_matcher :example_or_group?, <<-PATTERN
|
39
39
|
{
|
40
|
-
#{(
|
41
|
-
#{Includes
|
40
|
+
#{block_pattern('{#ExampleGroups.all #Examples.all}')}
|
41
|
+
#{send_pattern('#Includes.examples')}
|
42
42
|
}
|
43
43
|
PATTERN
|
44
44
|
|
@@ -29,10 +29,13 @@ module RuboCop
|
|
29
29
|
MSG = 'Do not use `let!` to setup objects not referenced in tests.'
|
30
30
|
|
31
31
|
def_node_matcher :example_or_shared_group_or_including?,
|
32
|
-
(
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
block_pattern(<<~PATTERN)
|
33
|
+
{
|
34
|
+
#SharedGroups.all
|
35
|
+
#ExampleGroups.all
|
36
|
+
#Includes.all
|
37
|
+
}
|
38
|
+
PATTERN
|
36
39
|
|
37
40
|
def_node_matcher :let_bang, <<-PATTERN
|
38
41
|
{
|
@@ -15,18 +15,12 @@ module RuboCop
|
|
15
15
|
#
|
16
16
|
class MessageChain < Base
|
17
17
|
MSG = 'Avoid stubbing using `%<method>s`.'
|
18
|
-
|
19
|
-
def_node_matcher :message_chain, <<-PATTERN
|
20
|
-
(send _ {:receive_message_chain :stub_chain} ...)
|
21
|
-
PATTERN
|
18
|
+
RESTRICT_ON_SEND = %i[receive_message_chain stub_chain].freeze
|
22
19
|
|
23
20
|
def on_send(node)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
message: format(MSG, method: node.method_name)
|
28
|
-
)
|
29
|
-
end
|
21
|
+
add_offense(
|
22
|
+
node.loc.selector, message: format(MSG, method: node.method_name)
|
23
|
+
)
|
30
24
|
end
|
31
25
|
end
|
32
26
|
end
|
@@ -30,6 +30,7 @@ module RuboCop
|
|
30
30
|
MSG = 'Prefer `%<style>s` for setting message expectations.'
|
31
31
|
|
32
32
|
SUPPORTED_STYLES = %w[allow expect].freeze
|
33
|
+
RESTRICT_ON_SEND = %i[to].freeze
|
33
34
|
|
34
35
|
def_node_matcher :message_expectation, <<-PATTERN
|
35
36
|
(send $(send nil? {:expect :allow} ...) :to #receive_message?)
|