rubocop-rspec 2.21.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +147 -9
  3. data/README.md +2 -2
  4. data/config/default.yml +159 -244
  5. data/config/obsoletion.yml +24 -0
  6. data/lib/rubocop/cop/rspec/around_block.rb +3 -3
  7. data/lib/rubocop/cop/rspec/base.rb +0 -1
  8. data/lib/rubocop/cop/rspec/be.rb +1 -1
  9. data/lib/rubocop/cop/rspec/be_empty.rb +1 -0
  10. data/lib/rubocop/cop/rspec/be_eq.rb +1 -1
  11. data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
  12. data/lib/rubocop/cop/rspec/be_nil.rb +2 -2
  13. data/lib/rubocop/cop/rspec/before_after_all.rb +7 -13
  14. data/lib/rubocop/cop/rspec/change_by_zero.rb +30 -4
  15. data/lib/rubocop/cop/rspec/context_method.rb +2 -2
  16. data/lib/rubocop/cop/rspec/context_wording.rb +1 -1
  17. data/lib/rubocop/cop/rspec/describe_symbol.rb +1 -1
  18. data/lib/rubocop/cop/rspec/described_class.rb +33 -11
  19. data/lib/rubocop/cop/rspec/dialect.rb +13 -0
  20. data/lib/rubocop/cop/rspec/duplicated_metadata.rb +1 -1
  21. data/lib/rubocop/cop/rspec/empty_example_group.rb +4 -1
  22. data/lib/rubocop/cop/rspec/empty_hook.rb +1 -1
  23. data/lib/rubocop/cop/rspec/empty_line_after_example.rb +2 -2
  24. data/lib/rubocop/cop/rspec/empty_metadata.rb +46 -0
  25. data/lib/rubocop/cop/rspec/empty_output.rb +47 -0
  26. data/lib/rubocop/cop/rspec/eq.rb +47 -0
  27. data/lib/rubocop/cop/rspec/example_length.rb +11 -5
  28. data/lib/rubocop/cop/rspec/example_without_description.rb +11 -2
  29. data/lib/rubocop/cop/rspec/example_wording.rb +11 -2
  30. data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +14 -5
  31. data/lib/rubocop/cop/rspec/expect_actual.rb +17 -14
  32. data/lib/rubocop/cop/rspec/expect_change.rb +2 -2
  33. data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
  34. data/lib/rubocop/cop/rspec/expect_in_let.rb +42 -0
  35. data/lib/rubocop/cop/rspec/expect_output.rb +1 -4
  36. data/lib/rubocop/cop/rspec/focus.rb +17 -2
  37. data/lib/rubocop/cop/rspec/hook_argument.rb +2 -2
  38. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +1 -1
  39. data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +2 -2
  40. data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
  41. data/lib/rubocop/cop/rspec/implicit_subject.rb +2 -2
  42. data/lib/rubocop/cop/rspec/indexed_let.rb +32 -1
  43. data/lib/rubocop/cop/rspec/instance_spy.rb +2 -2
  44. data/lib/rubocop/cop/rspec/instance_variable.rb +4 -4
  45. data/lib/rubocop/cop/rspec/is_expected_specify.rb +45 -0
  46. data/lib/rubocop/cop/rspec/iterated_expectation.rb +3 -3
  47. data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +2 -2
  48. data/lib/rubocop/cop/rspec/let_before_examples.rb +5 -1
  49. data/lib/rubocop/cop/rspec/let_setup.rb +1 -1
  50. data/lib/rubocop/cop/rspec/message_expectation.rb +1 -2
  51. data/lib/rubocop/cop/rspec/message_spies.rb +0 -2
  52. data/lib/rubocop/cop/rspec/metadata_style.rb +202 -0
  53. data/lib/rubocop/cop/rspec/missing_expectation_target_method.rb +54 -0
  54. data/lib/rubocop/cop/rspec/mixin/file_help.rb +14 -0
  55. data/lib/rubocop/cop/rspec/mixin/metadata.rb +21 -7
  56. data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +2 -2
  57. data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -1
  58. data/lib/rubocop/cop/rspec/multiple_expectations.rb +16 -11
  59. data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +2 -4
  60. data/lib/rubocop/cop/rspec/named_subject.rb +6 -3
  61. data/lib/rubocop/cop/rspec/pending.rb +12 -2
  62. data/lib/rubocop/cop/rspec/pending_without_reason.rb +1 -1
  63. data/lib/rubocop/cop/rspec/predicate_matcher.rb +10 -10
  64. data/lib/rubocop/cop/rspec/receive_counts.rb +1 -1
  65. data/lib/rubocop/cop/rspec/receive_messages.rb +161 -0
  66. data/lib/rubocop/cop/rspec/redundant_predicate_matcher.rb +67 -0
  67. data/lib/rubocop/cop/rspec/remove_const.rb +39 -0
  68. data/lib/rubocop/cop/rspec/repeated_example.rb +6 -6
  69. data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +1 -1
  70. data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +2 -2
  71. data/lib/rubocop/cop/rspec/repeated_include_example.rb +1 -1
  72. data/lib/rubocop/cop/rspec/repeated_subject_call.rb +125 -0
  73. data/lib/rubocop/cop/rspec/return_from_stub.rb +1 -1
  74. data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
  75. data/lib/rubocop/cop/rspec/shared_context.rb +1 -1
  76. data/lib/rubocop/cop/rspec/shared_examples.rb +66 -20
  77. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +2 -3
  78. data/lib/rubocop/cop/rspec/sort_metadata.rb +3 -2
  79. data/lib/rubocop/cop/rspec/spec_file_path_format.rb +133 -0
  80. data/lib/rubocop/cop/rspec/spec_file_path_suffix.rb +40 -0
  81. data/lib/rubocop/cop/rspec/stubbed_mock.rb +4 -2
  82. data/lib/rubocop/cop/rspec/subject_stub.rb +6 -6
  83. data/lib/rubocop/cop/rspec/undescriptive_literals_description.rb +69 -0
  84. data/lib/rubocop/cop/rspec/unspecified_exception.rb +2 -2
  85. data/lib/rubocop/cop/rspec/variable_definition.rb +4 -4
  86. data/lib/rubocop/cop/rspec/verified_double_reference.rb +6 -6
  87. data/lib/rubocop/cop/rspec/verified_doubles.rb +2 -2
  88. data/lib/rubocop/cop/rspec/void_expect.rb +4 -3
  89. data/lib/rubocop/cop/rspec_cops.rb +14 -28
  90. data/lib/rubocop/rspec/concept.rb +0 -1
  91. data/lib/rubocop/rspec/config_formatter.rb +1 -11
  92. data/lib/rubocop/rspec/cop/generator.rb +25 -0
  93. data/lib/rubocop/rspec/language.rb +8 -9
  94. data/lib/rubocop/rspec/node.rb +1 -1
  95. data/lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb +1 -1
  96. data/lib/rubocop/rspec/version.rb +1 -1
  97. data/lib/rubocop/rspec/wording.rb +8 -0
  98. data/lib/rubocop-rspec.rb +2 -16
  99. metadata +27 -49
  100. data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +0 -39
  101. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +0 -104
  102. data/lib/rubocop/cop/rspec/capybara/match_style.rb +0 -38
  103. data/lib/rubocop/cop/rspec/capybara/negation_matcher.rb +0 -33
  104. data/lib/rubocop/cop/rspec/capybara/specific_actions.rb +0 -29
  105. data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +0 -24
  106. data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +0 -35
  107. data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +0 -36
  108. data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +0 -128
  109. data/lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb +0 -117
  110. data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +0 -260
  111. data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +0 -56
  112. data/lib/rubocop/cop/rspec/factory_bot/factory_name_style.rb +0 -74
  113. data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +0 -89
  114. data/lib/rubocop/cop/rspec/file_path.rb +0 -173
  115. data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +0 -43
  116. data/lib/rubocop/cop/rspec/rails/have_http_status.rb +0 -55
  117. data/lib/rubocop/cop/rspec/rails/http_status.rb +0 -203
  118. data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +0 -145
  119. data/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +0 -60
  120. data/lib/rubocop/cop/rspec/rails/travel_around.rb +0 -92
  121. data/lib/rubocop/rspec/factory_bot/language.rb +0 -37
  122. data/lib/rubocop/rspec/factory_bot.rb +0 -64
  123. data/lib/rubocop/rspec/language/node_pattern.rb +0 -48
