rubocop-rspec 1.40.0 → 1.43.2
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 +37 -0
- data/CODE_OF_CONDUCT.md +17 -0
- data/config/default.yml +12 -2
- data/lib/rubocop-rspec.rb +3 -1
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +12 -19
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +12 -19
- data/lib/rubocop/cop/rspec/any_instance.rb +1 -1
- data/lib/rubocop/cop/rspec/around_block.rb +1 -1
- data/lib/rubocop/cop/rspec/base.rb +74 -0
- data/lib/rubocop/cop/rspec/be.rb +2 -2
- data/lib/rubocop/cop/rspec/be_eql.rb +6 -6
- data/lib/rubocop/cop/rspec/before_after_all.rb +1 -1
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +19 -17
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +14 -12
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +1 -1
- data/lib/rubocop/cop/rspec/context_method.rb +7 -9
- data/lib/rubocop/cop/rspec/context_wording.rb +3 -3
- data/lib/rubocop/cop/rspec/cop.rb +2 -66
- data/lib/rubocop/cop/rspec/describe_class.rb +20 -27
- data/lib/rubocop/cop/rspec/describe_method.rb +14 -6
- data/lib/rubocop/cop/rspec/describe_symbol.rb +2 -2
- data/lib/rubocop/cop/rspec/described_class.rb +12 -9
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -1
- data/lib/rubocop/cop/rspec/dialect.rb +5 -12
- data/lib/rubocop/cop/rspec/empty_example_group.rb +91 -7
- data/lib/rubocop/cop/rspec/empty_hook.rb +6 -10
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +5 -7
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +5 -9
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +8 -8
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +5 -9
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +6 -6
- data/lib/rubocop/cop/rspec/example_length.rb +1 -1
- data/lib/rubocop/cop/rspec/example_without_description.rb +1 -1
- data/lib/rubocop/cop/rspec/example_wording.rb +10 -11
- data/lib/rubocop/cop/rspec/expect_actual.rb +8 -11
- data/lib/rubocop/cop/rspec/expect_change.rb +10 -35
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +3 -3
- data/lib/rubocop/cop/rspec/expect_output.rb +2 -2
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +24 -21
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +20 -22
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +7 -8
- data/lib/rubocop/cop/rspec/file_path.rb +25 -17
- data/lib/rubocop/cop/rspec/focus.rb +7 -11
- data/lib/rubocop/cop/rspec/hook_argument.rb +16 -23
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +13 -14
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/implicit_expect.rb +7 -15
- data/lib/rubocop/cop/rspec/implicit_subject.rb +16 -11
- data/lib/rubocop/cop/rspec/instance_spy.rb +18 -12
- data/lib/rubocop/cop/rspec/instance_variable.rb +4 -8
- data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +3 -6
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +5 -6
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/leading_subject.rb +27 -20
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +2 -5
- data/lib/rubocop/cop/rspec/let_before_examples.rb +13 -11
- data/lib/rubocop/cop/rspec/let_setup.rb +21 -6
- data/lib/rubocop/cop/rspec/message_chain.rb +7 -6
- data/lib/rubocop/cop/rspec/message_expectation.rb +2 -2
- data/lib/rubocop/cop/rspec/message_spies.rb +2 -3
- data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_describes.rb +11 -8
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +7 -11
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +148 -0
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +18 -19
- data/lib/rubocop/cop/rspec/named_subject.rb +2 -2
- data/lib/rubocop/cop/rspec/nested_groups.rb +12 -13
- data/lib/rubocop/cop/rspec/not_to_not.rb +5 -6
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/pending.rb +1 -1
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +32 -69
- data/lib/rubocop/cop/rspec/rails/http_status.rb +5 -9
- data/lib/rubocop/cop/rspec/receive_counts.rb +15 -17
- data/lib/rubocop/cop/rspec/receive_never.rb +12 -12
- data/lib/rubocop/cop/rspec/repeated_description.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_example.rb +2 -2
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +1 -1
- data/lib/rubocop/cop/rspec/return_from_stub.rb +12 -22
- data/lib/rubocop/cop/rspec/scattered_let.rb +8 -11
- data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_context.rb +8 -21
- data/lib/rubocop/cop/rspec/shared_examples.rb +6 -9
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +15 -18
- data/lib/rubocop/cop/rspec/subject_stub.rb +5 -11
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +1 -1
- data/lib/rubocop/cop/rspec/variable_definition.rb +6 -6
- data/lib/rubocop/cop/rspec/variable_name.rb +28 -9
- data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -1
- data/lib/rubocop/cop/rspec/void_expect.rb +1 -1
- data/lib/rubocop/cop/rspec/yield.rb +14 -11
- data/lib/rubocop/cop/rspec_cops.rb +1 -0
- data/lib/rubocop/rspec/corrector/move_node.rb +7 -5
- data/lib/rubocop/rspec/description_extractor.rb +1 -1
- data/lib/rubocop/rspec/{blank_line_separation.rb → empty_line_separation.rb} +13 -10
- data/lib/rubocop/rspec/example_group.rb +21 -49
- data/lib/rubocop/rspec/factory_bot.rb +7 -1
- data/lib/rubocop/rspec/language.rb +6 -4
- data/lib/rubocop/rspec/language/node_pattern.rb +10 -1
- data/lib/rubocop/rspec/top_level_describe.rb +2 -2
- data/lib/rubocop/rspec/top_level_group.rb +57 -0
- data/lib/rubocop/rspec/variable.rb +1 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- metadata +29 -11
@@ -40,7 +40,9 @@ module RuboCop
|
|
40
40
|
# # ...
|
41
41
|
# end
|
42
42
|
# end
|
43
|
-
class FeatureMethods <
|
43
|
+
class FeatureMethods < Base
|
44
|
+
extend AutoCorrector
|
45
|
+
|
44
46
|
MSG = 'Use `%<replacement>s` instead of `%<method>s`.'
|
45
47
|
|
46
48
|
# https://git.io/v7Kwr
|
@@ -53,15 +55,18 @@ module RuboCop
|
|
53
55
|
feature: :describe
|
54
56
|
}.freeze
|
55
57
|
|
58
|
+
def_node_matcher :capybara_speak,
|
59
|
+
SelectorSet.new(MAP.keys).node_pattern_union
|
60
|
+
|
56
61
|
def_node_matcher :spec?, <<-PATTERN
|
57
62
|
(block
|
58
|
-
(send #
|
63
|
+
(send #rspec? {:describe :feature} ...)
|
59
64
|
...)
|
60
65
|
PATTERN
|
61
66
|
|
62
67
|
def_node_matcher :feature_method, <<-PATTERN
|
63
68
|
(block
|
64
|
-
$(send #
|
69
|
+
$(send #rspec? $#capybara_speak ...)
|
65
70
|
...)
|
66
71
|
PATTERN
|
67
72
|
|
@@ -71,18 +76,15 @@ module RuboCop
|
|
71
76
|
feature_method(node) do |send_node, match|
|
72
77
|
next if enabled?(match)
|
73
78
|
|
74
|
-
add_offense(
|
75
|
-
send_node,
|
76
|
-
|
77
|
-
message: format(MSG, method: match, replacement: MAP[match])
|
78
|
-
)
|
79
|
+
add_offense(send_node.loc.selector) do |corrector|
|
80
|
+
corrector.replace(send_node.loc.selector, MAP[match].to_s)
|
81
|
+
end
|
79
82
|
end
|
80
83
|
end
|
81
84
|
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
end
|
85
|
+
def message(range)
|
86
|
+
name = range.source.to_sym
|
87
|
+
format(MSG, method: name, replacement: MAP[name])
|
86
88
|
end
|
87
89
|
|
88
90
|
private
|
@@ -26,7 +26,7 @@ module RuboCop
|
|
26
26
|
# expect(page).to have_css('.foo', visible: :all)
|
27
27
|
# expect(page).to have_link('my link', visible: :hidden)
|
28
28
|
#
|
29
|
-
class VisibilityMatcher <
|
29
|
+
class VisibilityMatcher < Base
|
30
30
|
MSG_FALSE = 'Use `:all` or `:hidden` instead of `false`.'
|
31
31
|
MSG_TRUE = 'Use `:visible` instead of `true`.'
|
32
32
|
CAPYBARA_MATCHER_METHODS = %i[
|
@@ -23,22 +23,20 @@ module RuboCop
|
|
23
23
|
# describe '.foo_bar' do
|
24
24
|
# # ...
|
25
25
|
# end
|
26
|
-
class ContextMethod <
|
26
|
+
class ContextMethod < Base
|
27
|
+
extend AutoCorrector
|
28
|
+
|
27
29
|
MSG = 'Use `describe` for testing methods.'
|
28
30
|
|
29
31
|
def_node_matcher :context_method, <<-PATTERN
|
30
|
-
(block (send #
|
32
|
+
(block (send #rspec? :context $(str #method_name?) ...) ...)
|
31
33
|
PATTERN
|
32
34
|
|
33
35
|
def on_block(node)
|
34
36
|
context_method(node) do |context|
|
35
|
-
add_offense(context)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
def autocorrect(node)
|
40
|
-
lambda do |corrector|
|
41
|
-
corrector.replace(node.parent.loc.selector, 'describe')
|
37
|
+
add_offense(context) do |corrector|
|
38
|
+
corrector.replace(node.send_node.loc.selector, 'describe')
|
39
|
+
end
|
42
40
|
end
|
43
41
|
end
|
44
42
|
|
@@ -34,11 +34,11 @@ module RuboCop
|
|
34
34
|
# context 'when the display name is not present' do
|
35
35
|
# # ...
|
36
36
|
# end
|
37
|
-
class ContextWording <
|
37
|
+
class ContextWording < Base
|
38
38
|
MSG = 'Start context description with %<prefixes>s.'
|
39
39
|
|
40
40
|
def_node_matcher :context_wording, <<-PATTERN
|
41
|
-
(block (send #
|
41
|
+
(block (send #rspec? { :context :shared_context } $(str #bad_prefix?) ...) ...)
|
42
42
|
PATTERN
|
43
43
|
|
44
44
|
def on_block(node)
|
@@ -51,7 +51,7 @@ module RuboCop
|
|
51
51
|
private
|
52
52
|
|
53
53
|
def bad_prefix?(description)
|
54
|
-
!prefixes.include?(description.split.first)
|
54
|
+
!prefixes.include?(description.split(/\b/).first)
|
55
55
|
end
|
56
56
|
|
57
57
|
def joined_prefixes
|
@@ -3,72 +3,8 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
|
-
# @
|
7
|
-
|
8
|
-
# The criteria for whether rubocop-rspec analyzes a certain ruby file
|
9
|
-
# is configured via `AllCops/RSpec`. For example, if you want to
|
10
|
-
# customize your project to scan all files within a `test/` directory
|
11
|
-
# then you could add this to your configuration:
|
12
|
-
#
|
13
|
-
# @example configuring analyzed paths
|
14
|
-
# # .rubocop.yml
|
15
|
-
# # AllCops:
|
16
|
-
# # RSpec:
|
17
|
-
# # Patterns:
|
18
|
-
# # - '_test.rb$'
|
19
|
-
# # - '(?:^|/)test/'
|
20
|
-
class Cop < ::RuboCop::Cop::Cop
|
21
|
-
include RuboCop::RSpec::Language
|
22
|
-
include RuboCop::RSpec::Language::NodePattern
|
23
|
-
|
24
|
-
DEFAULT_CONFIGURATION =
|
25
|
-
RuboCop::RSpec::CONFIG.fetch('AllCops').fetch('RSpec')
|
26
|
-
|
27
|
-
DEFAULT_PATTERN_RE = Regexp.union(
|
28
|
-
DEFAULT_CONFIGURATION.fetch('Patterns')
|
29
|
-
.map(&Regexp.public_method(:new))
|
30
|
-
)
|
31
|
-
|
32
|
-
# Invoke the original inherited hook so our cops are recognized
|
33
|
-
def self.inherited(subclass)
|
34
|
-
RuboCop::Cop::Cop.inherited(subclass)
|
35
|
-
end
|
36
|
-
|
37
|
-
def relevant_file?(file)
|
38
|
-
relevant_rubocop_rspec_file?(file) && super
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def relevant_rubocop_rspec_file?(file)
|
44
|
-
rspec_pattern =~ file
|
45
|
-
end
|
46
|
-
|
47
|
-
def rspec_pattern
|
48
|
-
if rspec_pattern_config?
|
49
|
-
Regexp.union(rspec_pattern_config.map(&Regexp.public_method(:new)))
|
50
|
-
else
|
51
|
-
DEFAULT_PATTERN_RE
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def all_cops_config
|
56
|
-
config
|
57
|
-
.for_all_cops
|
58
|
-
end
|
59
|
-
|
60
|
-
def rspec_pattern_config?
|
61
|
-
return unless all_cops_config.key?('RSpec')
|
62
|
-
|
63
|
-
all_cops_config.fetch('RSpec').key?('Patterns')
|
64
|
-
end
|
65
|
-
|
66
|
-
def rspec_pattern_config
|
67
|
-
all_cops_config
|
68
|
-
.fetch('RSpec', DEFAULT_CONFIGURATION)
|
69
|
-
.fetch('Patterns')
|
70
|
-
end
|
71
|
-
end
|
6
|
+
# @deprecated Use ::RuboCop::Cop::RSpec::Base instead
|
7
|
+
Cop = Base
|
72
8
|
end
|
73
9
|
end
|
74
10
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
|
-
# Check that the first argument to the top
|
6
|
+
# Check that the first argument to the top-level describe is a constant.
|
7
7
|
#
|
8
8
|
# @example
|
9
9
|
# # bad
|
@@ -21,48 +21,41 @@ module RuboCop
|
|
21
21
|
#
|
22
22
|
# describe "A feature example", type: :feature do
|
23
23
|
# end
|
24
|
-
class DescribeClass <
|
25
|
-
include RuboCop::RSpec::
|
24
|
+
class DescribeClass < Base
|
25
|
+
include RuboCop::RSpec::TopLevelGroup
|
26
26
|
|
27
27
|
MSG = 'The first argument to describe should be '\
|
28
28
|
'the class or module being tested.'
|
29
29
|
|
30
|
-
def_node_matcher :valid_describe?, <<-PATTERN
|
31
|
-
{
|
32
|
-
(send #{RSPEC} :describe const ...)
|
33
|
-
(send #{RSPEC} :describe)
|
34
|
-
}
|
35
|
-
PATTERN
|
36
|
-
|
37
|
-
def_node_matcher :describe_with_rails_metadata?, <<-PATTERN
|
38
|
-
(send #{RSPEC} :describe !const ...
|
39
|
-
(hash <#rails_metadata? ...>)
|
40
|
-
)
|
41
|
-
PATTERN
|
42
|
-
|
43
30
|
def_node_matcher :rails_metadata?, <<-PATTERN
|
44
31
|
(pair
|
45
32
|
(sym :type)
|
46
|
-
(sym {:
|
33
|
+
(sym { :channel :controller :helper :job :mailer :model :request
|
34
|
+
:routing :view :feature :system :mailbox })
|
47
35
|
)
|
48
36
|
PATTERN
|
49
37
|
|
50
|
-
def_node_matcher :
|
38
|
+
def_node_matcher :example_group_with_rails_metadata?, <<~PATTERN
|
39
|
+
(send #rspec? :describe ... (hash <#rails_metadata? ...>))
|
40
|
+
PATTERN
|
41
|
+
|
42
|
+
def_node_matcher :not_a_const_described, <<~PATTERN
|
43
|
+
(send #rspec? :describe $[!const !#string_constant?] ...)
|
44
|
+
PATTERN
|
51
45
|
|
52
|
-
def
|
53
|
-
return if
|
54
|
-
return if valid_describe?(node)
|
55
|
-
return if describe_with_rails_metadata?(node)
|
56
|
-
return if string_constant_describe?(described_value)
|
46
|
+
def on_top_level_group(top_level_node)
|
47
|
+
return if example_group_with_rails_metadata?(top_level_node.send_node)
|
57
48
|
|
58
|
-
|
49
|
+
not_a_const_described(top_level_node.send_node) do |described|
|
50
|
+
add_offense(described)
|
51
|
+
end
|
59
52
|
end
|
60
53
|
|
61
54
|
private
|
62
55
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
56
|
+
def string_constant?(described)
|
57
|
+
described.str_type? &&
|
58
|
+
described.value.match?(/^(?:(?:::)?[A-Z]\w*)+$/)
|
66
59
|
end
|
67
60
|
end
|
68
61
|
end
|
@@ -16,17 +16,25 @@ module RuboCop
|
|
16
16
|
#
|
17
17
|
# describe MyClass, '.my_class_method' do
|
18
18
|
# end
|
19
|
-
class DescribeMethod <
|
20
|
-
include RuboCop::RSpec::
|
19
|
+
class DescribeMethod < Base
|
20
|
+
include RuboCop::RSpec::TopLevelGroup
|
21
21
|
|
22
22
|
MSG = 'The second argument to describe should be the method '\
|
23
23
|
"being tested. '#instance' or '.class'."
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
def_node_matcher :second_argument, <<~PATTERN
|
26
|
+
(block
|
27
|
+
(send #rspec? :describe _first_argument $(str _) ...) ...
|
28
|
+
)
|
29
|
+
PATTERN
|
28
30
|
|
29
|
-
|
31
|
+
def on_top_level_group(node)
|
32
|
+
second_argument = second_argument(node)
|
33
|
+
|
34
|
+
return unless second_argument
|
35
|
+
return if second_argument.str_content.start_with?('#', '.')
|
36
|
+
|
37
|
+
add_offense(second_argument)
|
30
38
|
end
|
31
39
|
end
|
32
40
|
end
|
@@ -17,11 +17,11 @@ module RuboCop
|
|
17
17
|
# end
|
18
18
|
#
|
19
19
|
# @see https://github.com/rspec/rspec-core/issues/1610
|
20
|
-
class DescribeSymbol <
|
20
|
+
class DescribeSymbol < Base
|
21
21
|
MSG = 'Avoid describing symbols.'
|
22
22
|
|
23
23
|
def_node_matcher :describe_symbol?, <<-PATTERN
|
24
|
-
(send #
|
24
|
+
(send #rspec? :describe $sym ...)
|
25
25
|
PATTERN
|
26
26
|
|
27
27
|
def on_send(node)
|
@@ -54,7 +54,8 @@ module RuboCop
|
|
54
54
|
# end
|
55
55
|
# end
|
56
56
|
#
|
57
|
-
class DescribedClass <
|
57
|
+
class DescribedClass < Base
|
58
|
+
extend AutoCorrector
|
58
59
|
include ConfigurableEnforcedStyle
|
59
60
|
|
60
61
|
DESCRIBED_CLASS = 'described_class'
|
@@ -85,22 +86,24 @@ module RuboCop
|
|
85
86
|
return unless body
|
86
87
|
|
87
88
|
find_usage(body) do |match|
|
88
|
-
|
89
|
+
msg = message(match.const_name)
|
90
|
+
add_offense(match, message: msg) do |corrector|
|
91
|
+
autocorrect(corrector, match)
|
92
|
+
end
|
89
93
|
end
|
90
94
|
end
|
91
95
|
|
92
|
-
|
96
|
+
private
|
97
|
+
|
98
|
+
def autocorrect(corrector, match)
|
93
99
|
replacement = if style == :described_class
|
94
100
|
DESCRIBED_CLASS
|
95
101
|
else
|
96
102
|
@described_class.const_name
|
97
103
|
end
|
98
|
-
lambda do |corrector|
|
99
|
-
corrector.replace(node.loc.expression, replacement)
|
100
|
-
end
|
101
|
-
end
|
102
104
|
|
103
|
-
|
105
|
+
corrector.replace(match, replacement)
|
106
|
+
end
|
104
107
|
|
105
108
|
def find_usage(node, &block)
|
106
109
|
yield(node) if offensive?(node)
|
@@ -139,7 +142,7 @@ module RuboCop
|
|
139
142
|
if style == :described_class
|
140
143
|
offensive_described_class?(node)
|
141
144
|
else
|
142
|
-
node.send_type? && node.
|
145
|
+
node.send_type? && node.method?(:described_class)
|
143
146
|
end
|
144
147
|
end
|
145
148
|
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
19
19
|
# end
|
20
20
|
#
|
21
21
|
# @see https://github.com/rubocop-hq/rubocop-rspec/issues/735
|
22
|
-
class DescribedClassModuleWrapping <
|
22
|
+
class DescribedClassModuleWrapping < Base
|
23
23
|
MSG = 'Avoid opening modules and defining specs within them.'
|
24
24
|
|
25
25
|
def_node_search :find_rspec_blocks,
|
@@ -41,7 +41,8 @@ module RuboCop
|
|
41
41
|
# describe 'display name presence' do
|
42
42
|
# # ...
|
43
43
|
# end
|
44
|
-
class Dialect <
|
44
|
+
class Dialect < Base
|
45
|
+
extend AutoCorrector
|
45
46
|
include MethodPreference
|
46
47
|
|
47
48
|
MSG = 'Prefer `%<prefer>s` over `%<current>s`.'
|
@@ -52,24 +53,16 @@ module RuboCop
|
|
52
53
|
return unless rspec_method?(node)
|
53
54
|
return unless preferred_methods[node.method_name]
|
54
55
|
|
55
|
-
|
56
|
-
|
56
|
+
msg = format(MSG, prefer: preferred_method(node.method_name),
|
57
|
+
current: node.method_name)
|
57
58
|
|
58
|
-
|
59
|
-
lambda do |corrector|
|
59
|
+
add_offense(node, message: msg) do |corrector|
|
60
60
|
current = node.loc.selector
|
61
61
|
preferred = preferred_method(current.source)
|
62
62
|
|
63
63
|
corrector.replace(current, preferred)
|
64
64
|
end
|
65
65
|
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
def message(node)
|
70
|
-
format(MSG, prefer: preferred_method(node.method_name),
|
71
|
-
current: node.method_name)
|
72
|
-
end
|
73
66
|
end
|
74
67
|
end
|
75
68
|
end
|
@@ -57,20 +57,104 @@ module RuboCop
|
|
57
57
|
# end
|
58
58
|
# end
|
59
59
|
#
|
60
|
-
class EmptyExampleGroup <
|
60
|
+
class EmptyExampleGroup < Base
|
61
61
|
MSG = 'Empty example group detected.'
|
62
62
|
|
63
|
-
|
63
|
+
# @!method example_group_body(node)
|
64
|
+
# Match example group blocks and yield their body
|
65
|
+
#
|
66
|
+
# @example source that matches
|
67
|
+
# describe 'example group' do
|
68
|
+
# it { is_expected.to be }
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# @param node [RuboCop::AST::Node]
|
72
|
+
# @yield [RuboCop::AST::Node] example group body
|
73
|
+
def_node_matcher :example_group_body, <<~PATTERN
|
74
|
+
(block #{ExampleGroups::ALL.send_pattern} args $_)
|
75
|
+
PATTERN
|
76
|
+
|
77
|
+
# @!method example_or_group_or_include?(node)
|
78
|
+
# Match examples, example groups and includes
|
79
|
+
#
|
80
|
+
# @example source that matches
|
81
|
+
# it { is_expected.to fly }
|
82
|
+
# describe('non-empty example groups too') { }
|
83
|
+
# it_behaves_like 'an animal'
|
84
|
+
# it_behaves_like('a cat') { let(:food) { 'milk' } }
|
85
|
+
# it_has_root_access
|
86
|
+
#
|
87
|
+
# @param node [RuboCop::AST::Node]
|
88
|
+
# @return [Array<RuboCop::AST::Node>] matching nodes
|
89
|
+
def_node_matcher :example_or_group_or_include?, <<~PATTERN
|
64
90
|
{
|
65
|
-
#{
|
66
|
-
|
91
|
+
#{Examples::ALL.block_pattern}
|
92
|
+
#{ExampleGroups::ALL.block_pattern}
|
93
|
+
#{Includes::ALL.send_pattern}
|
94
|
+
#{Includes::ALL.block_pattern}
|
95
|
+
(send nil? #custom_include? ...)
|
67
96
|
}
|
68
97
|
PATTERN
|
69
98
|
|
70
|
-
|
71
|
-
|
99
|
+
# @!method examples_inside_block?(node)
|
100
|
+
# Match examples defined inside a block which is not a hook
|
101
|
+
#
|
102
|
+
# @example source that matches
|
103
|
+
# %w(r g b).each do |color|
|
104
|
+
# it { is_expected.to have_color(color) }
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
# @example source that does not match
|
108
|
+
# before do
|
109
|
+
# it { is_expected.to fall_into_oblivion }
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# @param node [RuboCop::AST::Node]
|
113
|
+
# @return [Array<RuboCop::AST::Node>] matching nodes
|
114
|
+
def_node_matcher :examples_inside_block?, <<~PATTERN
|
115
|
+
(block !#{Hooks::ALL.send_pattern} _ #examples?)
|
116
|
+
PATTERN
|
72
117
|
|
73
|
-
|
118
|
+
# @!method examples_directly_or_in_block?(node)
|
119
|
+
# Match examples or examples inside blocks
|
120
|
+
#
|
121
|
+
# @example source that matches
|
122
|
+
# it { expect(drink).to be_cold }
|
123
|
+
# context('when winter') { it { expect(drink).to be_hot } }
|
124
|
+
# (1..5).each { |divisor| it { is_expected.to divide_by(divisor) } }
|
125
|
+
#
|
126
|
+
# @param node [RuboCop::AST::Node]
|
127
|
+
# @return [Array<RuboCop::AST::Node>] matching nodes
|
128
|
+
def_node_matcher :examples_directly_or_in_block?, <<~PATTERN
|
129
|
+
{
|
130
|
+
#example_or_group_or_include?
|
131
|
+
#examples_inside_block?
|
132
|
+
}
|
133
|
+
PATTERN
|
134
|
+
|
135
|
+
# @!method examples?(node)
|
136
|
+
# Matches examples defined in scopes where they could run
|
137
|
+
#
|
138
|
+
# @example source that matches
|
139
|
+
# it { expect(myself).to be_run }
|
140
|
+
# describe { it { i_run_as_well } }
|
141
|
+
#
|
142
|
+
# @example source that does not match
|
143
|
+
# before { it { whatever here wont run anyway } }
|
144
|
+
#
|
145
|
+
# @param node [RuboCop::AST::Node]
|
146
|
+
# @return [Array<RuboCop::AST::Node>] matching nodes
|
147
|
+
def_node_matcher :examples?, <<~PATTERN
|
148
|
+
{
|
149
|
+
#examples_directly_or_in_block?
|
150
|
+
(begin <#examples_directly_or_in_block? ...>)
|
151
|
+
}
|
152
|
+
PATTERN
|
153
|
+
|
154
|
+
def on_block(node)
|
155
|
+
example_group_body(node) do |body|
|
156
|
+
add_offense(node.send_node) unless examples?(body)
|
157
|
+
end
|
74
158
|
end
|
75
159
|
|
76
160
|
private
|