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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +1 -1
  4. data/config/default.yml +15 -10
  5. data/lib/rubocop/cop/rspec/describe_method.rb +1 -1
  6. data/lib/rubocop/cop/rspec/empty_example_group.rb +1 -1
  7. data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +2 -4
  8. data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +1 -3
  9. data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +1 -3
  10. data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +1 -3
  11. data/lib/rubocop/cop/rspec/example_without_description.rb +3 -4
  12. data/lib/rubocop/cop/rspec/expect_in_hook.rb +8 -23
  13. data/lib/rubocop/cop/rspec/expect_output.rb +0 -2
  14. data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +146 -0
  15. data/lib/rubocop/cop/rspec/instance_spy.rb +0 -2
  16. data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
  17. data/lib/rubocop/cop/rspec/leading_subject.rb +1 -6
  18. data/lib/rubocop/cop/rspec/let_before_examples.rb +0 -2
  19. data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +35 -0
  20. data/lib/rubocop/cop/rspec/multiple_expectations.rb +1 -1
  21. data/lib/rubocop/cop/rspec/multiple_subjects.rb +4 -4
  22. data/lib/rubocop/cop/rspec/nested_groups.rb +1 -1
  23. data/lib/rubocop/cop/rspec/pending.rb +1 -1
  24. data/lib/rubocop/cop/rspec/receive_never.rb +43 -0
  25. data/lib/rubocop/cop/rspec/scattered_let.rb +0 -2
  26. data/lib/rubocop/cop/rspec/shared_context.rb +3 -3
  27. data/lib/rubocop/cop/rspec/void_expect.rb +1 -1
  28. data/lib/rubocop/cop/rspec_cops.rb +4 -3
  29. data/lib/rubocop/rspec/align_let_brace.rb +1 -3
  30. data/lib/rubocop/rspec/blank_line_separation.rb +6 -0
  31. data/lib/rubocop/rspec/example_group.rb +0 -7
  32. data/lib/rubocop/rspec/language/node_pattern.rb +6 -0
  33. data/lib/rubocop/rspec/version.rb +1 -1
  34. data/rubocop-rspec.gemspec +2 -2
  35. data/spec/project/project_requires_spec.rb +13 -3
  36. data/spec/rubocop/cop/rspec/before_after_all_spec.rb +2 -2
  37. data/spec/rubocop/cop/rspec/empty_line_after_example_group_spec.rb +15 -0
  38. data/spec/rubocop/cop/rspec/factory_bot/attribute_defined_statically_spec.rb +156 -0
  39. data/spec/rubocop/cop/rspec/let_before_examples_spec.rb +0 -5
  40. data/spec/rubocop/cop/rspec/missing_example_group_argument_spec.rb +55 -0
  41. data/spec/rubocop/cop/rspec/overwriting_setup_spec.rb +0 -5
  42. data/spec/rubocop/cop/rspec/receive_never_spec.rb +45 -0
  43. data/spec/rubocop/cop/rspec/scattered_let_spec.rb +0 -5
  44. data/spec/shared/smoke_test_examples.rb +25 -0
  45. data/spec/smoke_tests/empty_spec.rb +0 -0
  46. data/spec/smoke_tests/factory_bot_spec.rb +11 -0
  47. data/spec/smoke_tests/no_tests_spec.rb +4 -0
  48. data/spec/smoke_tests/weird_rspec_spec.rb +233 -0
  49. data/spec/spec_helper.rb +4 -0
  50. metadata +24 -11
  51. data/lib/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically.rb +0 -93
  52. data/lib/rubocop/cop/rspec/factory_bot/static_attribute_defined_dynamically.rb +0 -81
  53. data/spec/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically_spec.rb +0 -139
  54. 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: 2cb62faf05dbb3d997032a8fbac1d3d1897542d7a98b1540c54afebc10a6a294