@@ -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, <<-PATTERN
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, <<-PATTERN
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, <<-PATTERN
45
+ def_node_search :find_arg_usage, <<~PATTERN
46
46
  {(send $... {:call :run}) (send _ _ $...) (yield $...) (block-pass $...)}
47
47
  PATTERN
48
48
 
@@ -6,7 +6,6 @@ module RuboCop
6
6
  # @abstract parent class to RSpec cops
7
7
  class Base < ::RuboCop::Cop::Base
8
8
  include RuboCop::RSpec::Language
9
- extend RuboCop::RSpec::Language::NodePattern
10
9
 
11
10
  exclude_from_registry
12
11
 
@@ -24,7 +24,7 @@ module RuboCop
24
24
  RESTRICT_ON_SEND = Runners.all
25
25
 
26
26
  # @!method be_without_args(node)
27
- def_node_matcher :be_without_args, <<-PATTERN
27
+ def_node_matcher :be_without_args, <<~PATTERN
28
28
  (send _ #Runners.all $(send nil? :be))
29
29
  PATTERN
30
30
 
@@ -28,6 +28,7 @@ module RuboCop
28
28
  (send nil? :match_array (array))
29
29
  (send nil? :contain_exactly)
30
30
  }
31
+ _?
31
32
  )
32
33
  PATTERN
