rubocop-rspec 2.13.1 → 2.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +405 -379
  3. data/CODE_OF_CONDUCT.md +4 -4
  4. data/MIT-LICENSE.md +1 -2
  5. data/config/default.yml +65 -4
  6. data/lib/rubocop/cop/rspec/capybara/negation_matcher.rb +106 -0
  7. data/lib/rubocop/cop/rspec/capybara/specific_actions.rb +85 -0
  8. data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +9 -2
  9. data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +5 -82
  10. data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +14 -14
  11. data/lib/rubocop/cop/rspec/change_by_zero.rb +1 -1
  12. data/lib/rubocop/cop/rspec/context_wording.rb +4 -2
  13. data/lib/rubocop/cop/rspec/example_wording.rb +32 -0
  14. data/lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb +99 -0
  15. data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +2 -2
  16. data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +1 -19
  17. data/lib/rubocop/cop/rspec/implicit_subject.rb +86 -19
  18. data/lib/rubocop/cop/rspec/let_before_examples.rb +15 -1
  19. data/lib/rubocop/cop/rspec/mixin/capybara_help.rb +80 -0
  20. data/lib/rubocop/cop/rspec/mixin/css_selector.rb +48 -1
  21. data/lib/rubocop/cop/rspec/mixin/skip_or_pending.rb +23 -0
  22. data/lib/rubocop/cop/rspec/no_expectation_example.rb +47 -6
  23. data/lib/rubocop/cop/rspec/pending.rb +2 -11
  24. data/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +135 -0
  25. data/lib/rubocop/cop/rspec/repeated_include_example.rb +1 -1
  26. data/lib/rubocop/cop/rspec/sort_metadata.rb +102 -0
  27. data/lib/rubocop/cop/rspec/subject_declaration.rb +1 -1
  28. data/lib/rubocop/cop/rspec_cops.rb +5 -0
  29. data/lib/rubocop/rspec/factory_bot/language.rb +20 -0
  30. data/lib/rubocop/rspec/version.rb +1 -1
  31. data/lib/rubocop-rspec.rb +2 -0
  32. metadata +9 -2
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ module Rails
7
+ # Identifies redundant spec type.
8
+ #
9
+ # After setting up rspec-rails, you will have enabled
10
+ # `config.infer_spec_type_from_file_location!` by default in
11
+ # spec/rails_helper.rb. This cop works in conjunction with this config.
12
+ # If you disable this config, disable this cop as well.
13
+ #
14
+ # @safety
15
+ # This cop is marked as unsafe because
16
+ # `config.infer_spec_type_from_file_location!` may not be enabled.
17
+ #
18
+ # @example
19
+ # # bad
20
+ # # spec/models/user_spec.rb
21
+ # RSpec.describe User, type: :model do
22
+ # end
23
+ #
24
+ # # good
25
+ # # spec/models/user_spec.rb
26
+ # RSpec.describe User do
27
+ # end
28
+ #
29
+ # # good
30
+ # # spec/models/user_spec.rb
31
+ # RSpec.describe User, type: :common do
32
+ # end
33
+ #
34
+ # @example `Inferences` configuration
35
+ # # .rubocop.yml
36
+ # # RSpec/InferredSpecType:
37
+ # # Inferences:
38
+ # # services: service
39
+ #
40
+ # # bad
41
+ # # spec/services/user_spec.rb
42
+ # RSpec.describe User, type: :service do
43
+ # end
44
+ #
45
+ # # good
46
+ # # spec/services/user_spec.rb
47
+ # RSpec.describe User do
48
+ # end
49
+ #
50
+ # # good
51
+ # # spec/services/user_spec.rb
52
+ # RSpec.describe User, type: :common do
53
+ # end
54
+ class InferredSpecType < Base
55
+ extend AutoCorrector
56
+
57
+ MSG = 'Remove redundant spec type.'
58
+
59
+ # @param [RuboCop::AST::BlockNode] node
60
+ def on_block(node)
61
+ return unless example_group?(node)
62
+
63
+ pair_node = describe_with_type(node)
64
+ return unless pair_node
65
+ return unless inferred_type?(pair_node)
66
+
67
+ removable_node = detect_removable_node(pair_node)
68
+ add_offense(removable_node) do |corrector|
69
+ autocorrect(corrector, removable_node)
70
+ end
71
+ end
72
+ alias on_numblock on_block
73
+
74
+ private
75
+
76
+ # @!method describe_with_type(node)
77
+ # @param [RuboCop::AST::BlockNode] node
78
+ # @return [RuboCop::AST::PairNode, nil]
79
+ def_node_matcher :describe_with_type, <<~PATTERN
80
+ (block
81
+ (send #rspec? #ExampleGroups.all
82
+ ...
83
+ (hash <$(pair (sym :type) sym) ...>)
84
+ )
85
+ ...
86
+ )
87
+ PATTERN
88
+
89
+ # @param [RuboCop::AST::Corrector] corrector
90
+ # @param [RuboCop::AST::Node] node
91
+ def autocorrect(corrector, node)
92
+ corrector.remove(
93
+ node.location.expression.with(
94
+ begin_pos: node.left_sibling.location.expression.end_pos
95
+ )
96
+ )
97
+ end
98
+
99
+ # @param [RuboCop::AST::PairNode] node
100
+ # @return [RuboCop::AST::Node]
101
+ def detect_removable_node(node)
102
+ if node.parent.pairs.size == 1
103
+ node.parent
104
+ else
105
+ node
106
+ end
107
+ end
108
+
109
+ # @return [String]
110
+ def file_path
111
+ processed_source.file_path
112
+ end
113
+
114
+ # @param [RuboCop::AST::PairNode] node
115
+ # @return [Boolean]
116
+ def inferred_type?(node)
117
+ inferred_type_from_file_path.inspect == node.value.source
118
+ end
119
+
120
+ # @return [Symbol, nil]
121
+ def inferred_type_from_file_path
122
+ inferences.find do |prefix, type|
123
+ break type.to_sym if file_path.include?("spec/#{prefix}/")
124
+ end
125
+ end
126
+
127
+ # @return [Hash]
128
+ def inferences
129
+ cop_config['Inferences'] || {}
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -47,7 +47,7 @@ module RuboCop
47
47
  #
