rubocop-rspec 1.43.2 → 2.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 +39 -4
- data/README.md +5 -1
- data/config/default.yml +183 -67
- data/lib/rubocop-rspec.rb +7 -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/around_block.rb +2 -2
- data/lib/rubocop/cop/rspec/base.rb +7 -54
- data/lib/rubocop/cop/rspec/be.rb +2 -2
- data/lib/rubocop/cop/rspec/before_after_all.rb +3 -3
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +2 -2
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +3 -2
- data/lib/rubocop/cop/rspec/describe_class.rb +34 -15
- data/lib/rubocop/cop/rspec/describe_method.rb +2 -2
- 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 +33 -38
- 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_in_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_output.rb +1 -1
- data/lib/rubocop/cop/rspec/file_path.rb +1 -1
- data/lib/rubocop/cop/rspec/focus.rb +13 -7
- 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 -2
- data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
- 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 +1 -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_spies.rb +3 -3
- 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/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/repeated_include_example.rb +104 -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 +1 -1
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +172 -0
- data/lib/rubocop/cop/rspec/subject_stub.rb +20 -10
- 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_cops.rb +2 -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 +1 -1
- data/lib/rubocop/rspec/example_group.rb +15 -5
- data/lib/rubocop/rspec/hook.rb +2 -6
- data/lib/rubocop/rspec/inject.rb +4 -2
- data/lib/rubocop/rspec/language.rb +144 -105
- 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 +25 -13
- 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
|
@@ -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)
|
@@ -22,19 +22,25 @@ module RuboCop
|
|
22
22
|
class Focus < Base
|
23
23
|
MSG = 'Focused spec found.'
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
def_node_matcher :focusable_selector?, <<-PATTERN
|
26
|
+
{
|
27
|
+
#ExampleGroups.regular
|
28
|
+
#ExampleGroups.skipped
|
29
|
+
#Examples.regular
|
30
|
+
#Examples.skipped
|
31
|
+
#Examples.pending
|
32
|
+
}
|
33
|
+
PATTERN
|
31
34
|
|
32
35
|
def_node_matcher :metadata, <<-PATTERN
|
33
36
|
{(send #rspec? #focusable_selector? <$(sym :focus) ...>)
|
34
37
|
(send #rspec? #focusable_selector? ... (hash <$(pair (sym :focus) true) ...>))}
|
35
38
|
PATTERN
|
36
39
|
|
37
|
-
def_node_matcher :focused_block?,
|
40
|
+
def_node_matcher :focused_block?,
|
41
|
+
send_pattern(<<~PATTERN)
|
42
|
+
{#ExampleGroups.focused #Examples.focused}
|
43
|
+
PATTERN
|
38
44
|
|
39
45
|
def on_send(node)
|
40
46
|
focus_metadata(node) do |focus|
|
@@ -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
|
|
@@ -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,7 +22,7 @@ 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
27
|
|
28
28
|
def_node_matcher :example_inclusion_offense, '(send _ % ...)'
|
@@ -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
|
{
|
@@ -29,14 +29,14 @@ module RuboCop
|
|
29
29
|
|
30
30
|
MSG_RECEIVE = 'Prefer `receive` for setting message expectations.'
|
31
31
|
|
32
|
-
MSG_HAVE_RECEIVED = 'Prefer `have_received` for setting message '\
|
33
|
-
'expectations. Setup `%<source>s` as a spy using '\
|
32
|
+
MSG_HAVE_RECEIVED = 'Prefer `have_received` for setting message ' \
|
33
|
+
'expectations. Setup `%<source>s` as a spy using ' \
|
34
34
|
'`allow` or `instance_spy`.'
|
35
35
|
|
36
36
|
SUPPORTED_STYLES = %w[have_received receive].freeze
|
37
37
|
|
38
38
|
def_node_matcher :message_expectation, %(
|
39
|
-
(send (send nil? :expect $_) #
|
39
|
+
(send (send nil? :expect $_) #Runners.all ...)
|
40
40
|
)
|
41
41
|
|
42
42
|
def_node_search :receive_message, %(
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps determine the offending location if there is not an empty line
|
7
|
+
# following the node. Allows comments to follow directly after.
|
8
|
+
module EmptyLineSeparation
|
9
|
+
include FinalEndLocation
|
10
|
+
include RangeHelp
|
11
|
+
|
12
|
+
def missing_separating_line_offense(node)
|
13
|
+
return if last_child?(node)
|
14
|
+
|
15
|
+
missing_separating_line(node) do |location|
|
16
|
+
msg = yield(node.method_name)
|
17
|
+
add_offense(location, message: msg) do |corrector|
|
18
|
+
corrector.insert_after(location.end, "\n")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def missing_separating_line(node)
|
24
|
+
line = final_end_location(node).line
|
25
|
+
|
26
|
+
line += 1 while comment_line?(processed_source[line])
|
27
|
+
|
28
|
+
return if processed_source[line].blank?
|
29
|
+
|
30
|
+
yield offending_loc(line)
|
31
|
+
end
|
32
|
+
|
33
|
+
def offending_loc(last_line)
|
34
|
+
offending_line = processed_source[last_line - 1]
|
35
|
+
|
36
|
+
content_length = offending_line.lstrip.length
|
37
|
+
start = offending_line.length - content_length
|
38
|
+
|
39
|
+
source_range(processed_source.buffer,
|
40
|
+
last_line, start, content_length)
|
41
|
+
end
|
42
|
+
|
43
|
+
def last_child?(node)
|
44
|
+
return true unless node.parent&.begin_type?
|
45
|
+
|
46
|
+
node.equal?(node.parent.children.last)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps find the true end location of nodes which might contain heredocs.
|
7
|
+
module FinalEndLocation
|
8
|
+
def final_end_location(start_node)
|
9
|
+
heredoc_endings =
|
10
|
+
start_node.each_node(:str, :dstr, :xstr)
|
11
|
+
.select(&:heredoc?)
|
12
|
+
.map { |node| node.loc.heredoc_end }
|
13
|
+
|
14
|
+
[start_node.loc.end, *heredoc_endings].max_by(&:line)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helper methods for top level example group cops
|
7
|
+
module TopLevelGroup
|
8
|
+
extend RuboCop::NodePattern::Macros
|
9
|
+
|
10
|
+
def on_new_investigation
|
11
|
+
super
|
12
|
+
|
13
|
+
top_level_groups.each do |node|
|
14
|
+
on_top_level_example_group(node) if example_group?(node)
|
15
|
+
on_top_level_group(node)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def top_level_groups
|
20
|
+
@top_level_groups ||=
|
21
|
+
top_level_nodes(root_node).select { |n| spec_group?(n) }
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# Dummy methods to be overridden in the consumer
|
27
|
+
def on_top_level_example_group(_node); end
|
28
|
+
|
29
|
+
def on_top_level_group(_node); end
|
30
|
+
|
31
|
+
def top_level_group?(node)
|
32
|
+
top_level_groups.include?(node)
|
33
|
+
end
|
34
|
+
|
35
|
+
def top_level_nodes(node)
|
36
|
+
return [] if node.nil?
|
37
|
+
|
38
|
+
case node.type
|
39
|
+
when :begin
|
40
|
+
node.children
|
41
|
+
when :module, :class
|
42
|
+
top_level_nodes(node.body)
|
43
|
+
else
|
44
|
+
[node]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def root_node
|
49
|
+
processed_source.ast
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps check offenses with variable definitions
|
7
|
+
module Variable
|
8
|
+
extend RuboCop::NodePattern::Macros
|
9
|
+
|
10
|
+
Subjects = RuboCop::RSpec::Language::Subjects
|
11
|
+
Helpers = RuboCop::RSpec::Language::Helpers
|
12
|
+
|
13
|
+
def_node_matcher :variable_definition?, <<~PATTERN
|
14
|
+
(send nil? {#Subjects.all #Helpers.all}
|
15
|
+
$({sym str dsym dstr} ...) ...)
|
16
|
+
PATTERN
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -23,10 +23,9 @@ module RuboCop
|
|
23
23
|
# end
|
24
24
|
# end
|
25
25
|
class MultipleDescribes < Base
|
26
|
-
include
|
26
|
+
include TopLevelGroup
|
27
27
|
|
28
|
-
MSG = 'Do not use multiple top-level example groups - '
|
29
|
-
'try to nest them.'
|
28
|
+
MSG = 'Do not use multiple top-level example groups - try to nest them.'
|
30
29
|
|
31
30
|
def on_top_level_group(node)
|
32
31
|
top_level_example_groups =
|