rubocop-rspec 2.11.1 → 2.13.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 +4 -4
- data/CHANGELOG.md +125 -81
- data/config/default.yml +59 -6
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +8 -9
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +8 -9
- data/lib/rubocop/cop/rspec/any_instance.rb +1 -0
- data/lib/rubocop/cop/rspec/around_block.rb +26 -3
- data/lib/rubocop/cop/rspec/be.rb +0 -1
- data/lib/rubocop/cop/rspec/be_eq.rb +0 -1
- data/lib/rubocop/cop/rspec/be_eql.rb +0 -1
- data/lib/rubocop/cop/rspec/before_after_all.rb +1 -0
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +9 -3
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +2 -1
- data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +86 -0
- data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +158 -0
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +0 -1
- data/lib/rubocop/cop/rspec/change_by_zero.rb +67 -7
- data/lib/rubocop/cop/rspec/class_check.rb +101 -0
- data/lib/rubocop/cop/rspec/context_method.rb +2 -1
- data/lib/rubocop/cop/rspec/context_wording.rb +49 -18
- data/lib/rubocop/cop/rspec/describe_class.rb +1 -1
- data/lib/rubocop/cop/rspec/describe_method.rb +1 -0
- data/lib/rubocop/cop/rspec/described_class.rb +5 -15
- data/lib/rubocop/cop/rspec/dialect.rb +1 -0
- data/lib/rubocop/cop/rspec/empty_example_group.rb +19 -4
- data/lib/rubocop/cop/rspec/empty_hook.rb +4 -5
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +4 -9
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +2 -1
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +32 -2
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +2 -1
- data/lib/rubocop/cop/rspec/example_length.rb +3 -2
- data/lib/rubocop/cop/rspec/example_without_description.rb +3 -2
- data/lib/rubocop/cop/rspec/example_wording.rb +2 -1
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +1 -0
- data/lib/rubocop/cop/rspec/expect_actual.rb +5 -0
- data/lib/rubocop/cop/rspec/expect_change.rb +9 -9
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +4 -1
- data/lib/rubocop/cop/rspec/expect_output.rb +1 -0
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +2 -1
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +50 -13
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +1 -0
- data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +1 -1
- data/lib/rubocop/cop/rspec/file_path.rb +8 -4
- data/lib/rubocop/cop/rspec/focus.rb +20 -4
- data/lib/rubocop/cop/rspec/hook_argument.rb +10 -5
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +10 -9
- data/lib/rubocop/cop/rspec/identical_equality_assertion.rb +0 -1
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +1 -0
- data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -3
- data/lib/rubocop/cop/rspec/instance_spy.rb +1 -1
- data/lib/rubocop/cop/rspec/instance_variable.rb +0 -1
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +3 -2
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +16 -0
- data/lib/rubocop/cop/rspec/leading_subject.rb +15 -15
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
- data/lib/rubocop/cop/rspec/let_before_examples.rb +7 -8
- data/lib/rubocop/cop/rspec/let_setup.rb +4 -4
- data/lib/rubocop/cop/rspec/message_chain.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/missing_example_group_argument.rb +2 -1
- data/lib/rubocop/cop/rspec/mixin/css_selector.rb +99 -0
- data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +13 -4
- data/lib/rubocop/cop/rspec/mixin/namespace.rb +23 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -0
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +19 -3
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +1 -3
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +17 -2
- data/lib/rubocop/cop/rspec/named_subject.rb +2 -1
- data/lib/rubocop/cop/rspec/nested_groups.rb +45 -25
- data/lib/rubocop/cop/rspec/no_expectation_example.rb +64 -0
- data/lib/rubocop/cop/rspec/not_to_not.rb +13 -1
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +2 -1
- data/lib/rubocop/cop/rspec/pending.rb +1 -0
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +2 -1
- data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +1 -2
- data/lib/rubocop/cop/rspec/rails/have_http_status.rb +47 -0
- data/lib/rubocop/cop/rspec/receive_counts.rb +14 -15
- data/lib/rubocop/cop/rspec/receive_never.rb +4 -5
- data/lib/rubocop/cop/rspec/repeated_description.rb +25 -26
- data/lib/rubocop/cop/rspec/repeated_example.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +28 -29
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +28 -29
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +32 -33
- data/lib/rubocop/cop/rspec/return_from_stub.rb +12 -12
- data/lib/rubocop/cop/rspec/scattered_let.rb +1 -5
- data/lib/rubocop/cop/rspec/scattered_setup.rb +2 -2
- data/lib/rubocop/cop/rspec/shared_context.rb +1 -1
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +0 -1
- data/lib/rubocop/cop/rspec/subject_declaration.rb +0 -1
- data/lib/rubocop/cop/rspec/subject_stub.rb +2 -2
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +15 -15
- data/lib/rubocop/cop/rspec/variable_definition.rb +1 -0
- data/lib/rubocop/cop/rspec/variable_name.rb +6 -7
- data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -0
- data/lib/rubocop/cop/rspec/void_expect.rb +2 -1
- data/lib/rubocop/cop/rspec/yield.rb +3 -2
- data/lib/rubocop/cop/rspec_cops.rb +5 -0
- data/lib/rubocop/rspec/config_formatter.rb +14 -3
- data/lib/rubocop/rspec/inject.rb +1 -3
- data/lib/rubocop/rspec/language/node_pattern.rb +4 -0
- data/lib/rubocop/rspec/language.rb +6 -1
- data/lib/rubocop/rspec/node.rb +1 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop/rspec/wording.rb +2 -2
- data/lib/rubocop/rspec.rb +14 -0
- data/lib/rubocop-rspec.rb +3 -0
- metadata +12 -88
@@ -6,7 +6,6 @@ module RuboCop
|
|
6
6
|
# Checks if an example group does not include any tests.
|
7
7
|
#
|
8
8
|
# @example usage
|
9
|
-
#
|
10
9
|
# # bad
|
11
10
|
# describe Bacon do
|
12
11
|
# let(:bacon) { Bacon.new(chunkiness) }
|
@@ -35,7 +34,12 @@ module RuboCop
|
|
35
34
|
# describe Bacon do
|
36
35
|
# pending 'will add tests later'
|
37
36
|
# end
|
37
|
+
#
|
38
38
|
class EmptyExampleGroup < Base
|
39
|
+
extend AutoCorrector
|
40
|
+
|
41
|
+
include RangeHelp
|
42
|
+
|
39
43
|
MSG = 'Empty example group detected.'
|
40
44
|
|
41
45
|
# @!method example_group_body(node)
|
@@ -119,7 +123,7 @@ module RuboCop
|
|
119
123
|
# describe { it { i_run_as_well } }
|
120
124
|
#
|
121
125
|
# @example source that does not match
|
122
|
-
# before { it { whatever here
|
126
|
+
# before { it { whatever here won't run anyway } }
|
123
127
|
#
|
124
128
|
# @param node [RuboCop::AST::Node]
|
125
129
|
# @return [Array<RuboCop::AST::Node>] matching nodes
|
@@ -130,12 +134,16 @@ module RuboCop
|
|
130
134
|
}
|
131
135
|
PATTERN
|
132
136
|
|
133
|
-
def on_block(node)
|
137
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
134
138
|
return if node.each_ancestor(:def, :defs).any?
|
135
139
|
return if node.each_ancestor(:block).any? { |block| example?(block) }
|
136
140
|
|
137
141
|
example_group_body(node) do |body|
|
138
|
-
|
142
|
+
next unless offensive?(body)
|
143
|
+
|
144
|
+
add_offense(node.send_node) do |corrector|
|
145
|
+
corrector.remove(removed_range(node))
|
146
|
+
end
|
139
147
|
end
|
140
148
|
end
|
141
149
|
|
@@ -163,6 +171,13 @@ module RuboCop
|
|
163
171
|
def examples_in_branches?(condition_node)
|
164
172
|
condition_node.branches.any? { |branch| examples?(branch) }
|
165
173
|
end
|
174
|
+
|
175
|
+
def removed_range(node)
|
176
|
+
range_by_whole_lines(
|
177
|
+
node.location.expression,
|
178
|
+
include_final_newline: true
|
179
|
+
)
|
180
|
+
end
|
166
181
|
end
|
167
182
|
end
|
168
183
|
end
|
@@ -22,6 +22,7 @@ module RuboCop
|
|
22
22
|
# create_feed
|
23
23
|
# end
|
24
24
|
# after(:all) { cleanup_feed }
|
25
|
+
#
|
25
26
|
class EmptyHook < Base
|
26
27
|
extend AutoCorrector
|
27
28
|
include RuboCop::Cop::RangeHelp
|
@@ -33,14 +34,12 @@ module RuboCop
|
|
33
34
|
(block $#{send_pattern('#Hooks.all')} _ nil?)
|
34
35
|
PATTERN
|
35
36
|
|
36
|
-
def on_block(node)
|
37
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
37
38
|
empty_hook?(node) do |hook|
|
38
39
|
add_offense(hook) do |corrector|
|
39
|
-
|
40
|
-
|
41
|
-
side: :left
|
40
|
+
corrector.remove(
|
41
|
+
range_with_surrounding_space(node.loc.expression, side: :left)
|
42
42
|
)
|
43
|
-
corrector.remove(range)
|
44
43
|
end
|
45
44
|
end
|
46
45
|
end
|
@@ -30,7 +30,6 @@ module RuboCop
|
|
30
30
|
# end
|
31
31
|
#
|
32
32
|
# @example with AllowConsecutiveOneLiners configuration
|
33
|
-
#
|
34
33
|
# # rubocop.yml
|
35
34
|
# # RSpec/EmptyLineAfterExample:
|
36
35
|
# # AllowConsecutiveOneLiners: false
|
@@ -47,7 +46,7 @@ module RuboCop
|
|
47
46
|
|
48
47
|
MSG = 'Add an empty line after `%<example>s`.'
|
49
48
|
|
50
|
-
def on_block(node)
|
49
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
51
50
|
return unless example?(node)
|
52
51
|
return if allowed_one_liner?(node)
|
53
52
|
|
@@ -65,19 +64,15 @@ module RuboCop
|
|
65
64
|
end
|
66
65
|
|
67
66
|
def consecutive_one_liner?(node)
|
68
|
-
node.
|
67
|
+
node.single_line? && next_one_line_example?(node)
|
69
68
|
end
|
70
69
|
|
71
70
|
def next_one_line_example?(node)
|
72
|
-
next_sibling =
|
71
|
+
next_sibling = node.right_sibling
|
73
72
|
return unless next_sibling
|
74
73
|
return unless example?(next_sibling)
|
75
74
|
|
76
|
-
next_sibling.
|
77
|
-
end
|
78
|
-
|
79
|
-
def next_sibling(node)
|
80
|
-
node.parent.children[node.sibling_index + 1]
|
75
|
+
next_sibling.single_line?
|
81
76
|
end
|
82
77
|
end
|
83
78
|
end
|
@@ -29,7 +29,7 @@ module RuboCop
|
|
29
29
|
|
30
30
|
MSG = 'Add an empty line after `%<example_group>s`.'
|
31
31
|
|
32
|
-
def on_block(node)
|
32
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
33
33
|
return unless example_group?(node)
|
34
34
|
|
35
35
|
missing_separating_line_offense(node) do |method|
|
@@ -16,13 +16,14 @@ module RuboCop
|
|
16
16
|
# let(:something) { other }
|
17
17
|
#
|
18
18
|
# it { does_something }
|
19
|
+
#
|
19
20
|
class EmptyLineAfterFinalLet < Base
|
20
21
|
extend AutoCorrector
|
21
22
|
include EmptyLineSeparation
|
22
23
|
|
23
24
|
MSG = 'Add an empty line after the last `%<let>s`.'
|
24
25
|
|
25
|
-
def on_block(node)
|
26
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
26
27
|
return unless example_group_with_body?(node)
|
27
28
|
|
28
29
|
final_let = node.body.child_nodes.reverse.find { |child| let?(child) }
|
@@ -5,6 +5,9 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Checks if there is an empty line after hook blocks.
|
7
7
|
#
|
8
|
+
# `AllowConsecutiveOneLiners` configures whether adjacent
|
9
|
+
# one-line definitions are considered an offense.
|
10
|
+
#
|
8
11
|
# @example
|
9
12
|
# # bad
|
10
13
|
# before { do_something }
|
@@ -19,11 +22,23 @@ module RuboCop
|
|
19
22
|
# it { does_something }
|
20
23
|
#
|
21
24
|
# # good
|
22
|
-
#
|
25
|
+
# after { do_something }
|
23
26
|
#
|
24
27
|
# it { does_something }
|
25
28
|
#
|
26
|
-
# #
|
29
|
+
# # fair - it's ok to have non-separated one-liners hooks
|
30
|
+
# around { |test| test.run }
|
31
|
+
# after { do_something }
|
32
|
+
#
|
33
|
+
# it { does_something }
|
34
|
+
#
|
35
|
+
# @example with AllowConsecutiveOneLiners configuration
|
36
|
+
# # rubocop.yml
|
37
|
+
# # RSpec/EmptyLineAfterHook:
|
38
|
+
# # AllowConsecutiveOneLiners: false
|
39
|
+
#
|
40
|
+
# # bad
|
41
|
+
# around { |test| test.run }
|
27
42
|
# after { do_something }
|
28
43
|
#
|
29
44
|
# it { does_something }
|
@@ -31,21 +46,36 @@ module RuboCop
|
|
31
46
|
# # good
|
32
47
|
# around { |test| test.run }
|
33
48
|
#
|
49
|
+
# after { do_something }
|
50
|
+
#
|
34
51
|
# it { does_something }
|
35
52
|
#
|
36
53
|
class EmptyLineAfterHook < Base
|
37
54
|
extend AutoCorrector
|
55
|
+
include ConfigurableEnforcedStyle
|
38
56
|
include EmptyLineSeparation
|
39
57
|
|
40
58
|
MSG = 'Add an empty line after `%<hook>s`.'
|
41
59
|
|
42
60
|
def on_block(node)
|
43
61
|
return unless hook?(node)
|
62
|
+
return if cop_config['AllowConsecutiveOneLiners'] &&
|
63
|
+
chained_single_line_hooks?(node)
|
44
64
|
|
45
65
|
missing_separating_line_offense(node) do |method|
|
46
66
|
format(MSG, hook: method)
|
47
67
|
end
|
48
68
|
end
|
69
|
+
|
70
|
+
alias on_numblock on_block
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def chained_single_line_hooks?(node)
|
75
|
+
next_node = node.right_sibling
|
76
|
+
|
77
|
+
hook?(next_node) && node.single_line? && next_node.single_line?
|
78
|
+
end
|
49
79
|
end
|
50
80
|
end
|
51
81
|
end
|
@@ -14,6 +14,7 @@ module RuboCop
|
|
14
14
|
# subject(:obj) { described_class }
|
15
15
|
#
|
16
16
|
# let(:foo) { bar }
|
17
|
+
#
|
17
18
|
class EmptyLineAfterSubject < Base
|
18
19
|
extend AutoCorrector
|
19
20
|
include EmptyLineSeparation
|
@@ -21,7 +22,7 @@ module RuboCop
|
|
21
22
|
|
22
23
|
MSG = 'Add an empty line after `%<subject>s`.'
|
23
24
|
|
24
|
-
def on_block(node)
|
25
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
25
26
|
return unless subject?(node)
|
26
27
|
return unless inside_example_group?(node)
|
27
28
|
|
@@ -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
|
@@ -47,12 +47,13 @@ module RuboCop
|
|
47
47
|
# content.
|
48
48
|
# HEREDOC
|
49
49
|
# end # 5 points
|
50
|
+
#
|
50
51
|
class ExampleLength < Base
|
51
52
|
include CodeLength
|
52
53
|
|
53
54
|
LABEL = 'Example'
|
54
55
|
|
55
|
-
def on_block(node)
|
56
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
56
57
|
return unless example?(node)
|
57
58
|
|
58
59
|
check_code_length(node)
|
@@ -14,7 +14,7 @@ module RuboCop
|
|
14
14
|
#
|
15
15
|
# This cop can be configured using the `EnforcedStyle` option
|
16
16
|
#
|
17
|
-
# @example `EnforcedStyle: always_allow`
|
17
|
+
# @example `EnforcedStyle: always_allow` (default)
|
18
18
|
# # bad
|
19
19
|
# it('') { is_expected.to be_good }
|
20
20
|
# it '' do
|
@@ -47,6 +47,7 @@ module RuboCop
|
|
47
47
|
# result = service.call
|
48
48
|
# expect(result).to be(true)
|
49
49
|
# end
|
50
|
+
#
|
50
51
|
class ExampleWithoutDescription < Base
|
51
52
|
include ConfigurableEnforcedStyle
|
52
53
|
|
@@ -57,7 +58,7 @@ module RuboCop
|
|
57
58
|
# @!method example_description(node)
|
58
59
|
def_node_matcher :example_description, '(send nil? _ $(str $_))'
|
59
60
|
|
60
|
-
def on_block(node)
|
61
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
61
62
|
return unless example?(node)
|
62
63
|
|
63
64
|
check_example_without_description(node.send_node)
|
@@ -29,6 +29,7 @@ module RuboCop
|
|
29
29
|
# # good
|
30
30
|
# it 'does things' do
|
31
31
|
# end
|
32
|
+
#
|
32
33
|
class ExampleWording < Base
|
33
34
|
extend AutoCorrector
|
34
35
|
|
@@ -46,7 +47,7 @@ module RuboCop
|
|
46
47
|
} ...) ...)
|
47
48
|
PATTERN
|
48
49
|
|
49
|
-
def on_block(node)
|
50
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
50
51
|
it_description(node) do |description_node, message|
|
51
52
|
if message.match?(SHOULD_PREFIX)
|
52
53
|
add_wording_offense(description_node, MSG_SHOULD)
|
@@ -5,6 +5,8 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Checks for `expect(...)` calls containing literal values.
|
7
7
|
#
|
8
|
+
# Autocorrection is performed when the expected is not a literal.
|
9
|
+
#
|
8
10
|
# @example
|
9
11
|
# # bad
|
10
12
|
# expect(5).to eq(price)
|
@@ -16,6 +18,9 @@ module RuboCop
|
|
16
18
|
# expect(pattern).to eq(/foo/)
|
17
19
|
# expect(name).to eq("John")
|
18
20
|
#
|
21
|
+
# # bad (not supported autocorrection)
|
22
|
+
# expect(false).to eq(true)
|
23
|
+
#
|
19
24
|
class ExpectActual < Base
|
20
25
|
extend AutoCorrector
|
21
26
|
|
@@ -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
|
@@ -69,7 +69,7 @@ module RuboCop
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
def on_block(node)
|
72
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
73
73
|
return unless style == :method_call
|
74
74
|
|
75
75
|
expect_change_with_block(node) do |receiver, message|
|
@@ -20,13 +20,14 @@ module RuboCop
|
|
20
20
|
# it do
|
21
21
|
# expect(something).to eq 'foo'
|
22
22
|
# end
|
23
|
+
#
|
23
24
|
class ExpectInHook < Base
|
24
25
|
MSG = 'Do not use `%<expect>s` in `%<hook>s` hook'
|
25
26
|
|
26
27
|
# @!method expectation(node)
|
27
28
|
def_node_search :expectation, send_pattern('#Expectations.all')
|
28
29
|
|
29
|
-
def on_block(node)
|
30
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
30
31
|
return unless hook?(node)
|
31
32
|
return if node.body.nil?
|
32
33
|
|
@@ -36,6 +37,8 @@ module RuboCop
|
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
40
|
+
alias on_numblock on_block
|
41
|
+
|
39
42
|
private
|
40
43
|
|
41
44
|
def message(expect, hook)
|
@@ -24,6 +24,7 @@ module RuboCop
|
|
24
24
|
#
|
25
25
|
# # good
|
26
26
|
# count { 1 }
|
27
|
+
#
|
27
28
|
class AttributeDefinedStatically < Base
|
28
29
|
extend AutoCorrector
|
29
30
|
|
@@ -39,7 +40,7 @@ module RuboCop
|
|
39
40
|
(block (send _ #attribute_defining_method? ...) _ { (begin $...) $(send ...) } )
|
40
41
|
PATTERN
|
41
42
|
|
42
|
-
def on_block(node)
|
43
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
43
44
|
attributes = factory_attributes(node) || []
|
44
45
|
attributes = [attributes] unless attributes.is_a?(Array) # rubocop:disable Style/ArrayCoercion, Lint/RedundantCopDisableDirective
|
45
46
|
|
@@ -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
|
@@ -24,6 +30,7 @@ module RuboCop
|
|
24
30
|
#
|
25
31
|
# # good
|
26
32
|
# 3.times { create :user }
|
33
|
+
#
|
27
34
|
class CreateList < Base
|
28
35
|
extend AutoCorrector
|
29
36
|
include ConfigurableEnforcedStyle
|
@@ -33,15 +40,31 @@ module RuboCop
|
|
33
40
|
MSG_N_TIMES = 'Prefer %<number>s.times.'
|
34
41
|
RESTRICT_ON_SEND = %i[create_list].freeze
|
35
42
|
|
36
|
-
# @!method
|
37
|
-
def_node_matcher :
|
43
|
+
# @!method array_new_or_n_times_block?(node)
|
44
|
+
def_node_matcher :array_new_or_n_times_block?, <<-PATTERN
|
38
45
|
(block
|
39
|
-
|
40
|
-
|
46
|
+
{
|
47
|
+
(send (const {nil? | cbase} :Array) :new (int _)) |
|
48
|
+
(send (int _) :times)
|
49
|
+
}
|
41
50
|
...
|
42
51
|
)
|
43
52
|
PATTERN
|
44
53
|
|
54
|
+
# @!method block_with_arg_and_used?(node)
|
55
|
+
def_node_matcher :block_with_arg_and_used?, <<-PATTERN
|
56
|
+
(block
|
57
|
+
_
|
58
|
+
(args (arg _value))
|
59
|
+
`_value
|
60
|
+
)
|
61
|
+
PATTERN
|
62
|
+
|
63
|
+
# @!method arguments_include_method_call?(node)
|
64
|
+
def_node_matcher :arguments_include_method_call?, <<-PATTERN
|
65
|
+
(send ${nil? #factory_bot?} :create (sym $_) `$(send ...))
|
66
|
+
PATTERN
|
67
|
+
|
45
68
|
# @!method factory_call(node)
|
46
69
|
def_node_matcher :factory_call, <<-PATTERN
|
47
70
|
(send ${nil? #factory_bot?} :create (sym $_) $...)
|
@@ -52,9 +75,13 @@ module RuboCop
|
|
52
75
|
(send {nil? #factory_bot?} :create_list (sym _) (int $_) ...)
|
53
76
|
PATTERN
|
54
77
|
|
55
|
-
def on_block(node)
|
78
|
+
def on_block(node) # rubocop:todo InternalAffairs/NumblockHandler
|
56
79
|
return unless style == :create_list
|
57
|
-
|
80
|
+
|
81
|
+
return unless array_new_or_n_times_block?(node)
|
82
|
+
return if block_with_arg_and_used?(node)
|
83
|
+
return unless node.body
|
84
|
+
return if arguments_include_method_call?(node.body)
|
58
85
|
return unless contains_only_factory?(node.body)
|
59
86
|
|
60
87
|
add_offense(node.send_node, message: MSG_CREATE_LIST) do |corrector|
|
@@ -160,7 +187,7 @@ module RuboCop
|
|
160
187
|
|
161
188
|
def call_with_block_replacement(node)
|
162
189
|
block = node.body
|
163
|
-
arguments = build_arguments(block, node
|
190
|
+
arguments = build_arguments(block, count_from(node))
|
164
191
|
replacement = format_receiver(block.receiver)
|
165
192
|
replacement += format_method_call(block, 'create_list', arguments)
|
166
193
|
replacement += format_block(block)
|
@@ -180,7 +207,7 @@ module RuboCop
|
|
180
207
|
block = node.body
|
181
208
|
factory, *options = *block.arguments
|
182
209
|
|
183
|
-
arguments = "#{factory.source}, #{node
|
210
|
+
arguments = "#{factory.source}, #{count_from(node)}"
|
184
211
|
options = build_options_string(options)
|
185
212
|
arguments += ", #{options}" unless options.empty?
|
186
213
|
|
@@ -189,11 +216,21 @@ module RuboCop
|
|
189
216
|
replacement
|
190
217
|
end
|
191
218
|
|
219
|
+
def count_from(node)
|
220
|
+
count_node =
|
221
|
+
if node.receiver.int_type?
|
222
|
+
node.receiver
|
223
|
+
else
|
224
|
+
node.send_node.first_argument
|
225
|
+
end
|
226
|
+
count_node.source
|
227
|
+
end
|
228
|
+
|
192
229
|
def format_block(node)
|
193
230
|
if node.body.begin_type?
|
194
231
|
format_multiline_block(node)
|
195
232
|
else
|
196
|
-
|
233
|
+
format_singleline_block(node)
|
197
234
|
end
|
198
235
|
end
|
199
236
|
|
@@ -205,7 +242,7 @@ module RuboCop
|
|
205
242
|
"#{indent_end}end"
|
206
243
|
end
|
207
244
|
|
208
|
-
def
|
245
|
+
def format_singleline_block(node)
|
209
246
|
" { #{node.arguments.source} #{node.body.source} }"
|
210
247
|
end
|
211
248
|
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
|
#
|
@@ -58,6 +58,7 @@ module RuboCop
|
|
58
58
|
#
|
59
59
|
class FilePath < Base
|
60
60
|
include TopLevelGroup
|
61
|
+
include Namespace
|
61
62
|
|
62
63
|
MSG = 'Spec path should end with `%<suffix>s`.'
|
63
64
|
|
@@ -101,7 +102,7 @@ module RuboCop
|
|
101
102
|
|
102
103
|
def pattern_for(example_group, method_name)
|
103
104
|
if spec_suffix_only? || !example_group.const_type?
|
104
|
-
return pattern_for_spec_suffix_only
|
105
|
+
return pattern_for_spec_suffix_only
|
105
106
|
end
|
106
107
|
|
107
108
|
[
|
@@ -111,19 +112,22 @@ module RuboCop
|
|
111
112
|
].join
|
112
113
|
end
|
113
114
|
|
114
|
-
def pattern_for_spec_suffix_only
|
115
|
+
def pattern_for_spec_suffix_only
|
115
116
|
'.*_spec\.rb'
|
116
117
|
end
|
117
118
|
|
118
119
|
def name_pattern(method_name)
|
119
120
|
return unless method_name&.str_type?
|
121
|
+
return if ignore_methods?
|
120
122
|
|
121
|
-
".*#{method_name.str_content.gsub(/\W/, '')}"
|
123
|
+
".*#{method_name.str_content.gsub(/\s/, '_').gsub(/\W/, '')}"
|
122
124
|
end
|
123
125
|
|
124
126
|
def expected_path(constant)
|
127
|
+
constants = namespace(constant) + constant.const_name.split('::')
|
128
|
+
|
125
129
|
File.join(
|
126
|
-
|
130
|
+
constants.map do |name|
|
127
131
|
custom_transform.fetch(name) { camel_to_snake_case(name) }
|
128
132
|
end
|
129
133
|
)
|
@@ -5,6 +5,8 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Checks if examples are focused.
|
7
7
|
#
|
8
|
+
# This cop does not support autocorrection in some cases.
|
9
|
+
#
|
8
10
|
# @example
|
9
11
|
# # bad
|
10
12
|
# describe MyClass, focus: true do
|
@@ -19,6 +21,22 @@ module RuboCop
|
|
19
21
|
# # good
|
20
22
|
# describe MyClass do
|
21
23
|
# end
|
24
|
+
#
|
25
|
+
# # bad
|
26
|
+
# fdescribe 'test' do; end
|
27
|
+
#
|
28
|
+
# # good
|
29
|
+
# describe 'test' do; end
|
30
|
+
#
|
31
|
+
# # bad
|
32
|
+
# fdescribe 'test' do; end
|
33
|
+
#
|
34
|
+
# # good
|
35
|
+
# describe 'test' do; end
|
36
|
+
#
|
37
|
+
# # bad (does not support autocorrection)
|
38
|
+
# focus 'test' do; end
|
39
|
+
#
|
22
40
|
class Focus < Base
|
23
41
|
extend AutoCorrector
|
24
42
|
include RangeHelp
|
@@ -69,10 +87,8 @@ module RuboCop
|
|
69
87
|
end
|
70
88
|
|
71
89
|
def with_surrounding(focus)
|
72
|
-
range_with_space =
|
73
|
-
|
74
|
-
side: :left
|
75
|
-
)
|
90
|
+
range_with_space =
|
91
|
+
range_with_surrounding_space(focus.loc.expression, side: :left)
|
76
92
|
|
77
93
|
range_with_surrounding_comma(range_with_space, :left)
|
78
94
|
end
|