rubocop-rspec 2.11.1 → 2.12.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 +20 -0
- data/config/default.yml +15 -0
- data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +77 -0
- data/lib/rubocop/cop/rspec/change_by_zero.rb +8 -3
- data/lib/rubocop/cop/rspec/described_class.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_hook.rb +2 -4
- data/lib/rubocop/cop/rspec/example_length.rb +1 -1
- data/lib/rubocop/cop/rspec/example_without_description.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_actual.rb +2 -0
- data/lib/rubocop/cop/rspec/expect_change.rb +8 -8
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +32 -9
- data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +1 -1
- data/lib/rubocop/cop/rspec/file_path.rb +2 -1
- data/lib/rubocop/cop/rspec/focus.rb +2 -4
- data/lib/rubocop/cop/rspec/hook_argument.rb +3 -3
- data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +2 -2
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
- data/lib/rubocop/cop/rspec/message_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/message_spies.rb +7 -1
- data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +13 -4
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +20 -0
- data/lib/rubocop/cop/rspec/not_to_not.rb +14 -1
- data/lib/rubocop/cop/rspec/rails/have_http_status.rb +47 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +11 -11
- data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/yield.rb +1 -1
- data/lib/rubocop/cop/rspec_cops.rb +2 -0
- data/lib/rubocop/rspec/node.rb +1 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a543787a865d7e8062e0b746c1b5dd641214bd17b17d25182a58b4a646c4bfb6
|
4
|
+
data.tar.gz: 57ddde6cfed19062929b00c729dd7403955bf3c92a8b5354cb3704bd7382c5ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4a03f557f7f2e7a7a24f01e14db9e7599ce08c7921618d877b807fd37ef065d97556b428931c4129b19ef1d791e072828fd0f3705797d1ec98c69eb7f25cf45
|
7
|
+
data.tar.gz: 0d7bacaeb99c2c60594d507158434e8740c5b2a96032f73db4247cd16ff0963b46de2313d3bf76cf6bb0ed3d33b1751f663062e00cef095ab4310642a4e5153c
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,21 @@
|
|
2
2
|
|
3
3
|
## Master (Unreleased)
|
4
4
|
|
5
|
+
## 2.12.1 (2022-07-03)
|
6
|
+
|
7
|
+
* Fix a false positive for `RSpec/Capybara/SpecificMatcher`. ([@ydah][])
|
8
|
+
|
9
|
+
## 2.12.0 (2022-07-02)
|
10
|
+
|
11
|
+
* Fix incorrect path suggested by `RSpec/FilePath` cop when second argument contains spaces. ([@tejasbubane][])
|
12
|
+
* Fix autocorrect for EmptyLineSeparation. ([@johnny-miyake][])
|
13
|
+
* Add new `RSpec/Capybara/SpecificMatcher` cop. ([@ydah][])
|
14
|
+
* Fixed false offense detection in `FactoryBot/CreateList` when a n.times block is including method calls in the factory create arguments. ([@ngouy][])
|
15
|
+
* Fix error in `RSpec/RSpec/FactoryBot/CreateList` cop for empty block. ([@tejasbubane][])
|
16
|
+
* Update `RSpec/MultipleExpectations` cop documentation with examples of aggregate_failures use. ([@edgibbs][])
|
17
|
+
* Declare autocorrect as unsafe for `RSpec/VerifiedDoubleReference`. ([@Drowze][])
|
18
|
+
* Add new `RSpec/Rails/HaveHttpStatus` cop. ([@akiomik][])
|
19
|
+
|
5
20
|
## 2.11.1 (2022-05-18)
|
6
21
|
|
7
22
|
* Fix a regression in `RSpec/ExpectChange` flagging chained method calls. ([@pirj][])
|
@@ -694,3 +709,8 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
|
|
694
709
|
[@t3h2mas]: https://github.com/t3h2mas
|
695
710
|
[@M-Yamashita01]: https://github.com/M-Yamashita01
|
696
711
|
[@luke-hill]: https://github.com/luke-hill
|
712
|
+
[@johnny-miyake]: https://github.com/johnny-miyake
|
713
|
+
[@ngouy]: https://github.com/ngouy
|
714
|
+
[@edgibbs]: https://github.com/edgibbs
|
715
|
+
[@Drowze]: https://github.com/Drowze
|
716
|
+
[@akiomik]: https://github.com/akiomik
|
data/config/default.yml
CHANGED
@@ -783,11 +783,13 @@ RSpec/VariableName:
|
|
783
783
|
RSpec/VerifiedDoubleReference:
|
784
784
|
Description: Checks for consistent verified double reference style.
|
785
785
|
Enabled: pending
|
786
|
+
SafeAutoCorrect: false
|
786
787
|
EnforcedStyle: constant
|
787
788
|
SupportedStyles:
|
788
789
|
- constant
|
789
790
|
- string
|
790
791
|
VersionAdded: 2.10.0
|
792
|
+
VersionChanged: '2.12'
|
791
793
|
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubleReference
|
792
794
|
|
793
795
|
RSpec/VerifiedDoubles:
|
@@ -832,6 +834,12 @@ RSpec/Capybara/FeatureMethods:
|
|
832
834
|
VersionChanged: '2.0'
|
833
835
|
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/FeatureMethods
|
834
836
|
|
837
|
+
RSpec/Capybara/SpecificMatcher:
|
838
|
+
Description: Checks for there is a more specific matcher offered by Capybara.
|
839
|
+
Enabled: pending
|
840
|
+
VersionAdded: '2.12'
|
841
|
+
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/SpecificMatcher
|
842
|
+
|
835
843
|
RSpec/Capybara/VisibilityMatcher:
|
836
844
|
Description: Checks for boolean visibility in Capybara finders.
|
837
845
|
Enabled: true
|
@@ -901,6 +909,13 @@ RSpec/Rails/AvoidSetupHook:
|
|
901
909
|
VersionAdded: '2.4'
|
902
910
|
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/AvoidSetupHook
|
903
911
|
|
912
|
+
RSpec/Rails/HaveHttpStatus:
|
913
|
+
Description: Checks that tests use `have_http_status` instead of equality matchers.
|
914
|
+
Enabled: pending
|
915
|
+
SafeAutoCorrect: false
|
916
|
+
VersionAdded: '2.12'
|
917
|
+
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HaveHttpStatus
|
918
|
+
|
904
919
|
RSpec/Rails/HttpStatus:
|
905
920
|
Description: Enforces use of symbolic or numeric value to describe HTTP status.
|
906
921
|
Enabled: true
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
module Capybara
|
7
|
+
# Checks for there is a more specific matcher offered by Capybara.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# expect(page).to have_selector('button')
|
13
|
+
# expect(page).to have_no_selector('button.cls')
|
14
|
+
# expect(page).to have_css('button')
|
15
|
+
# expect(page).to have_no_css('a.cls', exact_text: 'foo')
|
16
|
+
# expect(page).to have_css('table.cls')
|
17
|
+
# expect(page).to have_css('select')
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# expect(page).to have_button
|
21
|
+
# expect(page).to have_no_button(class: 'cls')
|
22
|
+
# expect(page).to have_button
|
23
|
+
# expect(page).to have_no_link('foo', class: 'cls')
|
24
|
+
# expect(page).to have_table(class: 'cls')
|
25
|
+
# expect(page).to have_select
|
26
|
+
#
|
27
|
+
class SpecificMatcher < Base
|
28
|
+
MSG = 'Prefer `%<good_matcher>s` over `%<bad_matcher>s`.'
|
29
|
+
RESTRICT_ON_SEND = %i[have_selector have_no_selector have_css
|
30
|
+
have_no_css].freeze
|
31
|
+
SPECIFIC_MATCHER = {
|
32
|
+
'button' => 'button',
|
33
|
+
'a' => 'link',
|
34
|
+
'table' => 'table',
|
35
|
+
'select' => 'select'
|
36
|
+
}.freeze
|
37
|
+
|
38
|
+
# @!method first_argument(node)
|
39
|
+
def_node_matcher :first_argument, <<-PATTERN
|
40
|
+
(send nil? _ (str $_) ... )
|
41
|
+
PATTERN
|
42
|
+
|
43
|
+
def on_send(node)
|
44
|
+
return unless (arg = first_argument(node))
|
45
|
+
return unless (matcher = specific_matcher(arg))
|
46
|
+
return if acceptable_pattern?(arg)
|
47
|
+
|
48
|
+
add_offense(node, message: message(node, matcher))
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def specific_matcher(arg)
|
54
|
+
splitted_arg = arg[/^\w+/, 0]
|
55
|
+
SPECIFIC_MATCHER[splitted_arg]
|
56
|
+
end
|
57
|
+
|
58
|
+
def acceptable_pattern?(arg)
|
59
|
+
arg.match?(/\[.+=\w+\]/) || arg.match?(/[ >,+]/)
|
60
|
+
end
|
61
|
+
|
62
|
+
def message(node, matcher)
|
63
|
+
format(MSG,
|
64
|
+
good_matcher: good_matcher(node, matcher),
|
65
|
+
bad_matcher: node.method_name)
|
66
|
+
end
|
67
|
+
|
68
|
+
def good_matcher(node, matcher)
|
69
|
+
node.method_name
|
70
|
+
.to_s
|
71
|
+
.gsub(/selector|css/, matcher.to_s)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -9,6 +9,8 @@ module RuboCop
|
|
9
9
|
# # bad
|
10
10
|
# expect { run }.to change(Foo, :bar).by(0)
|
11
11
|
# expect { run }.to change { Foo.bar }.by(0)
|
12
|
+
#
|
13
|
+
# # bad - compound expectations
|
12
14
|
# expect { run }
|
13
15
|
# .to change(Foo, :bar).by(0)
|
14
16
|
# .and change(Foo, :baz).by(0)
|
@@ -19,6 +21,9 @@ module RuboCop
|
|
19
21
|
# # good
|
20
22
|
# expect { run }.not_to change(Foo, :bar)
|
21
23
|
# expect { run }.not_to change { Foo.bar }
|
24
|
+
#
|
25
|
+
# # good - compound expectations
|
26
|
+
# define_negated_matcher :not_change, :change
|
22
27
|
# expect { run }
|
23
28
|
# .to not_change(Foo, :bar)
|
24
29
|
# .and not_change(Foo, :baz)
|
@@ -52,17 +57,17 @@ module RuboCop
|
|
52
57
|
|
53
58
|
def on_send(node)
|
54
59
|
expect_change_with_arguments(node.parent) do
|
55
|
-
|
60
|
+
check_offense(node.parent)
|
56
61
|
end
|
57
62
|
|
58
63
|
expect_change_with_block(node.parent.parent) do
|
59
|
-
|
64
|
+
check_offense(node.parent.parent)
|
60
65
|
end
|
61
66
|
end
|
62
67
|
|
63
68
|
private
|
64
69
|
|
65
|
-
def
|
70
|
+
def check_offense(node)
|
66
71
|
expression = node.loc.expression
|
67
72
|
if compound_expectations?(node)
|
68
73
|
add_offense(expression, message: MSG_COMPOUND)
|
@@ -11,7 +11,7 @@ module RuboCop
|
|
11
11
|
# This cop can be configured using the `EnforcedStyle` and `SkipBlocks`
|
12
12
|
# options.
|
13
13
|
#
|
14
|
-
# @example `EnforcedStyle: described_class`
|
14
|
+
# @example `EnforcedStyle: described_class` (default)
|
15
15
|
# # bad
|
16
16
|
# describe MyClass do
|
17
17
|
# subject { MyClass.do_something }
|
@@ -36,11 +36,9 @@ module RuboCop
|
|
36
36
|
def on_block(node)
|
37
37
|
empty_hook?(node) do |hook|
|
38
38
|
add_offense(hook) do |corrector|
|
39
|
-
|
40
|
-
|
41
|
-
side: :left
|
39
|
+
corrector.remove(
|
40
|
+
range_with_surrounding_space(node.loc.expression, side: :left)
|
42
41
|
)
|
43
|
-
corrector.remove(range)
|
44
42
|
end
|
45
43
|
end
|
46
44
|
end
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
# Checks for long examples.
|
7
7
|
#
|
8
8
|
# A long example is usually more difficult to understand. Consider
|
9
|
-
# extracting out some
|
9
|
+
# extracting out some behavior, e.g. with a `let` block, or a helper
|
10
10
|
# method.
|
11
11
|
#
|
12
12
|
# @example
|
@@ -10,14 +10,7 @@ module RuboCop
|
|
10
10
|
#
|
11
11
|
# This cop can be configured using the `EnforcedStyle` option.
|
12
12
|
#
|
13
|
-
# @example `EnforcedStyle:
|
14
|
-
# # bad
|
15
|
-
# expect { run }.to change(Foo, :bar)
|
16
|
-
#
|
17
|
-
# # good
|
18
|
-
# expect { run }.to change { Foo.bar }
|
19
|
-
#
|
20
|
-
# @example `EnforcedStyle: method_call`
|
13
|
+
# @example `EnforcedStyle: method_call` (default)
|
21
14
|
# # bad
|
22
15
|
# expect { run }.to change { Foo.bar }
|
23
16
|
# expect { run }.to change { foo.baz }
|
@@ -29,6 +22,13 @@ module RuboCop
|
|
29
22
|
# expect { run }.to change { Foo.bar(:count) }
|
30
23
|
# expect { run }.to change { user.reload.name }
|
31
24
|
#
|
25
|
+
# @example `EnforcedStyle: block`
|
26
|
+
# # bad
|
27
|
+
# expect { run }.to change(Foo, :bar)
|
28
|
+
#
|
29
|
+
# # good
|
30
|
+
# expect { run }.to change { Foo.bar }
|
31
|
+
#
|
32
32
|
class ExpectChange < Base
|
33
33
|
extend AutoCorrector
|
34
34
|
include ConfigurableEnforcedStyle
|
@@ -8,15 +8,21 @@ module RuboCop
|
|
8
8
|
#
|
9
9
|
# This cop can be configured using the `EnforcedStyle` option
|
10
10
|
#
|
11
|
-
# @example `EnforcedStyle: create_list`
|
11
|
+
# @example `EnforcedStyle: create_list` (default)
|
12
12
|
# # bad
|
13
13
|
# 3.times { create :user }
|
14
14
|
#
|
15
15
|
# # good
|
16
16
|
# create_list :user, 3
|
17
17
|
#
|
18
|
-
# #
|
19
|
-
# 3.times {
|
18
|
+
# # bad
|
19
|
+
# 3.times { create :user, age: 18 }
|
20
|
+
#
|
21
|
+
# # good - index is used to alter the created models attributes
|
22
|
+
# 3.times { |n| create :user, age: n }
|
23
|
+
#
|
24
|
+
# # good - contains a method call, may return different values
|
25
|
+
# 3.times { create :user, age: rand }
|
20
26
|
#
|
21
27
|
# @example `EnforcedStyle: n_times`
|
22
28
|
# # bad
|
@@ -33,15 +39,28 @@ module RuboCop
|
|
33
39
|
MSG_N_TIMES = 'Prefer %<number>s.times.'
|
34
40
|
RESTRICT_ON_SEND = %i[create_list].freeze
|
35
41
|
|
36
|
-
# @!method
|
37
|
-
def_node_matcher :
|
42
|
+
# @!method n_times_block?(node)
|
43
|
+
def_node_matcher :n_times_block?, <<-PATTERN
|
38
44
|
(block
|
39
45
|
(send (int _) :times)
|
40
|
-
(args)
|
41
46
|
...
|
42
47
|
)
|
43
48
|
PATTERN
|
44
49
|
|
50
|
+
# @!method n_times_block_with_arg_and_used?(node)
|
51
|
+
def_node_matcher :n_times_block_with_arg_and_used?, <<-PATTERN
|
52
|
+
(block
|
53
|
+
(send (int _) :times)
|
54
|
+
(args (arg _value))
|
55
|
+
`_value
|
56
|
+
)
|
57
|
+
PATTERN
|
58
|
+
|
59
|
+
# @!method arguments_include_method_call?(node)
|
60
|
+
def_node_matcher :arguments_include_method_call?, <<-PATTERN
|
61
|
+
(send ${nil? #factory_bot?} :create (sym $_) `$(send ...))
|
62
|
+
PATTERN
|
63
|
+
|
45
64
|
# @!method factory_call(node)
|
46
65
|
def_node_matcher :factory_call, <<-PATTERN
|
47
66
|
(send ${nil? #factory_bot?} :create (sym $_) $...)
|
@@ -54,7 +73,11 @@ module RuboCop
|
|
54
73
|
|
55
74
|
def on_block(node)
|
56
75
|
return unless style == :create_list
|
57
|
-
|
76
|
+
|
77
|
+
return unless n_times_block?(node)
|
78
|
+
return if n_times_block_with_arg_and_used?(node)
|
79
|
+
return unless node.body
|
80
|
+
return if arguments_include_method_call?(node.body)
|
58
81
|
return unless contains_only_factory?(node.body)
|
59
82
|
|
60
83
|
add_offense(node.send_node, message: MSG_CREATE_LIST) do |corrector|
|
@@ -193,7 +216,7 @@ module RuboCop
|
|
193
216
|
if node.body.begin_type?
|
194
217
|
format_multiline_block(node)
|
195
218
|
else
|
196
|
-
|
219
|
+
format_singleline_block(node)
|
197
220
|
end
|
198
221
|
end
|
199
222
|
|
@@ -205,7 +228,7 @@ module RuboCop
|
|
205
228
|
"#{indent_end}end"
|
206
229
|
end
|
207
230
|
|
208
|
-
def
|
231
|
+
def format_singleline_block(node)
|
209
232
|
" { #{node.arguments.source} #{node.body.source} }"
|
210
233
|
end
|
211
234
|
end
|
@@ -7,7 +7,7 @@ module RuboCop
|
|
7
7
|
# Use shorthands from `FactoryBot::Syntax::Methods` in your specs.
|
8
8
|
#
|
9
9
|
# @safety
|
10
|
-
# The
|
10
|
+
# The autocorrection is marked as unsafe because the cop
|
11
11
|
# cannot verify whether you already include
|
12
12
|
# `FactoryBot::Syntax::Methods` in your test suite.
|
13
13
|
#
|
@@ -117,8 +117,9 @@ module RuboCop
|
|
117
117
|
|
118
118
|
def name_pattern(method_name)
|
119
119
|
return unless method_name&.str_type?
|
120
|
+
return if ignore_methods?
|
120
121
|
|
121
|
-
".*#{method_name.str_content.gsub(/\W/, '')}"
|
122
|
+
".*#{method_name.str_content.gsub(/\s/, '_').gsub(/\W/, '')}"
|
122
123
|
end
|
123
124
|
|
124
125
|
def expected_path(constant)
|
@@ -69,10 +69,8 @@ module RuboCop
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def with_surrounding(focus)
|
72
|
-
range_with_space =
|
73
|
-
|
74
|
-
side: :left
|
75
|
-
)
|
72
|
+
range_with_space =
|
73
|
+
range_with_surrounding_space(focus.loc.expression, side: :left)
|
76
74
|
|
77
75
|
range_with_surrounding_comma(range_with_space, :left)
|
78
76
|
end
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
# styles: "implicit", "each", and "example." All styles have
|
11
11
|
# the same behavior.
|
12
12
|
#
|
13
|
-
# @example
|
13
|
+
# @example `EnforcedStyle: implicit` (default)
|
14
14
|
# # bad
|
15
15
|
# before(:each) do
|
16
16
|
# # ...
|
@@ -26,7 +26,7 @@ module RuboCop
|
|
26
26
|
# # ...
|
27
27
|
# end
|
28
28
|
#
|
29
|
-
# @example
|
29
|
+
# @example `EnforcedStyle: each`
|
30
30
|
# # bad
|
31
31
|
# before(:example) do
|
32
32
|
# # ...
|
@@ -42,7 +42,7 @@ module RuboCop
|
|
42
42
|
# # ...
|
43
43
|
# end
|
44
44
|
#
|
45
|
-
# @example
|
45
|
+
# @example `EnforcedStyle: example`
|
46
46
|
# # bad
|
47
47
|
# before(:each) do
|
48
48
|
# # ...
|
@@ -8,7 +8,7 @@ module RuboCop
|
|
8
8
|
# This cop can be configured using the `EnforcedStyle` option
|
9
9
|
# and supports the `--auto-gen-config` flag.
|
10
10
|
#
|
11
|
-
# @example `EnforcedStyle: is_expected`
|
11
|
+
# @example `EnforcedStyle: is_expected` (default)
|
12
12
|
#
|
13
13
|
# # bad
|
14
14
|
# it { should be_truthy }
|
@@ -5,14 +5,14 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Checks that only one `it_behaves_like` style is used.
|
7
7
|
#
|
8
|
-
# @example
|
8
|
+
# @example `EnforcedStyle: it_behaves_like` (default)
|
9
9
|
# # bad
|
10
10
|
# it_should_behave_like 'a foo'
|
11
11
|
#
|
12
12
|
# # good
|
13
13
|
# it_behaves_like 'a foo'
|
14
14
|
#
|
15
|
-
# @example
|
15
|
+
# @example `EnforcedStyle: it_should_behave_like`
|
16
16
|
# # bad
|
17
17
|
# it_behaves_like 'a foo'
|
18
18
|
#
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
#
|
11
11
|
# If several examples may define a `DummyClass`, instead of being a
|
12
12
|
# blank slate class as it will be in the first example, subsequent
|
13
|
-
# examples will be reopening it and modifying its
|
13
|
+
# examples will be reopening it and modifying its behavior in
|
14
14
|
# unpredictable ways.
|
15
15
|
# Even worse when a class that exists in the codebase is reopened.
|
16
16
|
#
|
@@ -8,7 +8,7 @@ module RuboCop
|
|
8
8
|
# This cop can be configured in your configuration using the
|
9
9
|
# `EnforcedStyle` option and supports `--auto-gen-config`.
|
10
10
|
#
|
11
|
-
# @example `EnforcedStyle: allow`
|
11
|
+
# @example `EnforcedStyle: allow` (default)
|
12
12
|
#
|
13
13
|
# # bad
|
14
14
|
# expect(foo).to receive(:bar)
|
@@ -8,21 +8,27 @@ module RuboCop
|
|
8
8
|
# This cop can be configured in your configuration using the
|
9
9
|
# `EnforcedStyle` option and supports `--auto-gen-config`.
|
10
10
|
#
|
11
|
-
# @example `EnforcedStyle: have_received`
|
11
|
+
# @example `EnforcedStyle: have_received` (default)
|
12
12
|
#
|
13
13
|
# # bad
|
14
14
|
# expect(foo).to receive(:bar)
|
15
|
+
# do_something
|
15
16
|
#
|
16
17
|
# # good
|
18
|
+
# allow(foo).to receive(:bar) # or use instance_spy
|
19
|
+
# do_something
|
17
20
|
# expect(foo).to have_received(:bar)
|
18
21
|
#
|
19
22
|
# @example `EnforcedStyle: receive`
|
20
23
|
#
|
21
24
|
# # bad
|
25
|
+
# allow(foo).to receive(:bar)
|
26
|
+
# do_something
|
22
27
|
# expect(foo).to have_received(:bar)
|
23
28
|
#
|
24
29
|
# # good
|
25
30
|
# expect(foo).to receive(:bar)
|
31
|
+
# do_something
|
26
32
|
#
|
27
33
|
class MessageSpies < Base
|
28
34
|
include ConfigurableEnforcedStyle
|
@@ -4,7 +4,10 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
6
|
# Helps determine the offending location if there is not an empty line
|
7
|
-
# following the node. Allows comments to follow directly after
|
7
|
+
# following the node. Allows comments to follow directly after
|
8
|
+
# in the following cases.
|
9
|
+
# - `rubocop:enable` directive
|
10
|
+
# - followed by empty line(s)
|
8
11
|
module EmptyLineSeparation
|
9
12
|
include FinalEndLocation
|
10
13
|
include RangeHelp
|
@@ -21,13 +24,19 @@ module RuboCop
|
|
21
24
|
end
|
22
25
|
|
23
26
|
def missing_separating_line(node)
|
24
|
-
line = final_end_location(node).line
|
27
|
+
line = final_end_line = final_end_location(node).line
|
25
28
|
|
26
|
-
|
29
|
+
while comment_line?(processed_source[line])
|
30
|
+
line += 1
|
31
|
+
comment = processed_source.comment_at_line(line)
|
32
|
+
if DirectiveComment.new(comment).enabled?
|
33
|
+
enable_directive_line = line
|
34
|
+
end
|
35
|
+
end
|
27
36
|
|
28
37
|
return if processed_source[line].blank?
|
29
38
|
|
30
|
-
yield offending_loc(
|
39
|
+
yield offending_loc(enable_directive_line || final_end_line)
|
31
40
|
end
|
32
41
|
|
33
42
|
def offending_loc(last_line)
|
@@ -31,6 +31,26 @@ module RuboCop
|
|
31
31
|
# end
|
32
32
|
# end
|
33
33
|
#
|
34
|
+
# @example `aggregate_failures: true` (default)
|
35
|
+
#
|
36
|
+
# # good - the cop ignores when RSpec aggregates failures
|
37
|
+
# describe UserCreator do
|
38
|
+
# it 'builds a user', :aggregate_failures do
|
39
|
+
# expect(user.name).to eq("John")
|
40
|
+
# expect(user.age).to eq(22)
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# @example `aggregate_failures: false`
|
45
|
+
#
|
46
|
+
# # Detected as an offense
|
47
|
+
# describe UserCreator do
|
48
|
+
# it 'builds a user', aggregate_failures: false do
|
49
|
+
# expect(user.name).to eq("John")
|
50
|
+
# expect(user.age).to eq(22)
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
34
54
|
# @example configuration
|
35
55
|
#
|
36
56
|
# # .rubocop.yml
|
@@ -5,7 +5,8 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Checks for consistent method usage for negating expectations.
|
7
7
|
#
|
8
|
-
# @example
|
8
|
+
# @example `EnforcedStyle: not_to` (default)
|
9
|
+
#
|
9
10
|
# # bad
|
10
11
|
# it '...' do
|
11
12
|
# expect(false).to_not be_true
|
@@ -15,6 +16,18 @@ module RuboCop
|
|
15
16
|
# it '...' do
|
16
17
|
# expect(false).not_to be_true
|
17
18
|
# end
|
19
|
+
#
|
20
|
+
# @example `EnforcedStyle: to_not`
|
21
|
+
#
|
22
|
+
# # bad
|
23
|
+
# it '...' do
|
24
|
+
# expect(false).not_to be_true
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # good
|
28
|
+
# it '...' do
|
29
|
+
# expect(false).to_not be_true
|
30
|
+
# end
|
18
31
|
class NotToNot < Base
|
19
32
|
extend AutoCorrector
|
20
33
|
include ConfigurableEnforcedStyle
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
module Rails
|
7
|
+
# Checks that tests use `have_http_status` instead of equality matchers.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# expect(response.status).to be(200)
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# expect(response).to have_http_status(200)
|
15
|
+
#
|
16
|
+
class HaveHttpStatus < Base
|
17
|
+
extend AutoCorrector
|
18
|
+
|
19
|
+
MSG =
|
20
|
+
'Prefer `expect(response).%<to>s have_http_status(%<status>i)` ' \
|
21
|
+
'over `expect(response.status).%<to>s %<match>s`.'
|
22
|
+
|
23
|
+
# @!method match_status(node)
|
24
|
+
def_node_matcher :match_status, <<-PATTERN
|
25
|
+
(send
|
26
|
+
(send nil? :expect
|
27
|
+
$(send (send nil? :response) :status)
|
28
|
+
)
|
29
|
+
$#Runners.all
|
30
|
+
$(send nil? {:be :eq :eql :equal} (int $_))
|
31
|
+
)
|
32
|
+
PATTERN
|
33
|
+
|
34
|
+
def on_send(node)
|
35
|
+
match_status(node) do |response_status, to, match, status|
|
36
|
+
message = format(MSG, to: to, match: match.source, status: status)
|
37
|
+
add_offense(node, message: message) do |corrector|
|
38
|
+
corrector.replace(response_status.source_range, 'response')
|
39
|
+
corrector.replace(match.loc.selector, 'have_http_status')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -11,6 +11,17 @@ module RuboCop
|
|
11
11
|
#
|
12
12
|
# This cop can be configured using the `EnforcedStyle` option
|
13
13
|
#
|
14
|
+
# @example `EnforcedStyle: and_return` (default)
|
15
|
+
# # bad
|
16
|
+
# allow(Foo).to receive(:bar) { "baz" }
|
17
|
+
# expect(Foo).to receive(:bar) { "baz" }
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# allow(Foo).to receive(:bar).and_return("baz")
|
21
|
+
# expect(Foo).to receive(:bar).and_return("baz")
|
22
|
+
# # also good as the returned value is dynamic
|
23
|
+
# allow(Foo).to receive(:bar) { bar.baz }
|
24
|
+
#
|
14
25
|
# @example `EnforcedStyle: block`
|
15
26
|
# # bad
|
16
27
|
# allow(Foo).to receive(:bar).and_return("baz")
|
@@ -22,17 +33,6 @@ module RuboCop
|
|
22
33
|
# # also good as the returned value is dynamic
|
23
34
|
# allow(Foo).to receive(:bar).and_return(bar.baz)
|
24
35
|
#
|
25
|
-
# @example `EnforcedStyle: and_return`
|
26
|
-
# # bad
|
27
|
-
# allow(Foo).to receive(:bar) { "baz" }
|
28
|
-
# expect(Foo).to receive(:bar) { "baz" }
|
29
|
-
#
|
30
|
-
# # good
|
31
|
-
# allow(Foo).to receive(:bar).and_return("baz")
|
32
|
-
# expect(Foo).to receive(:bar).and_return("baz")
|
33
|
-
# # also good as the returned value is dynamic
|
34
|
-
# allow(Foo).to receive(:bar) { bar.baz }
|
35
|
-
#
|
36
36
|
class ReturnFromStub < Base
|
37
37
|
extend AutoCorrector
|
38
38
|
include ConfigurableEnforcedStyle
|
@@ -35,7 +35,7 @@ module RuboCop
|
|
35
35
|
occurrences.each do |occurrence|
|
36
36
|
lines_except_current = lines - [occurrence.first_line]
|
37
37
|
message = format(MSG, hook_name: occurrences.first.method_name,
|
38
|
-
|
38
|
+
lines: lines_msg(lines_except_current))
|
39
39
|
add_offense(occurrence, message: message)
|
40
40
|
end
|
41
41
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative 'rspec/capybara/current_path_expectation'
|
4
4
|
require_relative 'rspec/capybara/feature_methods'
|
5
|
+
require_relative 'rspec/capybara/specific_matcher'
|
5
6
|
require_relative 'rspec/capybara/visibility_matcher'
|
6
7
|
|
7
8
|
require_relative 'rspec/factory_bot/attribute_defined_statically'
|
@@ -10,6 +11,7 @@ require_relative 'rspec/factory_bot/factory_class_name'
|
|
10
11
|
require_relative 'rspec/factory_bot/syntax_methods'
|
11
12
|
|
12
13
|
require_relative 'rspec/rails/avoid_setup_hook'
|
14
|
+
require_relative 'rspec/rails/have_http_status'
|
13
15
|
begin
|
14
16
|
require_relative 'rspec/rails/http_status'
|
15
17
|
rescue LoadError
|
data/lib/rubocop/rspec/node.rb
CHANGED
@@ -4,7 +4,7 @@ module RuboCop
|
|
4
4
|
module RSpec
|
5
5
|
# RuboCop RSpec specific extensions of RuboCop::AST::Node
|
6
6
|
module Node
|
7
|
-
# In various cops we want to regard const as literal
|
7
|
+
# In various cops we want to regard const as literal although it's not
|
8
8
|
# strictly literal.
|
9
9
|
def recursive_literal_or_const?
|
10
10
|
case type
|
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.
|
4
|
+
version: 2.12.1
|
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-
|
13
|
+
date: 2022-07-03 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rubocop
|
@@ -18,14 +18,14 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '1.
|
21
|
+
version: '1.31'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: '1.
|
28
|
+
version: '1.31'
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
30
|
name: rack
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
@@ -141,6 +141,7 @@ files:
|
|
141
141
|
- lib/rubocop/cop/rspec/before_after_all.rb
|
142
142
|
- lib/rubocop/cop/rspec/capybara/current_path_expectation.rb
|
143
143
|
- lib/rubocop/cop/rspec/capybara/feature_methods.rb
|
144
|
+
- lib/rubocop/cop/rspec/capybara/specific_matcher.rb
|
144
145
|
- lib/rubocop/cop/rspec/capybara/visibility_matcher.rb
|
145
146
|
- lib/rubocop/cop/rspec/change_by_zero.rb
|
146
147
|
- lib/rubocop/cop/rspec/context_method.rb
|
@@ -207,6 +208,7 @@ files:
|
|
207
208
|
- lib/rubocop/cop/rspec/pending.rb
|
208
209
|
- lib/rubocop/cop/rspec/predicate_matcher.rb
|
209
210
|
- lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb
|
211
|
+
- lib/rubocop/cop/rspec/rails/have_http_status.rb
|
210
212
|
- lib/rubocop/cop/rspec/rails/http_status.rb
|
211
213
|
- lib/rubocop/cop/rspec/receive_counts.rb
|
212
214
|
- lib/rubocop/cop/rspec/receive_never.rb
|