rubocop-rspec 2.27.1 → 2.28.0

Sign up to get free protection for your applications and to get access to all the features.
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