rubocop-rspec 1.27.0 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|
[](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
|