rubocop-rspec 1.27.0 → 1.28.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +1 -1
- data/config/default.yml +15 -10
- data/lib/rubocop/cop/rspec/describe_method.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_example_group.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +2 -4
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +1 -3
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +1 -3
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +1 -3
- data/lib/rubocop/cop/rspec/example_without_description.rb +3 -4
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +8 -23
- data/lib/rubocop/cop/rspec/expect_output.rb +0 -2
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +146 -0
- data/lib/rubocop/cop/rspec/instance_spy.rb +0 -2
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/leading_subject.rb +1 -6
- data/lib/rubocop/cop/rspec/let_before_examples.rb +0 -2
- data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +35 -0
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +4 -4
- data/lib/rubocop/cop/rspec/nested_groups.rb +1 -1
- data/lib/rubocop/cop/rspec/pending.rb +1 -1
- data/lib/rubocop/cop/rspec/receive_never.rb +43 -0
- data/lib/rubocop/cop/rspec/scattered_let.rb +0 -2
- data/lib/rubocop/cop/rspec/shared_context.rb +3 -3
- data/lib/rubocop/cop/rspec/void_expect.rb +1 -1
- data/lib/rubocop/cop/rspec_cops.rb +4 -3
- data/lib/rubocop/rspec/align_let_brace.rb +1 -3
- data/lib/rubocop/rspec/blank_line_separation.rb +6 -0
- data/lib/rubocop/rspec/example_group.rb +0 -7
- data/lib/rubocop/rspec/language/node_pattern.rb +6 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- data/rubocop-rspec.gemspec +2 -2
- data/spec/project/project_requires_spec.rb +13 -3
- data/spec/rubocop/cop/rspec/before_after_all_spec.rb +2 -2
- data/spec/rubocop/cop/rspec/empty_line_after_example_group_spec.rb +15 -0
- data/spec/rubocop/cop/rspec/factory_bot/attribute_defined_statically_spec.rb +156 -0
- data/spec/rubocop/cop/rspec/let_before_examples_spec.rb +0 -5
- data/spec/rubocop/cop/rspec/missing_example_group_argument_spec.rb +55 -0
- data/spec/rubocop/cop/rspec/overwriting_setup_spec.rb +0 -5
- data/spec/rubocop/cop/rspec/receive_never_spec.rb +45 -0
- data/spec/rubocop/cop/rspec/scattered_let_spec.rb +0 -5
- data/spec/shared/smoke_test_examples.rb +25 -0
- data/spec/smoke_tests/empty_spec.rb +0 -0
- data/spec/smoke_tests/factory_bot_spec.rb +11 -0
- data/spec/smoke_tests/no_tests_spec.rb +4 -0
- data/spec/smoke_tests/weird_rspec_spec.rb +233 -0
- data/spec/spec_helper.rb +4 -0
- metadata +24 -11
- data/lib/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically.rb +0 -93
- data/lib/rubocop/cop/rspec/factory_bot/static_attribute_defined_dynamically.rb +0 -81
- data/spec/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically_spec.rb +0 -139
- data/spec/rubocop/cop/rspec/factory_bot/static_attribute_defined_dynamically_spec.rb +0 -107
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6138f067fde5bf88b21e56895a967a55e8bc9357dfd16d0044fd2777c5cbadc7
|
4
|
+
data.tar.gz: 64d630cc6a9f3d1413a8155486f002a1d524f9750ebf2c18d5c5bc485c21e438
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57246fef93f5061741c542a5710c16c905ff086da1d06974473e8b6ad54a6c84e26c4d79f7f538a92bca7d53ceb4c20e9eace2d65536922168e4ca227bb5a152
|
7
|
+
data.tar.gz: 6940142c7e889246bab48ccd06dc35784731181b774fc047ba9359f5e5b5975b5b10cee3a2ac970e11142ed1ae9dfc004e88e30cba5470945088a23cd7506b8d
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,15 @@
|
|
2
2
|
|
3
3
|
## Master (Unreleased)
|
4
4
|
|
5
|
+
## 1.28.0 (2018-08-14)
|
6
|
+
|
7
|
+
* Add `RSpec/ReceiveNever` cop enforcing usage of `not_to receive` instead of `never` matcher. ([@Darhazer][])
|
8
|
+
* Fix false positive in `RSpec/EmptyLineAfterExampleGroup` cop when example is inside `if`. ([@Darhazer][])
|
9
|
+
* Add `RSpec/MissingExampleGroupArgument` to enforce first argument for an example group. ([@geniou][])
|
10
|
+
* Drop support for ruby `2.1`. ([@bquorning][])
|
11
|
+
* Add `FactoryBot/AttributeDefinedStatically` cop to help FactoryBot users with the deprecation of static attributes. ([@composerinteralia][], [@seanpdoyle][])
|
12
|
+
* Remove `FactoryBot/DynamicAttributeDefinedStatically` and `FactoryBot/StaticAttributeDefinedDynamically` cops. ([@composerinteralia][])
|
13
|
+
|
5
14
|
## 1.27.0 (2018-06-14)
|
6
15
|
|
7
16
|
* `RSpec/LeadingSubject` now enforces subject to be before any examples, hooks or let declarations. ([@Darhazer][])
|
@@ -351,3 +360,5 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
|
|
351
360
|
[@abrom]: https://github.com/abrom
|
352
361
|
[@patrickomatic]: https://github.com/patrickomatic
|
353
362
|
[@tdeo]: https://github.com/tdeo
|
363
|
+
[@composerinteralia]: https://github.com/composerinteralia
|
364
|
+
[@seanpdoyle]: https://github.com/seanpdoyle
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
[![Maintainability](https://api.codeclimate.com/v1/badges/8ffaabf633c968c22bdd/maintainability)](https://codeclimate.com/github/rubocop-hq/rubocop-rspec/maintainability)
|
8
8
|
|
9
9
|
RSpec-specific analysis for your projects, as an extension to
|
10
|
-
[RuboCop](https://github.com/
|
10
|
+
[RuboCop](https://github.com/rubocop-hq/rubocop).
|
11
11
|
|
12
12
|
## Installation
|
13
13
|
|
data/config/default.yml
CHANGED
@@ -262,6 +262,11 @@ RSpec/MessageSpies:
|
|
262
262
|
- receive
|
263
263
|
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageSpies
|
264
264
|
|
265
|
+
RSpec/MissingExampleGroupArgument:
|
266
|
+
Description: Checks that the first argument to an example group is not empty.
|
267
|
+
Enabled: true
|
268
|
+
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExampleGroupArgument
|
269
|
+
|
265
270
|
RSpec/MultipleDescribes:
|
266
271
|
Description: Checks for multiple top level describes.
|
267
272
|
Enabled: true
|
@@ -314,6 +319,11 @@ RSpec/ReceiveCounts:
|
|
314
319
|
Description: Check for `once` and `twice` receive counts matchers usage.
|
315
320
|
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveCounts
|
316
321
|
|
322
|
+
RSpec/ReceiveNever:
|
323
|
+
Enabled: true
|
324
|
+
Description: Prefer `not_to receive(...)` over `receive(...).never`.
|
325
|
+
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveNever
|
326
|
+
|
317
327
|
RSpec/RepeatedDescription:
|
318
328
|
Enabled: true
|
319
329
|
Description: Check for repeated description strings in example groups.
|
@@ -395,6 +405,11 @@ Capybara/FeatureMethods:
|
|
395
405
|
EnabledMethods: []
|
396
406
|
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/FeatureMethods
|
397
407
|
|
408
|
+
FactoryBot/AttributeDefinedStatically:
|
409
|
+
Description: Always declare attribute values as blocks.
|
410
|
+
Enabled: true
|
411
|
+
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/AttributeDefinedStatically
|
412
|
+
|
398
413
|
FactoryBot/CreateList:
|
399
414
|
Description: Checks for create_list usage.
|
400
415
|
Enabled: true
|
@@ -404,16 +419,6 @@ FactoryBot/CreateList:
|
|
404
419
|
- n_times
|
405
420
|
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/CreateList
|
406
421
|
|
407
|
-
FactoryBot/DynamicAttributeDefinedStatically:
|
408
|
-
Description: Prefer declaring dynamic attribute values in a block.
|
409
|
-
Enabled: true
|
410
|
-
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/DynamicAttributeDefinedStatically
|
411
|
-
|
412
|
-
FactoryBot/StaticAttributeDefinedDynamically:
|
413
|
-
Description: Prefer declaring static attribute values without a block.
|
414
|
-
Enabled: true
|
415
|
-
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/StaticAttributeDefinedDynamically
|
416
|
-
|
417
422
|
Rails/HttpStatus:
|
418
423
|
Description: Enforces use of symbolic or numeric value to describe HTTP status.
|
419
424
|
Enabled: true
|
@@ -27,7 +27,7 @@ module RuboCop
|
|
27
27
|
|
28
28
|
def on_top_level_describe(_node, (_, second_arg))
|
29
29
|
return unless second_arg && second_arg.str_type?
|
30
|
-
return if METHOD_STRING_MATCHER =~
|
30
|
+
return if METHOD_STRING_MATCHER =~ second_arg.str_content
|
31
31
|
|
32
32
|
add_offense(second_arg, location: :expression)
|
33
33
|
end
|
@@ -28,11 +28,9 @@ module RuboCop
|
|
28
28
|
|
29
29
|
MSG = 'Add an empty line after `%<example_group>s`.'.freeze
|
30
30
|
|
31
|
-
def_node_matcher :example_group, ExampleGroups::ALL.block_pattern
|
32
|
-
|
33
31
|
def on_block(node)
|
34
|
-
return unless example_group(node)
|
35
|
-
return if
|
32
|
+
return unless example_group?(node)
|
33
|
+
return if last_child?(node)
|
36
34
|
|
37
35
|
missing_separating_line(node) do |location|
|
38
36
|
add_offense(
|
@@ -21,15 +21,13 @@ module RuboCop
|
|
21
21
|
|
22
22
|
MSG = 'Add an empty line after the last `let` block.'.freeze
|
23
23
|
|
24
|
-
def_node_matcher :let?, Helpers::ALL.block_pattern
|
25
|
-
|
26
24
|
def on_block(node)
|
27
25
|
return unless example_group_with_body?(node)
|
28
26
|
|
29
27
|
latest_let = node.body.child_nodes.select { |child| let?(child) }.last
|
30
28
|
|
31
29
|
return if latest_let.nil?
|
32
|
-
return if
|
30
|
+
return if last_child?(latest_let)
|
33
31
|
|
34
32
|
missing_separating_line(latest_let) do |location|
|
35
33
|
add_offense(latest_let, location: location)
|
@@ -38,11 +38,9 @@ module RuboCop
|
|
38
38
|
|
39
39
|
MSG = 'Add an empty line after `%<hook>s`.'.freeze
|
40
40
|
|
41
|
-
def_node_matcher :hook?, Hooks::ALL.block_pattern
|
42
|
-
|
43
41
|
def on_block(node)
|
44
42
|
return unless hook?(node)
|
45
|
-
return if
|
43
|
+
return if last_child?(node)
|
46
44
|
|
47
45
|
missing_separating_line(node) do |location|
|
48
46
|
add_offense(
|
@@ -19,11 +19,9 @@ module RuboCop
|
|
19
19
|
|
20
20
|
MSG = 'Add empty line after `subject`.'.freeze
|
21
21
|
|
22
|
-
def_node_matcher :subject?, Subject::ALL.block_pattern
|
23
|
-
|
24
22
|
def on_block(node)
|
25
23
|
return unless subject?(node) && !in_spec_block?(node)
|
26
|
-
return if
|
24
|
+
return if last_child?(node)
|
27
25
|
|
28
26
|
missing_separating_line(node) do |location|
|
29
27
|
add_offense(node, location: location, message: MSG)
|
@@ -54,15 +54,14 @@ module RuboCop
|
|
54
54
|
'have auto-generated description.'.freeze
|
55
55
|
MSG_ADD_DESCRIPTION = 'Add a description.'.freeze
|
56
56
|
|
57
|
-
def_node_matcher :example?, Examples::ALL.send_pattern
|
58
57
|
def_node_matcher :example_description, '(send nil? _ $(str $_))'
|
59
58
|
|
60
|
-
def
|
59
|
+
def on_block(node)
|
61
60
|
return unless example?(node)
|
62
61
|
|
63
|
-
check_example_without_description(node)
|
62
|
+
check_example_without_description(node.send_node)
|
64
63
|
|
65
|
-
example_description(node) do |message_node, message|
|
64
|
+
example_description(node.send_node) do |message_node, message|
|
66
65
|
return unless message.to_s.empty?
|
67
66
|
|
68
67
|
add_offense(message_node, message: MSG_DEFAULT_ARGUMENT)
|
@@ -22,38 +22,23 @@ module RuboCop
|
|
22
22
|
# end
|
23
23
|
class ExpectInHook < Cop
|
24
24
|
MSG = 'Do not use `%<expect>s` in `%<hook>s` hook'.freeze
|
25
|
-
HOOKS = Hooks::ALL.node_pattern_union.freeze
|
26
25
|
|
27
|
-
|
28
|
-
(block (send _ $#{HOOKS} ...) _ $!nil?)
|
29
|
-
PATTERN
|
30
|
-
|
31
|
-
def_node_search :expect, <<-PATTERN
|
32
|
-
{
|
33
|
-
#{Expectations::ALL.send_pattern}
|
34
|
-
#{Expectations::ALL.block_pattern}
|
35
|
-
}
|
36
|
-
PATTERN
|
26
|
+
def_node_search :expectation, Expectations::ALL.send_pattern
|
37
27
|
|
38
28
|
def on_block(node)
|
39
|
-
hook(node)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
29
|
+
return unless hook?(node)
|
30
|
+
return if node.body.nil?
|
31
|
+
|
32
|
+
expectation(node.body) do |expect|
|
33
|
+
add_offense(expect, location: :selector,
|
34
|
+
message: message(expect, node))
|
45
35
|
end
|
46
36
|
end
|
47
37
|
|
48
38
|
private
|
49
39
|
|
50
40
|
def message(expect, hook)
|
51
|
-
format(MSG, expect: expect.method_name, hook: hook)
|
52
|
-
end
|
53
|
-
|
54
|
-
def send_node(node)
|
55
|
-
return node if node.send_type?
|
56
|
-
node.children.first
|
41
|
+
format(MSG, expect: expect.method_name, hook: hook.method_name)
|
57
42
|
end
|
58
43
|
end
|
59
44
|
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
module FactoryBot
|
7
|
+
# Always declare attribute values as blocks.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# kind [:active, :rejected].sample
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# kind { [:active, :rejected].sample }
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# closed_at 1.day.from_now
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# closed_at { 1.day.from_now }
|
21
|
+
#
|
22
|
+
# # bad
|
23
|
+
# count 1
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# count { 1 }
|
27
|
+
class AttributeDefinedStatically < Cop
|
28
|
+
MSG = 'Use a block to declare attribute values.'.freeze
|
29
|
+
|
30
|
+
ATTRIBUTE_DEFINING_METHODS = %i[factory trait transient ignore].freeze
|
31
|
+
|
32
|
+
UNPROXIED_METHODS = %i[
|
33
|
+
__send__
|
34
|
+
__id__
|
35
|
+
nil?
|
36
|
+
send
|
37
|
+
object_id
|
38
|
+
extend
|
39
|
+
instance_eval
|
40
|
+
initialize
|
41
|
+
block_given?
|
42
|
+
raise
|
43
|
+
caller
|
44
|
+
method
|
45
|
+
].freeze
|
46
|
+
|
47
|
+
DEFINITION_PROXY_METHODS = %i[
|
48
|
+
add_attribute
|
49
|
+
after
|
50
|
+
association
|
51
|
+
before
|
52
|
+
callback
|
53
|
+
ignore
|
54
|
+
initialize_with
|
55
|
+
sequence
|
56
|
+
skip_create
|
57
|
+
to_create
|
58
|
+
].freeze
|
59
|
+
|
60
|
+
RESERVED_METHODS =
|
61
|
+
DEFINITION_PROXY_METHODS +
|
62
|
+
UNPROXIED_METHODS +
|
63
|
+
ATTRIBUTE_DEFINING_METHODS
|
64
|
+
|
65
|
+
def_node_matcher :value_matcher, <<-PATTERN
|
66
|
+
(send nil? !#reserved_method? $...)
|
67
|
+
PATTERN
|
68
|
+
|
69
|
+
def_node_search :factory_attributes, <<-PATTERN
|
70
|
+
(block (send nil? #attribute_defining_method? ...) _ { (begin $...) $(send ...) } )
|
71
|
+
PATTERN
|
72
|
+
|
73
|
+
def on_block(node)
|
74
|
+
factory_attributes(node).to_a.flatten.each do |attribute|
|
75
|
+
next if proc?(attribute) || association?(attribute)
|
76
|
+
add_offense(attribute, location: :expression)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def autocorrect(node)
|
81
|
+
if node.parenthesized?
|
82
|
+
autocorrect_replacing_parens(node)
|
83
|
+
else
|
84
|
+
autocorrect_without_parens(node)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def proc?(attribute)
|
91
|
+
value_matcher(attribute).to_a.all?(&:block_pass_type?)
|
92
|
+
end
|
93
|
+
|
94
|
+
def association?(attribute)
|
95
|
+
argument = attribute.first_argument
|
96
|
+
argument.hash_type? && factory_key?(argument)
|
97
|
+
end
|
98
|
+
|
99
|
+
def factory_key?(hash_node)
|
100
|
+
hash_node.keys.any? { |key| key.value == :factory }
|
101
|
+
end
|
102
|
+
|
103
|
+
def autocorrect_replacing_parens(node)
|
104
|
+
left_braces, right_braces = braces(node)
|
105
|
+
|
106
|
+
lambda do |corrector|
|
107
|
+
corrector.replace(node.location.begin, ' ' + left_braces)
|
108
|
+
corrector.replace(node.location.end, right_braces)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def autocorrect_without_parens(node)
|
113
|
+
left_braces, right_braces = braces(node)
|
114
|
+
|
115
|
+
lambda do |corrector|
|
116
|
+
argument = node.first_argument
|
117
|
+
expression = argument.location.expression
|
118
|
+
corrector.insert_before(expression, left_braces)
|
119
|
+
corrector.insert_after(expression, right_braces)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def braces(node)
|
124
|
+
if value_hash_without_braces?(node.first_argument)
|
125
|
+
['{ { ', ' } }']
|
126
|
+
else
|
127
|
+
['{ ', ' }']
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def value_hash_without_braces?(node)
|
132
|
+
node.hash_type? && !node.braces?
|
133
|
+
end
|
134
|
+
|
135
|
+
def reserved_method?(method_name)
|
136
|
+
RESERVED_METHODS.include?(method_name)
|
137
|
+
end
|
138
|
+
|
139
|
+
def attribute_defining_method?(method_name)
|
140
|
+
ATTRIBUTE_DEFINING_METHODS.include?(method_name)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -32,7 +32,7 @@ module RuboCop
|
|
32
32
|
def on_block(node)
|
33
33
|
each?(node) do |arg, body|
|
34
34
|
if single_expectation?(body, arg) || only_expectations?(body, arg)
|
35
|
-
add_offense(node.
|
35
|
+
add_offense(node.send_node, location: :expression)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -37,11 +37,6 @@ module RuboCop
|
|
37
37
|
MSG = 'Declare `subject` above any other `%<offending>s` ' \
|
38
38
|
'declarations.'.freeze
|
39
39
|
|
40
|
-
def_node_matcher :subject?, Subject::ALL.block_pattern
|
41
|
-
def_node_matcher :let?, Helpers::ALL.block_pattern
|
42
|
-
def_node_matcher :hook?, Hooks::ALL.block_pattern
|
43
|
-
def_node_matcher :example?, Examples::ALL.block_pattern
|
44
|
-
|
45
40
|
def on_block(node)
|
46
41
|
return unless subject?(node) && !in_spec_block?(node)
|
47
42
|
|
@@ -88,7 +83,7 @@ module RuboCop
|
|
88
83
|
|
89
84
|
def in_spec_block?(node)
|
90
85
|
node.each_ancestor(:block).any? do |ancestor|
|
91
|
-
|
86
|
+
example?(ancestor)
|
92
87
|
end
|
93
88
|
end
|
94
89
|
end
|