33
34
 
@@ -30,7 +30,7 @@ module RuboCop
30
30
  RESTRICT_ON_SEND = %i[eq].freeze
31
31
 
32
32
  # @!method eq_type_with_identity?(node)
33
- def_node_matcher :eq_type_with_identity?, <<-PATTERN
33
+ def_node_matcher :eq_type_with_identity?, <<~PATTERN
34
34
  (send nil? :eq {true false nil})
35
35
  PATTERN
36
36
 
@@ -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, <<-PATTERN
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?, <<-PATTERN
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?, <<-PATTERN
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(:all) { Widget.delete_all }
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 = %i[before after].freeze
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, <<-PATTERN
37
- $(send _ {:before :after} (sym {:all :context}))
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, <<-PATTERN
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, <<-PATTERN
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, <<-PATTERN
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
- range = node.loc.dot.with(end_pos: node.source_range.end_pos)
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, <<-PATTERN
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) # rubocop:disable InternalAffairs/NumblockHandler
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, <<-PATTERN
64
+ def_node_matcher :context_wording, <<~PATTERN
65
65
  (block (send #rspec? { :context :shared_context } $({str dstr xstr} ...) ...) ...)
66
66
  PATTERN
67
67
 
@@ -22,7 +22,7 @@ module RuboCop
22
22
  RESTRICT_ON_SEND = %i[describe].freeze
23
23
 
24
24
  # @!method describe_symbol?(node)
25
- def_node_matcher :describe_symbol?, <<-PATTERN
25
+ def_node_matcher :describe_symbol?, <<~PATTERN
26
26
  (send #rspec? :describe $sym ...)
27
27
  PATTERN
28
28
 
@@ -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` and `SkipBlocks`
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?, <<-PATTERN
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, <<-PATTERN
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, name = *node # rubocop:disable InternalAffairs/NodeDestructuring
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
@@ -19,7 +19,7 @@ module RuboCop
19
19
 
20
20
  MSG = 'Avoid duplicated metadata.'
21
21
 
22
- def on_metadata(symbols, _pairs)
22
+ def on_metadata(symbols, _hash)
23
23
  symbols.each do |symbol|
24
24
  on_metadata_symbol(symbol)
25
25
  end
@@ -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
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- # Checks for empty before and after hooks.
6
+ # Checks for empty before and after hooks.
7
7
  #
8
8
  # @example
9
9
  # # bad
@@ -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 literals you want to fold with `CountAsOne`.
30
- # Available are: 'array', 'hash', and 'heredoc'. Each literal
31
- # will be counted as one line regardless of its actual size.
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
- # end # 5 points
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
- # it '' do
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
- # it do
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