4
- data.tar.gz: 6b1fae2d79e473c5e8295fe6ccb5e843e8801b2ec6ea3c54625e8ba16e7c522d
3
+ metadata.gz: 6138f067fde5bf88b21e56895a967a55e8bc9357dfd16d0044fd2777c5cbadc7
4
+ data.tar.gz: 64d630cc6a9f3d1413a8155486f002a1d524f9750ebf2c18d5c5bc485c21e438
5
5
  SHA512:
6
- metadata.gz: 2136057006988a3e05ab8be06f16125e76c520d1e46d656dd8aee9d7ae0c841fbc55d07e247e332120ab32b1f0a41e5b24827012104c8c3b75ac7e15de7e9395
7
- data.tar.gz: 6a55cfcf03e4c2b15157e3292a89e161b3a25dc10ee45325912e9bf0fd4a13705b7d9b1e7c5f309c9a5ea9fc608a333af144a36844e95d6f20658cde5d290fd5
6
+ metadata.gz: 57246fef93f5061741c542a5710c16c905ff086da1d06974473e8b6ad54a6c84e26c4d79f7f538a92bca7d53ceb4c20e9eace2d65536922168e4ca227bb5a152
7
+ data.tar.gz: 6940142c7e889246bab48ccd06dc35784731181b774fc047ba9359f5e5b5975b5b10cee3a2ac970e11142ed1ae9dfc004e88e30cba5470945088a23cd7506b8d
@@ -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/bbatsov/rubocop).
10
+ [RuboCop](https://github.com/rubocop-hq/rubocop).
11
11
 
12
12
  ## Installation
13
13
 
@@ -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 =~ one(second_arg.children)
30
+ return if METHOD_STRING_MATCHER =~ second_arg.str_content
31
31
 
32
32
  add_offense(second_arg, location: :expression)
33
33
  end
@@ -70,7 +70,7 @@ module RuboCop
70
70
  def on_block(node)
71
71
  return unless example_group?(node) && !contains_example?(node)
72
72
 
73
- add_offense(node.children.first, location: :expression)
73
+ add_offense(node.send_node, location: :expression)
74
74
  end
75
75
 
76
76
  private
@@ -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 node.parent && node.equal?(node.parent.children.last)
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 latest_let.equal?(node.body.children.last)
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 node.equal?(node.parent.children.last)
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 node.equal?(node.parent.children.last)
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 on_send(node)
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
- def_node_matcher :hook, <<-PATTERN
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) do |hook_name, body|
40
- expect(body) do |expect|
41
- method = send_node(expect)
42
- add_offense(method, location: :selector,
43
- message: message(method, hook_name))
44
- end
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
@@ -18,8 +18,6 @@ module RuboCop
18
18
  MSG = 'Use `expect { ... }.to output(...).to_%<name>s` '\
19
19
  'instead of mutating $%<name>s.'.freeze
20
20
 
21
- def_node_matcher :hook?, Hooks::ALL.block_pattern
22
-
23
21
  def on_gvasgn(node)
24
22
  return unless inside_example_scope?(node)
25
23
 
@@ -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
@@ -22,8 +22,6 @@ module RuboCop
22
22
  MSG = 'Use `instance_spy` when you check your double '\
23
23
  'with `have_received`.'.freeze
24
24
 
25
- def_node_matcher :example?, Examples::ALL.block_pattern
26
-
27
25
  def_node_search :null_double, <<-PATTERN
28
26
  (lvasgn $_
29
27
  (send
@@ -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.children.first, location: :expression)
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
- Examples::ALL.include?(ancestor.method_name)
86
+ example?(ancestor)
92
87
  end
93
88
  end
94
89
  end
@@ -36,8 +36,6 @@ module RuboCop
36
36
 
37
37
  MSG = 'Move `let` before the examples in the group.'.freeze
38
38
 
39
- def_node_matcher :let?, Helpers::ALL.block_pattern
40
-
41
39
  def_node_matcher :example_or_group?, <<-PATTERN
42
40
  {
43
41
  #{(Examples::ALL + ExampleGroups::ALL).block_pattern}