48
48
  class RepeatedIncludeExample < Base
49
49
  MSG = 'Repeated include of shared_examples %<name>s ' \
50
- 'on line(s) %<repeat>s'
50
+ 'on line(s) %<repeat>s'
51
51
 
52
52
  # @!method several_include_examples?(node)
53
53
  def_node_matcher :several_include_examples?, <<-PATTERN
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Sort RSpec metadata alphabetically.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # describe 'Something', :b, :a
11
+ # context 'Something', foo: 'bar', baz: true
12
+ # it 'works', :b, :a, foo: 'bar', baz: true
13
+ #
14
+ # # good
15
+ # describe 'Something', :a, :b
16
+ # context 'Something', baz: true, foo: 'bar'
17
+ # it 'works', :a, :b, baz: true, foo: 'bar'
18
+ #
19
+ class SortMetadata < Base
20
+ extend AutoCorrector
21
+ include RangeHelp
22
+
23
+ MSG = 'Sort metadata alphabetically.'
24
+
25
+ # @!method rspec_metadata(node)
26
+ def_node_matcher :rspec_metadata, <<~PATTERN
27
+ (block
28
+ (send
29
+ #rspec? {#Examples.all #ExampleGroups.all #SharedGroups.all #Hooks.all #Includes.all}
30
+ _ ${send str sym}* (hash $...)?)
31
+ ...)
32
+ PATTERN
33
+
34
+ # @!method rspec_configure(node)
35
+ def_node_matcher :rspec_configure, <<~PATTERN
36
+ (block (send #rspec? :configure) (args (arg $_)) ...)
37
+ PATTERN
38
+
39
+ # @!method metadata_in_block(node)
40
+ def_node_search :metadata_in_block, <<~PATTERN
41
+ (send (lvar %) #Hooks.all _ ${send str sym}* (hash $...)?)
42
+ PATTERN
43
+
44
+ def on_block(node)
45
+ rspec_configure(node) do |block_var|
46
+ metadata_in_block(node, block_var) do |symbols, pairs|
47
+ investigate(symbols, pairs.flatten)
48
+ end
49
+ end
50
+
51
+ rspec_metadata(node) do |symbols, pairs|
52
+ investigate(symbols, pairs.flatten)
53
+ end
54
+ end
55
+
56
+ alias on_numblock on_block
57
+
58
+ private
59
+
60
+ def investigate(symbols, pairs)
61
+ return if sorted?(symbols, pairs)
62
+
63
+ crime_scene = crime_scene(symbols, pairs)
64
+ add_offense(crime_scene) do |corrector|
65
+ corrector.replace(crime_scene, replacement(symbols, pairs))
66
+ end
67
+ end
68
+
69
+ def crime_scene(symbols, pairs)
70
+ metadata = symbols + pairs
71
+
72
+ range_between(
73
+ metadata.first.loc.expression.begin_pos,
74
+ metadata.last.loc.expression.end_pos
75
+ )
76
+ end
77
+
78
+ def replacement(symbols, pairs)
79
+ (sort_symbols(symbols) + sort_pairs(pairs)).map(&:source).join(', ')
80
+ end
81
+
82
+ def sorted?(symbols, pairs)
83
+ symbols == sort_symbols(symbols) && pairs == sort_pairs(pairs)
84
+ end
85
+
86
+ def sort_pairs(pairs)
87
+ pairs.sort_by { |pair| pair.key.source.downcase }
88
+ end
89
+
90
+ def sort_symbols(symbols)
91
+ symbols.sort_by do |symbol|
92
+ if %i[str sym].include?(symbol.type)
93
+ symbol.value.to_s.downcase
94
+ else
95
+ symbol.source.downcase
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -25,7 +25,7 @@ module RuboCop
25
25
 
26
26
  # @!method offensive_subject_declaration?(node)
27
27
  def_node_matcher :offensive_subject_declaration?, <<~PATTERN
28
- (send nil? ${#Subjects.all #Helpers.all} {(sym :subject) (str "subject")} ...)
28
+ (send nil? ${#Subjects.all #Helpers.all} ({sym str} #Subjects.all) ...)
29
29
  PATTERN
30
30
 
31
31
  def on_send(node)
@@ -2,11 +2,14 @@
2
2
 
3
3
  require_relative 'rspec/capybara/current_path_expectation'
4
4
  require_relative 'rspec/capybara/feature_methods'
5
+ require_relative 'rspec/capybara/negation_matcher'
6
+ require_relative 'rspec/capybara/specific_actions'
5
7
  require_relative 'rspec/capybara/specific_finders'
6
8
  require_relative 'rspec/capybara/specific_matcher'
7
9
  require_relative 'rspec/capybara/visibility_matcher'
8
10
 
9
11
  require_relative 'rspec/factory_bot/attribute_defined_statically'
12
+ require_relative 'rspec/factory_bot/consistent_parentheses_style'
10
13
  require_relative 'rspec/factory_bot/create_list'
11
14
  require_relative 'rspec/factory_bot/factory_class_name'
12
15
  require_relative 'rspec/factory_bot/syntax_methods'
@@ -18,6 +21,7 @@ begin
18
21
  rescue LoadError
19
22
  # Rails/HttpStatus cannot be loaded if rack/utils is unavailable.
20
23
  end
24
+ require_relative 'rspec/rails/inferred_spec_type'
21
25
 
22
26
  require_relative 'rspec/align_left_let_brace'
23
27
  require_relative 'rspec/align_right_let_brace'
@@ -97,6 +101,7 @@ require_relative 'rspec/scattered_setup'
97
101
  require_relative 'rspec/shared_context'
98
102
  require_relative 'rspec/shared_examples'
99
103
  require_relative 'rspec/single_argument_message_chain'
104
+ require_relative 'rspec/sort_metadata'
100
105
  require_relative 'rspec/stubbed_mock'
101
106
  require_relative 'rspec/subject_declaration'
102
107
  require_relative 'rspec/subject_stub'
@@ -7,6 +7,26 @@ module RuboCop
7
7
  module Language
8
8
  extend RuboCop::NodePattern::Macros
9
9
 
10
+ METHODS = %i[
11
+ attributes_for
12
+ attributes_for_list
13
+ attributes_for_pair
14
+ build
15
+ build_list
16
+ build_pair
17
+ build_stubbed
18
+ build_stubbed_list
19
+ build_stubbed_pair
20
+ create
21
+ create_list
22
+ create_pair
23
+ generate
24
+ generate_list
25
+ null
26
+ null_list
27
+ null_pair
28
+ ].to_set.freeze
29
+
10
30
  # @!method factory_bot?(node)
11
31
  def_node_matcher :factory_bot?, <<~PATTERN
12
32
  (const {nil? cbase} {:FactoryGirl :FactoryBot})
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module RSpec
5
5
  # Version information for the RSpec RuboCop plugin.
6
6
  module Version
7
- STRING = '2.13.1'
7
+ STRING = '2.14.0'
8
8
  end
9
9
  end
10
10
  end
data/lib/rubocop-rspec.rb CHANGED
@@ -23,6 +23,8 @@ require_relative 'rubocop/cop/rspec/mixin/empty_line_separation'
23
23
  require_relative 'rubocop/cop/rspec/mixin/inside_example_group'
24
24
  require_relative 'rubocop/cop/rspec/mixin/namespace'
25
25
  require_relative 'rubocop/cop/rspec/mixin/css_selector'
26
+ require_relative 'rubocop/cop/rspec/mixin/skip_or_pending'
27
+ require_relative 'rubocop/cop/rspec/mixin/capybara_help'
26
28
 
27
29
  require_relative 'rubocop/rspec/concept'
28
30
  require_relative 'rubocop/rspec/example_group'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.13.1
4
+ version: 2.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Backus
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-09-12 00:00:00.000000000 Z
13
+ date: 2022-10-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubocop
@@ -58,6 +58,8 @@ files:
58
58
  - lib/rubocop/cop/rspec/before_after_all.rb
59
59
  - lib/rubocop/cop/rspec/capybara/current_path_expectation.rb
60
60
  - lib/rubocop/cop/rspec/capybara/feature_methods.rb
61
+ - lib/rubocop/cop/rspec/capybara/negation_matcher.rb
62
+ - lib/rubocop/cop/rspec/capybara/specific_actions.rb
61
63
  - lib/rubocop/cop/rspec/capybara/specific_finders.rb
62
64
  - lib/rubocop/cop/rspec/capybara/specific_matcher.rb
63
65
  - lib/rubocop/cop/rspec/capybara/visibility_matcher.rb
@@ -87,6 +89,7 @@ files:
87
89
  - lib/rubocop/cop/rspec/expect_in_hook.rb
88
90
  - lib/rubocop/cop/rspec/expect_output.rb
89
91
  - lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb
92
+ - lib/rubocop/cop/rspec/factory_bot/consistent_parentheses_style.rb
90
93
  - lib/rubocop/cop/rspec/factory_bot/create_list.rb
91
94
  - lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb
92
95
  - lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb
@@ -110,12 +113,14 @@ files:
110
113
  - lib/rubocop/cop/rspec/message_expectation.rb
111
114
  - lib/rubocop/cop/rspec/message_spies.rb
112
115
  - lib/rubocop/cop/rspec/missing_example_group_argument.rb
116
+ - lib/rubocop/cop/rspec/mixin/capybara_help.rb
113
117
  - lib/rubocop/cop/rspec/mixin/comments_help.rb
114
118
  - lib/rubocop/cop/rspec/mixin/css_selector.rb
115
119
  - lib/rubocop/cop/rspec/mixin/empty_line_separation.rb
116
120
  - lib/rubocop/cop/rspec/mixin/final_end_location.rb
117
121
  - lib/rubocop/cop/rspec/mixin/inside_example_group.rb
118
122
  - lib/rubocop/cop/rspec/mixin/namespace.rb
123
+ - lib/rubocop/cop/rspec/mixin/skip_or_pending.rb
119
124
  - lib/rubocop/cop/rspec/mixin/top_level_group.rb
120
125
  - lib/rubocop/cop/rspec/mixin/variable.rb
121
126
  - lib/rubocop/cop/rspec/multiple_describes.rb
@@ -132,6 +137,7 @@ files:
132
137
  - lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb
133
138
  - lib/rubocop/cop/rspec/rails/have_http_status.rb
134
139
  - lib/rubocop/cop/rspec/rails/http_status.rb
140
+ - lib/rubocop/cop/rspec/rails/inferred_spec_type.rb
135
141
  - lib/rubocop/cop/rspec/receive_counts.rb
136
142
  - lib/rubocop/cop/rspec/receive_never.rb
137
143
  - lib/rubocop/cop/rspec/repeated_description.rb
@@ -145,6 +151,7 @@ files:
145
151
  - lib/rubocop/cop/rspec/shared_context.rb
146
152
  - lib/rubocop/cop/rspec/shared_examples.rb
147
153
  - lib/rubocop/cop/rspec/single_argument_message_chain.rb
154
+ - lib/rubocop/cop/rspec/sort_metadata.rb
148
155
  - lib/rubocop/cop/rspec/stubbed_mock.rb
149
156
  - lib/rubocop/cop/rspec/subject_declaration.rb
150
157
  - lib/rubocop/cop/rspec/subject_stub.rb