rubocop-rspec 2.27.1 → 2.28.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 629669f9a1d9d41dae7bc62c630f3a6cdae80623d3213c8e79ac8eb207f79e59
4
- data.tar.gz: 5005161c3684fcd8b794284bcaeedc50253a545d649be9e0e0a82958fdd125b0
3
+ metadata.gz: 3bec4edcf5bcf8c729a8c897b3de5b80b68c08de7ee3b2a25cfa23518db43390
4
+ data.tar.gz: '0848c7f26310108d511c7986127016963432371d6554c679a8fb318387c05998'
5
5
  SHA512:
6
- metadata.gz: 8af331d4b31697228397a1122cbe331223d3f040f44d2260e5148d73177df5ba08ae2aea1d481b27f698b5d59c9522d1c5f4c5e08e14b473a548de75ccf218c6
7
- data.tar.gz: 0f86ea257bcd14e73c57b2e431f618e0959cf9dbeca6e22c4b75bd8d4945f670d8fdb65212ff12969b351b62c35f845ca28041d4b1b30627e7d64dda5932b365
6
+ metadata.gz: 72958ac870b50c4b3c5b91be2f18ab88d6b2abf64af255e56451c0a6f58b3fd570dd2a3452e7326af58af57cce9347e370978bd21685f6470bba50ea8d93b195
7
+ data.tar.gz: 34dc88c068186ac780e2c3e4ebc3048159c236acc4b685fd6630cd59de0910a3f4f181a310d0e2ff7d1b5f9a2609219118119ff23dee212b870b24f685aef195
data/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 2.28.0 (2024-03-30)
6
+
7
+ - Extract RSpec Rails cops to a separate repository, [`rubocop-rspec_rails`](https://github.com/rubocop/rubocop-rspec_rails). The `rubocop-rspec_rails` repository is a dependency of `rubocop-rspec` and the cops related to rspec-rails are aliased (`RSpec/Rails/Foo` == `RSpecRails/Foo`) until v3.0 is released, so the change will be invisible to users until then. ([@ydah])
8
+
5
9
  ## 2.27.1 (2024-03-03)
6
10
 
7
11
  - Fix a false positive for `RSpec/RepeatedSubjectCall` when `subject.method_call`. ([@ydah])
@@ -27,3 +27,10 @@ renamed:
27
27
  RSpec/FactoryBot/FactoryClassName: FactoryBot/FactoryClassName
28
28
  RSpec/FactoryBot/FactoryNameStyle: FactoryBot/FactoryNameStyle
29
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
@@ -26,7 +26,7 @@ module RuboCop
26
26
  # @example with AssignmentOnly configuration
27
27
  # # rubocop.yml
28
28
  # # RSpec/InstanceVariable:
29
- # # AssignmentOnly: false
29
+ # # AssignmentOnly: true
30
30
  #
31
31
  # # bad
32
32
  # describe MyClass do
@@ -4,39 +4,23 @@ module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
6
  module Rails
7
- # Checks that tests use RSpec `before` hook over Rails `setup` method.
8
- #
9
- # @example
10
- # # bad
11
- # setup do
12
- # allow(foo).to receive(:bar)
13
- # end
14
- #
15
- # # good
16
- # before do
17
- # allow(foo).to receive(:bar)
18
- # end
19
- #
20
- class AvoidSetupHook < Base
21
- extend AutoCorrector
22
-
23
- MSG = 'Use `before` instead of `setup`.'
24
-
25
- # @!method setup_call(node)
26
- def_node_matcher :setup_call, <<~PATTERN
27
- (block
28
- $(send nil? :setup)
29
- (args) _)
30
- PATTERN
31
-
32
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
33
- setup_call(node) do |setup|
34
- add_offense(node) do |corrector|
35
- corrector.replace setup, 'before'
36
- end
37
- end
38
- end
39
- end
7
+ # @!parse
8
+ # # Checks that tests use RSpec `before` hook over Rails `setup`
9
+ # # method.
10
+ # #
11
+ # # @example
12
+ # # # bad
13
+ # # setup do
14
+ # # allow(foo).to receive(:bar)
15
+ # # end
16
+ # #
17
+ # # # good
18
+ # # before do
19
+ # # allow(foo).to receive(:bar)
20
+ # # end
21
+ # #
22
+ # class AvoidSetupHook < RuboCop::Cop::RSpecRails::Base; end
23
+ AvoidSetupHook = ::RuboCop::Cop::RSpecRails::AvoidSetupHook
40
24
  end
41
25
  end
42
26
  end
@@ -4,75 +4,31 @@ module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
6
  module Rails
7
- # Checks that tests use `have_http_status` instead of equality matchers.
8
- #
9
- # @example ResponseMethods: ['response', 'last_response'] (default)
10
- # # bad
11
- # expect(response.status).to be(200)
12
- # expect(last_response.code).to eq("200")
13
- #
14
- # # good
15
- # expect(response).to have_http_status(200)
16
- # expect(last_response).to have_http_status(200)
17
- #
18
- # @example ResponseMethods: ['foo_response']
19
- # # bad
20
- # expect(foo_response.status).to be(200)
21
- #
22
- # # good
23
- # expect(foo_response).to have_http_status(200)
24
- #
25
- # # also good
26
- # expect(response).to have_http_status(200)
27
- # expect(last_response).to have_http_status(200)
28
- #
29
- class HaveHttpStatus < ::RuboCop::Cop::Base
30
- extend AutoCorrector
31
-
32
- MSG =
33
- 'Prefer `expect(%<response>s).%<to>s ' \
34
- 'have_http_status(%<status>s)` over `%<bad_code>s`.'
35
-
36
- RUNNERS = %i[to to_not not_to].to_set
37
- RESTRICT_ON_SEND = RUNNERS
38
-
39
- # @!method match_status(node)
40
- def_node_matcher :match_status, <<~PATTERN
41
- (send
42
- (send nil? :expect
43
- $(send $(send nil? #response_methods?) {:status :code})
44
- )
45
- $RUNNERS
46
- $(send nil? {:be :eq :eql :equal} ({int str} $_))
47
- )
48
- PATTERN
49
-
50
- def on_send(node) # rubocop:disable Metrics/MethodLength
51
- match_status(node) do
52
- |response_status, response_method, to, match, status|
53
- return unless status.to_s.match?(/\A\d+\z/)
54
-
55
- message = format(MSG, response: response_method.method_name,
56
- to: to, status: status,
57
- bad_code: node.source)
58
- add_offense(node, message: message) do |corrector|
59
- corrector.replace(response_status, response_method.method_name)
60
- corrector.replace(match.loc.selector, 'have_http_status')
61
- corrector.replace(match.first_argument, status.to_s)
62
- end
63
- end
64
- end
65
-
66
- private
67
-
68
- def response_methods?(name)
69
- response_methods.include?(name.to_s)
70
- end
71
-
72
- def response_methods
73
- cop_config.fetch('ResponseMethods', [])
74
- end
75
- end
7
+ # @!parse
8
+ # # Checks that tests use `have_http_status` instead of equality matchers.
9
+ # #
10
+ # # @example ResponseMethods: ['response', 'last_response'] (default)
11
+ # # # bad
12
+ # # expect(response.status).to be(200)
13
+ # # expect(last_response.code).to eq("200")
14
+ # #
15
+ # # # good
16
+ # # expect(response).to have_http_status(200)
17
+ # # expect(last_response).to have_http_status(200)
18
+ # #
19
+ # # @example ResponseMethods: ['foo_response']
20
+ # # # bad
21
+ # # expect(foo_response.status).to be(200)
22
+ # #
23
+ # # # good
24
+ # # expect(foo_response).to have_http_status(200)
25
+ # #
26
+ # # # also good
27
+ # # expect(response).to have_http_status(200)
28
+ # # expect(last_response).to have_http_status(200)
29
+ # #
30
+ # class HaveHttpStatus < ::RuboCop::Cop::Base; end
31
+ HaveHttpStatus = ::RuboCop::Cop::RSpecRails::HaveHttpStatus
76
32
  end
77
33
  end
78
34
  end
@@ -1,213 +1,60 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rack/utils'
4
-
5
3
  module RuboCop
6
4
  module Cop
7
5
  module RSpec
8
6
  module Rails
9
- # Enforces use of symbolic or numeric value to describe HTTP status.
10
- #
11
- # This cop inspects only `have_http_status` calls.
12
- # So, this cop does not check if a method starting with `be_*` is used
13
- # when setting for `EnforcedStyle: symbolic` or
14
- # `EnforcedStyle: numeric`.
15
- #
16
- # @example `EnforcedStyle: symbolic` (default)
17
- # # bad
18
- # it { is_expected.to have_http_status 200 }
19
- # it { is_expected.to have_http_status 404 }
20
- # it { is_expected.to have_http_status "403" }
21
- #
22
- # # good
23
- # it { is_expected.to have_http_status :ok }
24
- # it { is_expected.to have_http_status :not_found }
25
- # it { is_expected.to have_http_status :forbidden }
26
- # it { is_expected.to have_http_status :success }
27
- # it { is_expected.to have_http_status :error }
28
- #
29
- # @example `EnforcedStyle: numeric`
30
- # # bad
31
- # it { is_expected.to have_http_status :ok }
32
- # it { is_expected.to have_http_status :not_found }
33
- # it { is_expected.to have_http_status "forbidden" }
34
- #
35
- # # good
36
- # it { is_expected.to have_http_status 200 }
37
- # it { is_expected.to have_http_status 404 }
38
- # it { is_expected.to have_http_status 403 }
39
- # it { is_expected.to have_http_status :success }
40
- # it { is_expected.to have_http_status :error }
41
- #
42
- # @example `EnforcedStyle: be_status`
43
- # # bad
44
- # it { is_expected.to have_http_status :ok }
45
- # it { is_expected.to have_http_status :not_found }
46
- # it { is_expected.to have_http_status "forbidden" }
47
- # it { is_expected.to have_http_status 200 }
48
- # it { is_expected.to have_http_status 404 }
49
- # it { is_expected.to have_http_status "403" }
50
- #
51
- # # good
52
- # it { is_expected.to be_ok }
53
- # it { is_expected.to be_not_found }
54
- # it { is_expected.to have_http_status :success }
55
- # it { is_expected.to have_http_status :error }
56
- #
57
- class HttpStatus < Base
58
- extend AutoCorrector
59
- include ConfigurableEnforcedStyle
60
- RESTRICT_ON_SEND = %i[have_http_status].freeze
61
-
62
- # @!method http_status(node)
63
- def_node_matcher :http_status, <<~PATTERN
64
- (send nil? :have_http_status ${int sym str})
65
- PATTERN
66
-
67
- def on_send(node)
68
- http_status(node) do |arg|
69
- return if arg.str_type? && arg.heredoc?
70
-
71
- checker = checker_class.new(arg)
72
- return unless checker.offensive?
73
-
74
- add_offense(checker.offense_range,
75
- message: checker.message) do |corrector|
76
- corrector.replace(checker.offense_range, checker.prefer)
77
- end
78
- end
79
- end
80
-
81
- private
82
-
83
- def checker_class
84
- case style
85
- when :symbolic
86
- SymbolicStyleChecker
87
- when :numeric
88
- NumericStyleChecker
89
- when :be_status
90
- BeStatusStyleChecker
91
- end
92
- end
93
-
94
- # :nodoc:
95
- class StyleCheckerBase
96
- MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
97
- 'to describe HTTP status code.'
98
- ALLOWED_STATUSES = %i[error success missing redirect].freeze
99
-
100
- attr_reader :node
101
-
102
- def initialize(node)
103
- @node = node
104
- end
105
-
106
- def message
107
- format(MSG, prefer: prefer, current: current)
108
- end
109
-
110
- def current
111
- offense_range.source
112
- end
113
-
114
- def offense_range
115
- node
116
- end
117
-
118
- def allowed_symbol?
119
- node.sym_type? && ALLOWED_STATUSES.include?(node.value)
120
- end
121
-
122
- def custom_http_status_code?
123
- node.int_type? &&
124
- !::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(node.source.to_i)
125
- end
126
- end
127
-
128
- # :nodoc:
129
- class SymbolicStyleChecker < StyleCheckerBase
130
- def offensive?
131
- !node.sym_type? && !custom_http_status_code?
132
- end
133
-
134
- def prefer
135
- symbol.inspect
136
- end
137
-
138
- private
139
-
140
- def symbol
141
- ::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number)
142
- end
143
-
144
- def number
145
- node.value.to_i
146
- end
147
- end
148
-
149
- # :nodoc:
150
- class NumericStyleChecker < StyleCheckerBase
151
- def offensive?
152
- !node.int_type? && !allowed_symbol?
153
- end
154
-
155
- def prefer
156
- number.to_s
157
- end
158
-
159
- private
160
-
161
- def symbol
162
- node.value
163
- end
164
-
165
- def number
166
- ::Rack::Utils::SYMBOL_TO_STATUS_CODE[symbol.to_sym]
167
- end
168
- end
169
-
170
- # :nodoc:
171
- class BeStatusStyleChecker < StyleCheckerBase
172
- def offensive?
173
- (!node.sym_type? && !custom_http_status_code?) ||
174
- (!node.int_type? && !allowed_symbol?)
175
- end
176
-
177
- def offense_range
178
- node.parent
179
- end
180
-
181
- def prefer
182
- if node.sym_type?
183
- "be_#{node.value}"
184
- elsif node.int_type?
185
- "be_#{symbol}"
186
- elsif node.str_type?
187
- "be_#{normalize_str}"
188
- end
189
- end
190
-
191
- private
192
-
193
- def symbol
194
- ::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number)
195
- end
196
-
197
- def number
198
- node.value.to_i
199
- end
200
-
201
- def normalize_str
202
- str = node.value.to_s
203
- if str.match?(/\A\d+\z/)
204
- ::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(str.to_i)
205
- else
206
- str
207
- end
208
- end
209
- end
210
- end
7
+ # @!parse
8
+ # # Enforces use of symbolic or numeric value to describe HTTP status.
9
+ # #
10
+ # # This cop inspects only `have_http_status` calls.
11
+ # # So, this cop does not check if a method starting with `be_*` is
12
+ # # used when setting for `EnforcedStyle: symbolic` or
13
+ # # `EnforcedStyle: numeric`.
14
+ # #
15
+ # # @example `EnforcedStyle: symbolic` (default)
16
+ # # # bad
17
+ # # it { is_expected.to have_http_status 200 }
18
+ # # it { is_expected.to have_http_status 404 }
19
+ # # it { is_expected.to have_http_status "403" }
20
+ # #
21
+ # # # good
22
+ # # it { is_expected.to have_http_status :ok }
23
+ # # it { is_expected.to have_http_status :not_found }
24
+ # # it { is_expected.to have_http_status :forbidden }
25
+ # # it { is_expected.to have_http_status :success }
26
+ # # it { is_expected.to have_http_status :error }
27
+ # #
28
+ # # @example `EnforcedStyle: numeric`
29
+ # # # bad
30
+ # # it { is_expected.to have_http_status :ok }
31
+ # # it { is_expected.to have_http_status :not_found }
32
+ # # it { is_expected.to have_http_status "forbidden" }
33
+ # #
34
+ # # # good
35
+ # # it { is_expected.to have_http_status 200 }
36
+ # # it { is_expected.to have_http_status 404 }
37
+ # # it { is_expected.to have_http_status 403 }
38
+ # # it { is_expected.to have_http_status :success }
39
+ # # it { is_expected.to have_http_status :error }
40
+ # #
41
+ # # @example `EnforcedStyle: be_status`
42
+ # # # bad
43
+ # # it { is_expected.to have_http_status :ok }
44
+ # # it { is_expected.to have_http_status :not_found }
45
+ # # it { is_expected.to have_http_status "forbidden" }
46
+ # # it { is_expected.to have_http_status 200 }
47
+ # # it { is_expected.to have_http_status 404 }
48
+ # # it { is_expected.to have_http_status "403" }
49
+ # #
50
+ # # # good
51
+ # # it { is_expected.to be_ok }
52
+ # # it { is_expected.to be_not_found }
53
+ # # it { is_expected.to have_http_status :success }
54
+ # # it { is_expected.to have_http_status :error }
55
+ # #
56
+ # class HttpStatus < RuboCop::Cop::RSpecRails::Base; end
57
+ HttpStatus = ::RuboCop::Cop::RSpecRails::HttpStatus
211
58
  end
212
59
  end
213
60
  end
@@ -4,141 +4,58 @@ module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
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/Rails/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(remove_range(node))
93
- end
94
-
95
- # @param [RuboCop::AST::Node] node
96
- # @return [Parser::Source::Range]
97
- def remove_range(node)
98
- if node.left_sibling
99
- node.source_range.with(
100
- begin_pos: node.left_sibling.source_range.end_pos
101
- )
102
- elsif node.right_sibling
103
- node.source_range.with(
104
- end_pos: node.right_sibling.source_range.begin_pos
105
- )
106
- end
107
- end
108
-
109
- # @param [RuboCop::AST::PairNode] node
110
- # @return [RuboCop::AST::Node]
111
- def detect_removable_node(node)
112
- if node.parent.pairs.size == 1
113
- node.parent
114
- else
115
- node
116
- end
117
- end
118
-
119
- # @return [String]
120
- def file_path
121
- processed_source.file_path
122
- end
123
-
124
- # @param [RuboCop::AST::PairNode] node
125
- # @return [Boolean]
126
- def inferred_type?(node)
127
- inferred_type_from_file_path.inspect == node.value.source
128
- end
129
-
130
- # @return [Symbol, nil]
131
- def inferred_type_from_file_path
132
- inferences.find do |prefix, type|
133
- break type.to_sym if file_path.include?("spec/#{prefix}/")
134
- end
135
- end
136
-
137
- # @return [Hash]
138
- def inferences
139
- cop_config['Inferences'] || {}
140
- end
141
- end
7
+ # @!parse
8
+ # # Identifies redundant spec type.
9
+ # #
10
+ # # After setting up rspec-rails, you will have enabled
11
+ # # `config.infer_spec_type_from_file_location!` by default in
12
+ # # spec/rails_helper.rb. This cop works in conjunction with
13
+ # # this config.
14
+ # # If you disable this config, disable this cop as well.
15
+ # #
16
+ # # @safety
17
+ # # This cop is marked as unsafe because
18
+ # # `config.infer_spec_type_from_file_location!` may not be enabled.
19
+ # #
20
+ # # @example
21
+ # # # bad
22
+ # # # spec/models/user_spec.rb
23
+ # # RSpec.describe User, type: :model do
24
+ # # end
25
+ # #
26
+ # # # good
27
+ # # # spec/models/user_spec.rb
28
+ # # RSpec.describe User do
29
+ # # end
30
+ # #
31
+ # # # good
32
+ # # # spec/models/user_spec.rb
33
+ # # RSpec.describe User, type: :common do
34
+ # # end
35
+ # #
36
+ # # @example `Inferences` configuration
37
+ # # # .rubocop.yml
38
+ # # # RSpec/Rails/InferredSpecType:
39
+ # # # Inferences:
40
+ # # # services: service
41
+ # #
42
+ # # # bad
43
+ # # # spec/services/user_spec.rb
44
+ # # RSpec.describe User, type: :service do
45
+ # # end
46
+ # #
47
+ # # # good
48
+ # # # spec/services/user_spec.rb
49
+ # # RSpec.describe User do
50
+ # # end
51
+ # #
52
+ # # # good
53
+ # # # spec/services/user_spec.rb
54
+ # # RSpec.describe User, type: :common do
55
+ # # end
56
+ # #
57
+ # class InferredSpecType < RuboCop::Cop::RSpecRails::Base; end
58
+ InferredSpecType = ::RuboCop::Cop::RSpecRails::InferredSpecType
142
59
  end
143
60
  end
144
61
  end