rubocop-rspec 2.21.0 → 3.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 +147 -9
- data/README.md +2 -2
- data/config/default.yml +159 -244
- data/config/obsoletion.yml +24 -0
- data/lib/rubocop/cop/rspec/around_block.rb +3 -3
- data/lib/rubocop/cop/rspec/base.rb +0 -1
- data/lib/rubocop/cop/rspec/be.rb +1 -1
- data/lib/rubocop/cop/rspec/be_empty.rb +1 -0
- data/lib/rubocop/cop/rspec/be_eq.rb +1 -1
- data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
- data/lib/rubocop/cop/rspec/be_nil.rb +2 -2
- data/lib/rubocop/cop/rspec/before_after_all.rb +7 -13
- data/lib/rubocop/cop/rspec/change_by_zero.rb +30 -4
- data/lib/rubocop/cop/rspec/context_method.rb +2 -2
- data/lib/rubocop/cop/rspec/context_wording.rb +1 -1
- data/lib/rubocop/cop/rspec/describe_symbol.rb +1 -1
- data/lib/rubocop/cop/rspec/described_class.rb +33 -11
- data/lib/rubocop/cop/rspec/dialect.rb +13 -0
- data/lib/rubocop/cop/rspec/duplicated_metadata.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_example_group.rb +4 -1
- data/lib/rubocop/cop/rspec/empty_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +2 -2
- data/lib/rubocop/cop/rspec/empty_metadata.rb +46 -0
- data/lib/rubocop/cop/rspec/empty_output.rb +47 -0
- data/lib/rubocop/cop/rspec/eq.rb +47 -0
- data/lib/rubocop/cop/rspec/example_length.rb +11 -5
- data/lib/rubocop/cop/rspec/example_without_description.rb +11 -2
- data/lib/rubocop/cop/rspec/example_wording.rb +11 -2
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +14 -5
- data/lib/rubocop/cop/rspec/expect_actual.rb +17 -14
- data/lib/rubocop/cop/rspec/expect_change.rb +2 -2
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
- data/lib/rubocop/cop/rspec/expect_output.rb +1 -4
- data/lib/rubocop/cop/rspec/focus.rb +17 -2
- data/lib/rubocop/cop/rspec/hook_argument.rb +2 -2
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +1 -1
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +2 -2
- data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
- data/lib/rubocop/cop/rspec/implicit_subject.rb +2 -2
- data/lib/rubocop/cop/rspec/indexed_let.rb +32 -1
- data/lib/rubocop/cop/rspec/instance_spy.rb +2 -2
- data/lib/rubocop/cop/rspec/instance_variable.rb +4 -4
- data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +3 -3
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +2 -2
- data/lib/rubocop/cop/rspec/let_before_examples.rb +5 -1
- data/lib/rubocop/cop/rspec/let_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/message_expectation.rb +1 -2
- data/lib/rubocop/cop/rspec/message_spies.rb +0 -2
- data/lib/rubocop/cop/rspec/metadata_style.rb +202 -0
- data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/file_help.rb +14 -0
- data/lib/rubocop/cop/rspec/mixin/metadata.rb +21 -7
- data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +2 -2
- data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +16 -11
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +2 -4
- data/lib/rubocop/cop/rspec/named_subject.rb +6 -3
- data/lib/rubocop/cop/rspec/pending.rb +12 -2
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +1 -1
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +10 -10
- 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_predicate_matcher.rb +67 -0
- data/lib/rubocop/cop/rspec/remove_const.rb +39 -0
- data/lib/rubocop/cop/rspec/repeated_example.rb +6 -6
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +2 -2
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_subject_call.rb +125 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +1 -1
- data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_context.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_examples.rb +66 -20
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +2 -3
- data/lib/rubocop/cop/rspec/sort_metadata.rb +3 -2
- 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 +4 -2
- data/lib/rubocop/cop/rspec/subject_stub.rb +6 -6
- data/lib/rubocop/cop/rspec/undescriptive_literals_description.rb +69 -0
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +2 -2
- data/lib/rubocop/cop/rspec/variable_definition.rb +4 -4
- data/lib/rubocop/cop/rspec/verified_double_reference.rb +6 -6
- data/lib/rubocop/cop/rspec/verified_doubles.rb +2 -2
- data/lib/rubocop/cop/rspec/void_expect.rb +4 -3
- data/lib/rubocop/cop/rspec_cops.rb +14 -28
- data/lib/rubocop/rspec/concept.rb +0 -1
- data/lib/rubocop/rspec/config_formatter.rb +1 -11
- data/lib/rubocop/rspec/cop/generator.rb +25 -0
- data/lib/rubocop/rspec/language.rb +8 -9
- data/lib/rubocop/rspec/node.rb +1 -1
- data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +1 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop/rspec/wording.rb +8 -0
- data/lib/rubocop-rspec.rb +2 -16
- metadata +27 -49
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +0 -39
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +0 -104
- data/lib/rubocop/cop/rspec/capybara/match_style.rb +0 -38
- data/lib/rubocop/cop/rspec/capybara/negation_matcher.rb +0 -33
- data/lib/rubocop/cop/rspec/capybara/specific_actions.rb +0 -29
- data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +0 -24
- data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +0 -35
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +0 -36
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +0 -128
- data/lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb +0 -117
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +0 -260
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +0 -56
- data/lib/rubocop/cop/rspec/factory_bot/factory_name_style.rb +0 -74
- data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +0 -89
- data/lib/rubocop/cop/rspec/file_path.rb +0 -173
- data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +0 -43
- data/lib/rubocop/cop/rspec/rails/have_http_status.rb +0 -55
- data/lib/rubocop/cop/rspec/rails/http_status.rb +0 -203
- data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +0 -145
- data/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +0 -60
- data/lib/rubocop/cop/rspec/rails/travel_around.rb +0 -92
- data/lib/rubocop/rspec/factory_bot/language.rb +0 -37
- data/lib/rubocop/rspec/factory_bot.rb +0 -64
- data/lib/rubocop/rspec/language/node_pattern.rb +0 -48
data/config/obsoletion.yml
CHANGED
@@ -21,3 +21,27 @@ renamed:
|
|
21
21
|
RSpec/Capybara/SpecificFinders: Capybara/SpecificFinders
|
22
22
|
RSpec/Capybara/SpecificMatcher: Capybara/SpecificMatcher
|
23
23
|
RSpec/Capybara/VisibilityMatcher: Capybara/VisibilityMatcher
|
24
|
+
RSpec/FactoryBot/AttributeDefinedStatically: FactoryBot/AttributeDefinedStatically
|
25
|
+
RSpec/FactoryBot/ConsistentParenthesesStyle: FactoryBot/ConsistentParenthesesStyle
|
26
|
+
RSpec/FactoryBot/CreateList: FactoryBot/CreateList
|
27
|
+
RSpec/FactoryBot/FactoryClassName: FactoryBot/FactoryClassName
|
28
|
+
RSpec/FactoryBot/FactoryNameStyle: FactoryBot/FactoryNameStyle
|
29
|
+
RSpec/FactoryBot/SyntaxMethods: FactoryBot/SyntaxMethods
|
30
|
+
RSpec/Rails/AvoidSetupHook: RSpecRails/AvoidSetupHook
|
31
|
+
RSpec/Rails/HaveHttpStatus: RSpecRails/HaveHttpStatus
|
32
|
+
RSpec/Rails/HttpStatus: RSpecRails/HttpStatus
|
33
|
+
RSpec/Rails/InferredSpecType: RSpecRails/InferredSpecType
|
34
|
+
RSpec/Rails/MinitestAssertions: RSpecRails/MinitestAssertions
|
35
|
+
RSpec/Rails/NegationBeValid: RSpecRails/NegationBeValid
|
36
|
+
RSpec/Rails/TravelAround: RSpecRails/TravelAround
|
37
|
+
|
38
|
+
split:
|
39
|
+
RSpec/FilePath:
|
40
|
+
alternatives:
|
41
|
+
- RSpec/SpecFilePathFormat
|
42
|
+
- RSpec/SpecFilePathSuffix
|
43
|
+
|
44
|
+
removed:
|
45
|
+
RSpec/Capybara/FeatureMethods:
|
46
|
+
reason: >
|
47
|
+
this cop has migrated to `RSpec/Dialect`. Please use `RSpec/Dialect` instead
|
@@ -32,17 +32,17 @@ module RuboCop
|
|
32
32
|
'or `%<arg>s.run`.'
|
33
33
|
|
34
34
|
# @!method hook_block(node)
|
35
|
-
def_node_matcher :hook_block,
|
35
|
+
def_node_matcher :hook_block, <<~PATTERN
|
36
36
|
(block (send nil? :around sym ?) (args $...) ...)
|
37
37
|
PATTERN
|
38
38
|
|
39
39
|
# @!method hook_numblock(node)
|
40
|
-
def_node_matcher :hook_numblock,
|
40
|
+
def_node_matcher :hook_numblock, <<~PATTERN
|
41
41
|
(numblock (send nil? :around sym ?) ...)
|
42
42
|
PATTERN
|
43
43
|
|
44
44
|
# @!method find_arg_usage(node)
|
45
|
-
def_node_search :find_arg_usage,
|
45
|
+
def_node_search :find_arg_usage, <<~PATTERN
|
46
46
|
{(send $... {:call :run}) (send _ _ $...) (yield $...) (block-pass $...)}
|
47
47
|
PATTERN
|
48
48
|
|
data/lib/rubocop/cop/rspec/be.rb
CHANGED
@@ -44,7 +44,7 @@ module RuboCop
|
|
44
44
|
RESTRICT_ON_SEND = %i[to].freeze
|
45
45
|
|
46
46
|
# @!method eql_type_with_identity(node)
|
47
|
-
def_node_matcher :eql_type_with_identity,
|
47
|
+
def_node_matcher :eql_type_with_identity, <<~PATTERN
|
48
48
|
(send _ :to $(send nil? :eql {true false int float sym nil}))
|
49
49
|
PATTERN
|
50
50
|
|
@@ -33,12 +33,12 @@ module RuboCop
|
|
33
33
|
RESTRICT_ON_SEND = %i[be be_nil].freeze
|
34
34
|
|
35
35
|
# @!method be_nil_matcher?(node)
|
36
|
-
def_node_matcher :be_nil_matcher?,
|
36
|
+
def_node_matcher :be_nil_matcher?, <<~PATTERN
|
37
37
|
(send nil? :be_nil)
|
38
38
|
PATTERN
|
39
39
|
|
40
40
|
# @!method nil_value_expectation?(node)
|
41
|
-
def_node_matcher :nil_value_expectation?,
|
41
|
+
def_node_matcher :nil_value_expectation?, <<~PATTERN
|
42
42
|
(send nil? :be nil)
|
43
43
|
PATTERN
|
44
44
|
|
@@ -3,22 +3,16 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
|
-
# Check that before/after(:all) isn't being used.
|
6
|
+
# Check that before/after(:all/:context) isn't being used.
|
7
7
|
#
|
8
8
|
# @example
|
9
|
-
# # bad
|
10
|
-
# #
|
11
|
-
# # Faster but risk of state leaking between examples
|
12
|
-
# #
|
9
|
+
# # bad - Faster but risk of state leaking between examples
|
13
10
|
# describe MyClass do
|
14
11
|
# before(:all) { Widget.create }
|
15
|
-
# after(:
|
12
|
+
# after(:context) { Widget.delete_all }
|
16
13
|
# end
|
17
14
|
#
|
18
|
-
# # good
|
19
|
-
# #
|
20
|
-
# # Slower but examples are properly isolated
|
21
|
-
# #
|
15
|
+
# # good - Slower but examples are properly isolated
|
22
16
|
# describe MyClass do
|
23
17
|
# before(:each) { Widget.create }
|
24
18
|
# after(:each) { Widget.delete_all }
|
@@ -30,11 +24,11 @@ module RuboCop
|
|
30
24
|
'`use_transactional_fixtures` is enabled, then records created ' \
|
31
25
|
'in `%<hook>s` are not automatically rolled back.'
|
32
26
|
|
33
|
-
RESTRICT_ON_SEND =
|
27
|
+
RESTRICT_ON_SEND = Set[:before, :after].freeze
|
34
28
|
|
35
29
|
# @!method before_or_after_all(node)
|
36
|
-
def_node_matcher :before_or_after_all,
|
37
|
-
$(send _
|
30
|
+
def_node_matcher :before_or_after_all, <<~PATTERN
|
31
|
+
$(send _ RESTRICT_ON_SEND (sym {:all :context}))
|
38
32
|
PATTERN
|
39
33
|
|
40
34
|
def on_send(node)
|
@@ -59,6 +59,8 @@ module RuboCop
|
|
59
59
|
#
|
60
60
|
class ChangeByZero < Base
|
61
61
|
extend AutoCorrector
|
62
|
+
include RangeHelp
|
63
|
+
|
62
64
|
MSG = 'Prefer `not_to change` over `to %<method>s.by(0)`.'
|
63
65
|
MSG_COMPOUND = 'Prefer %<preferred>s with compound expectations ' \
|
64
66
|
'over `%<method>s.by(0)`.'
|
@@ -66,14 +68,14 @@ module RuboCop
|
|
66
68
|
RESTRICT_ON_SEND = CHANGE_METHODS.freeze
|
67
69
|
|
68
70
|
# @!method expect_change_with_arguments(node)
|
69
|
-
def_node_matcher :expect_change_with_arguments,
|
71
|
+
def_node_matcher :expect_change_with_arguments, <<~PATTERN
|
70
72
|
(send
|
71
73
|
$(send nil? CHANGE_METHODS ...) :by
|
72
74
|
(int 0))
|
73
75
|
PATTERN
|
74
76
|
|
75
77
|
# @!method expect_change_with_block(node)
|
76
|
-
def_node_matcher :expect_change_with_block,
|
78
|
+
def_node_matcher :expect_change_with_block, <<~PATTERN
|
77
79
|
(send
|
78
80
|
(block
|
79
81
|
$(send nil? CHANGE_METHODS)
|
@@ -83,7 +85,7 @@ module RuboCop
|
|
83
85
|
PATTERN
|
84
86
|
|
85
87
|
# @!method change_nodes(node)
|
86
|
-
def_node_search :change_nodes,
|
88
|
+
def_node_search :change_nodes, <<~PATTERN
|
87
89
|
$(send nil? CHANGE_METHODS ...)
|
88
90
|
PATTERN
|
89
91
|
|
@@ -140,8 +142,32 @@ module RuboCop
|
|
140
142
|
|
141
143
|
change_nodes(node) do |change_node|
|
142
144
|
corrector.replace(change_node.loc.selector, negated_matcher)
|
143
|
-
|
145
|
+
insert_operator(corrector, node, change_node)
|
146
|
+
remove_by_zero(corrector, node, change_node)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def insert_operator(corrector, node, change_node)
|
151
|
+
operator = node.right_siblings.first
|
152
|
+
return unless %i[& |].include?(operator)
|
153
|
+
|
154
|
+
corrector.insert_after(
|
155
|
+
replace_node(node, change_node), " #{operator}"
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
159
|
+
def replace_node(node, change_node)
|
160
|
+
expect_change_with_arguments(node) ? change_node : change_node.parent
|
161
|
+
end
|
162
|
+
|
163
|
+
def remove_by_zero(corrector, node, change_node)
|
164
|
+
range = node.loc.dot.with(end_pos: node.source_range.end_pos)
|
165
|
+
if change_node.loc.line == range.line
|
144
166
|
corrector.remove(range)
|
167
|
+
else
|
168
|
+
corrector.remove(
|
169
|
+
range_by_whole_lines(range, include_final_newline: true)
|
170
|
+
)
|
145
171
|
end
|
146
172
|
end
|
147
173
|
|
@@ -30,7 +30,7 @@ module RuboCop
|
|
30
30
|
MSG = 'Use `describe` for testing methods.'
|
31
31
|
|
32
32
|
# @!method context_method(node)
|
33
|
-
def_node_matcher :context_method,
|
33
|
+
def_node_matcher :context_method, <<~PATTERN
|
34
34
|
(block
|
35
35
|
(send #rspec? :context
|
36
36
|
${(str #method_name?) (dstr (str #method_name?) ...)}
|
@@ -38,7 +38,7 @@ module RuboCop
|
|
38
38
|
...)
|
39
39
|
PATTERN
|
40
40
|
|
41
|
-
def on_block(node)
|
41
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
42
42
|
context_method(node) do |context|
|
43
43
|
add_offense(context) do |corrector|
|
44
44
|
corrector.replace(node.send_node.loc.selector, 'describe')
|
@@ -61,7 +61,7 @@ module RuboCop
|
|
61
61
|
MSG = 'Context description should match %<patterns>s.'
|
62
62
|
|
63
63
|
# @!method context_wording(node)
|
64
|
-
def_node_matcher :context_wording,
|
64
|
+
def_node_matcher :context_wording, <<~PATTERN
|
65
65
|
(block (send #rspec? { :context :shared_context } $({str dstr xstr} ...) ...) ...)
|
66
66
|
PATTERN
|
67
67
|
|
@@ -8,8 +8,10 @@ module RuboCop
|
|
8
8
|
# If the first argument of describe is a class, the class is exposed to
|
9
9
|
# each example via described_class.
|
10
10
|
#
|
11
|
-
# This cop can be configured using the `EnforcedStyle
|
12
|
-
# options.
|
11
|
+
# This cop can be configured using the `EnforcedStyle`, `SkipBlocks`
|
12
|
+
# and `OnlyStaticConstants` options.
|
13
|
+
# `OnlyStaticConstants` is only relevant when `EnforcedStyle` is
|
14
|
+
# `described_class`.
|
13
15
|
#
|
14
16
|
# @example `EnforcedStyle: described_class` (default)
|
15
17
|
# # bad
|
@@ -22,6 +24,18 @@ module RuboCop
|
|
22
24
|
# subject { described_class.do_something }
|
23
25
|
# end
|
24
26
|
#
|
27
|
+
# @example `OnlyStaticConstants: true` (default)
|
28
|
+
# # good
|
29
|
+
# describe MyClass do
|
30
|
+
# subject { MyClass::CONSTANT }
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# @example `OnlyStaticConstants: false`
|
34
|
+
# # bad
|
35
|
+
# describe MyClass do
|
36
|
+
# subject { MyClass::CONSTANT }
|
37
|
+
# end
|
38
|
+
#
|
25
39
|
# @example `EnforcedStyle: explicit`
|
26
40
|
# # bad
|
27
41
|
# describe MyClass do
|
@@ -54,7 +68,7 @@ module RuboCop
|
|
54
68
|
# end
|
55
69
|
# end
|
56
70
|
#
|
57
|
-
class DescribedClass < Base
|
71
|
+
class DescribedClass < Base # rubocop:disable Metrics/ClassLength
|
58
72
|
extend AutoCorrector
|
59
73
|
include ConfigurableEnforcedStyle
|
60
74
|
include Namespace
|
@@ -63,7 +77,7 @@ module RuboCop
|
|
63
77
|
MSG = 'Use `%<replacement>s` instead of `%<src>s`.'
|
64
78
|
|
65
79
|
# @!method common_instance_exec_closure?(node)
|
66
|
-
def_node_matcher :common_instance_exec_closure?,
|
80
|
+
def_node_matcher :common_instance_exec_closure?, <<~PATTERN
|
67
81
|
(block (send (const nil? {:Class :Module :Struct}) :new ...) ...)
|
68
82
|
PATTERN
|
69
83
|
|
@@ -75,7 +89,7 @@ module RuboCop
|
|
75
89
|
def_node_matcher :scope_changing_syntax?, '{def class module}'
|
76
90
|
|
77
91
|
# @!method described_constant(node)
|
78
|
-
def_node_matcher :described_constant,
|
92
|
+
def_node_matcher :described_constant, <<~PATTERN
|
79
93
|
(block (send _ :describe $(const ...) ...) (args) $_)
|
80
94
|
PATTERN
|
81
95
|
|
@@ -112,14 +126,17 @@ module RuboCop
|
|
112
126
|
|
113
127
|
def find_usage(node, &block)
|
114
128
|
yield(node) if offensive?(node)
|
115
|
-
|
116
|
-
return if scope_change?(node) || node.const_type?
|
129
|
+
return if scope_change?(node) || allowed?(node)
|
117
130
|
|
118
131
|
node.each_child_node do |child|
|
119
132
|
find_usage(child, &block)
|
120
133
|
end
|
121
134
|
end
|
122
135
|
|
136
|
+
def allowed?(node)
|
137
|
+
node.const_type? && only_static_constants?
|
138
|
+
end
|
139
|
+
|
123
140
|
def message(offense)
|
124
141
|
if style == :described_class
|
125
142
|
format(MSG, replacement: DESCRIBED_CLASS, src: offense)
|
@@ -139,6 +156,10 @@ module RuboCop
|
|
139
156
|
node.block_type? && !rspec_block?(node) && cop_config['SkipBlocks']
|
140
157
|
end
|
141
158
|
|
159
|
+
def only_static_constants?
|
160
|
+
cop_config.fetch('OnlyStaticConstants', true)
|
161
|
+
end
|
162
|
+
|
142
163
|
def offensive?(node)
|
143
164
|
if style == :described_class
|
144
165
|
offensive_described_class?(node)
|
@@ -148,15 +169,15 @@ module RuboCop
|
|
148
169
|
end
|
149
170
|
|
150
171
|
def offensive_described_class?(node)
|
151
|
-
return unless node.const_type?
|
172
|
+
return false unless node.const_type?
|
152
173
|
|
153
174
|
# E.g. `described_class::CONSTANT`
|
154
|
-
return if contains_described_class?(node)
|
175
|
+
return false if contains_described_class?(node)
|
155
176
|
|
156
177
|
nearest_described_class, = node.each_ancestor(:block)
|
157
178
|
.map { |ancestor| described_constant(ancestor) }.find(&:itself)
|
158
179
|
|
159
|
-
return if nearest_described_class.equal?(node)
|
180
|
+
return false if nearest_described_class.equal?(node)
|
160
181
|
|
161
182
|
full_const_name(nearest_described_class) == full_const_name(node)
|
162
183
|
end
|
@@ -194,7 +215,8 @@ module RuboCop
|
|
194
215
|
# const_name(s(:const, s(:const, nil, :M), :C)) # => [:M, :C]
|
195
216
|
# const_name(s(:const, s(:cbase), :C)) # => [nil, :C]
|
196
217
|
def const_name(node)
|
197
|
-
namespace
|
218
|
+
namespace = node.namespace
|
219
|
+
name = node.short_name
|
198
220
|
if !namespace
|
199
221
|
[name]
|
200
222
|
elsif namespace.const_type?
|
@@ -29,6 +29,19 @@ module RuboCop
|
|
29
29
|
# PreferredMethods:
|
30
30
|
# context: describe
|
31
31
|
#
|
32
|
+
# If you were previously using the `RSpec/Capybara/FeatureMethods` cop and
|
33
|
+
# want to keep disabling all Capybara-specific methods that have the same
|
34
|
+
# native RSpec method (e.g. are just aliases), use the following config:
|
35
|
+
#
|
36
|
+
# RSpec/Dialect:
|
37
|
+
# PreferredMethods:
|
38
|
+
# background: :before
|
39
|
+
# scenario: :it
|
40
|
+
# xscenario: :xit
|
41
|
+
# given: :let
|
42
|
+
# given!: :let!
|
43
|
+
# feature: :describe
|
44
|
+
#
|
32
45
|
# You can expect the following behavior:
|
33
46
|
#
|
34
47
|
# @example
|
@@ -131,6 +131,7 @@ module RuboCop
|
|
131
131
|
{
|
132
132
|
#examples_directly_or_in_block?
|
133
133
|
(begin <#examples_directly_or_in_block? ...>)
|
134
|
+
(begin <#examples_in_branches? ...>)
|
134
135
|
}
|
135
136
|
PATTERN
|
136
137
|
|
@@ -161,7 +162,7 @@ module RuboCop
|
|
161
162
|
end
|
162
163
|
|
163
164
|
def conditionals_with_examples?(body)
|
164
|
-
return unless body.begin_type? || body.case_type?
|
165
|
+
return false unless body.begin_type? || body.case_type?
|
165
166
|
|
166
167
|
body.each_descendant(:if, :case).any? do |condition_node|
|
167
168
|
examples_in_branches?(condition_node)
|
@@ -169,6 +170,8 @@ module RuboCop
|
|
169
170
|
end
|
170
171
|
|
171
172
|
def examples_in_branches?(condition_node)
|
173
|
+
return false if !condition_node.if_type? && !condition_node.case_type?
|
174
|
+
|
172
175
|
condition_node.branches.any? { |branch| examples?(branch) }
|
173
176
|
end
|
174
177
|
|
@@ -71,8 +71,8 @@ module RuboCop
|
|
71
71
|
|
72
72
|
def next_one_line_example?(node)
|
73
73
|
next_sibling = node.right_sibling
|
74
|
-
return unless next_sibling
|
75
|
-
return unless example?(next_sibling)
|
74
|
+
return false unless next_sibling
|
75
|
+
return false unless example?(next_sibling)
|
76
76
|
|
77
77
|
next_sibling.single_line?
|
78
78
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Avoid empty metadata hash.
|
7
|
+
#
|
8
|
+
# @example EnforcedStyle: symbol (default)
|
9
|
+
# # bad
|
10
|
+
# describe 'Something', {}
|
11
|
+
#
|
12
|
+
# # good
|
13
|
+
# describe 'Something'
|
14
|
+
class EmptyMetadata < Base
|
15
|
+
extend AutoCorrector
|
16
|
+
|
17
|
+
include Metadata
|
18
|
+
include RangeHelp
|
19
|
+
|
20
|
+
MSG = 'Avoid empty metadata hash.'
|
21
|
+
|
22
|
+
def on_metadata(_symbols, hash)
|
23
|
+
return unless hash&.pairs&.empty?
|
24
|
+
|
25
|
+
add_offense(hash) do |corrector|
|
26
|
+
remove_empty_metadata(corrector, hash)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def remove_empty_metadata(corrector, node)
|
33
|
+
corrector.remove(
|
34
|
+
range_with_surrounding_comma(
|
35
|
+
range_with_surrounding_space(
|
36
|
+
node.source_range,
|
37
|
+
side: :left
|
38
|
+
),
|
39
|
+
:left
|
40
|
+
)
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Check that the `output` matcher is not called with an empty string.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# expect { foo }.to output('').to_stdout
|
11
|
+
# expect { bar }.not_to output('').to_stderr
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# expect { foo }.not_to output.to_stdout
|
15
|
+
# expect { bar }.to output.to_stderr
|
16
|
+
#
|
17
|
+
class EmptyOutput < Base
|
18
|
+
extend AutoCorrector
|
19
|
+
|
20
|
+
MSG = 'Use `%<runner>s` instead of matching on an empty output.'
|
21
|
+
RESTRICT_ON_SEND = Runners.all
|
22
|
+
|
23
|
+
# @!method matching_empty_output(node)
|
24
|
+
def_node_matcher :matching_empty_output, <<~PATTERN
|
25
|
+
(send
|
26
|
+
(block
|
27
|
+
(send nil? :expect) ...
|
28
|
+
)
|
29
|
+
#Runners.all
|
30
|
+
(send $(send nil? :output (str empty?)) ...)
|
31
|
+
)
|
32
|
+
PATTERN
|
33
|
+
|
34
|
+
def on_send(send_node)
|
35
|
+
matching_empty_output(send_node) do |node|
|
36
|
+
runner = send_node.method?(:to) ? 'not_to' : 'to'
|
37
|
+
message = format(MSG, runner: runner)
|
38
|
+
add_offense(node, message: message) do |corrector|
|
39
|
+
corrector.replace(send_node.loc.selector, runner)
|
40
|
+
corrector.replace(node, 'output')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Use `eq` instead of `be ==` to compare objects.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# expect(foo).to be == 42
|
11
|
+
#
|
12
|
+
# # good
|
13
|
+
# expect(foo).to eq 42
|
14
|
+
#
|
15
|
+
class Eq < Base
|
16
|
+
extend AutoCorrector
|
17
|
+
include RangeHelp
|
18
|
+
|
19
|
+
MSG = 'Use `eq` instead of `be ==` to compare objects.'
|
20
|
+
RESTRICT_ON_SEND = Runners.all
|
21
|
+
|
22
|
+
# @!method be_equals(node)
|
23
|
+
def_node_matcher :be_equals, <<~PATTERN
|
24
|
+
(send _ #Runners.all $(send (send nil? :be) :== _))
|
25
|
+
PATTERN
|
26
|
+
|
27
|
+
def on_send(node)
|
28
|
+
be_equals(node) do |matcher|
|
29
|
+
range = offense_range(matcher)
|
30
|
+
add_offense(range) do |corrector|
|
31
|
+
corrector.replace(range, 'eq')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def offense_range(matcher)
|
39
|
+
range_between(
|
40
|
+
matcher.source_range.begin_pos,
|
41
|
+
matcher.loc.selector.end_pos
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -26,11 +26,12 @@ module RuboCop
|
|
26
26
|
# expect(result).to be(true)
|
27
27
|
# end
|
28
28
|
#
|
29
|
-
# You can set
|
30
|
-
# Available are: 'array', 'hash', and '
|
31
|
-
# will be counted as one line regardless of
|
29
|
+
# You can set constructs you want to fold with `CountAsOne`.
|
30
|
+
# Available are: 'array', 'hash', 'heredoc', and 'method_call'.
|
31
|
+
# Each construct will be counted as one line regardless of
|
32
|
+
# its actual size.
|
32
33
|
#
|
33
|
-
# @example CountAsOne: ['array', 'heredoc']
|
34
|
+
# @example CountAsOne: ['array', 'heredoc', 'method_call']
|
34
35
|
#
|
35
36
|
# it do
|
36
37
|
# array = [ # +1
|
@@ -46,7 +47,12 @@ module RuboCop
|
|
46
47
|
# Heredoc
|
47
48
|
# content.
|
48
49
|
# HEREDOC
|
49
|
-
#
|
50
|
+
#
|
51
|
+
# foo( # +1
|
52
|
+
# 1,
|
53
|
+
# 2
|
54
|
+
# )
|
55
|
+
# end # 6 points
|
50
56
|
#
|
51
57
|
class ExampleLength < Base
|
52
58
|
include CodeLength
|
@@ -7,6 +7,7 @@ module RuboCop
|
|
7
7
|
#
|
8
8
|
# RSpec allows for auto-generated example descriptions when there is no
|
9
9
|
# description provided or the description is an empty one.
|
10
|
+
# It is acceptable to use `specify` without a description
|
10
11
|
#
|
11
12
|
# This cop removes empty descriptions.
|
12
13
|
# It also defines whether auto-generated description is allowed, based
|
@@ -14,17 +15,24 @@ module RuboCop
|
|
14
15
|
#
|
15
16
|
# This cop can be configured using the `EnforcedStyle` option
|
16
17
|
#
|
18
|
+
# @example
|
19
|
+
# # always good
|
20
|
+
# specify do
|
21
|
+
# result = service.call
|
22
|
+
# expect(result).to be(true)
|
23
|
+
# end
|
24
|
+
#
|
17
25
|
# @example `EnforcedStyle: always_allow` (default)
|
18
26
|
# # bad
|
19
27
|
# it('') { is_expected.to be_good }
|
20
|
-
#
|
28
|
+
# specify '' do
|
21
29
|
# result = service.call
|
22
30
|
# expect(result).to be(true)
|
23
31
|
# end
|
24
32
|
#
|
25
33
|
# # good
|
26
34
|
# it { is_expected.to be_good }
|
27
|
-
#
|
35
|
+
# specify do
|
28
36
|
# result = service.call
|
29
37
|
# expect(result).to be(true)
|
30
38
|
# end
|
@@ -75,6 +83,7 @@ module RuboCop
|
|
75
83
|
def check_example_without_description(node)
|
76
84
|
return if node.arguments?
|
77
85
|
return unless disallow_empty_description?(node)
|
86
|
+
return if node.method?(:specify) && node.parent.multiline?
|
78
87
|
|
79
88
|
add_offense(node, message: MSG_ADD_DESCRIPTION)
|
80
89
|
end
|