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.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +125 -81
  3. data/config/default.yml +59 -6
  4. data/lib/rubocop/cop/rspec/align_left_let_brace.rb +8 -9
  5. data/lib/rubocop/cop/rspec/align_right_let_brace.rb +8 -9
  6. data/lib/rubocop/cop/rspec/any_instance.rb +1 -0
  7. data/lib/rubocop/cop/rspec/around_block.rb +26 -3
  8. data/lib/rubocop/cop/rspec/be.rb +0 -1
  9. data/lib/rubocop/cop/rspec/be_eq.rb +0 -1
  10. data/lib/rubocop/cop/rspec/be_eql.rb +0 -1
  11. data/lib/rubocop/cop/rspec/before_after_all.rb +1 -0
  12. data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +9 -3
  13. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +2 -1
  14. data/lib/rubocop/cop/rspec/capybara/specific_finders.rb +86 -0
  15. data/lib/rubocop/cop/rspec/capybara/specific_matcher.rb +158 -0
  16. data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +0 -1
  17. data/lib/rubocop/cop/rspec/change_by_zero.rb +67 -7
  18. data/lib/rubocop/cop/rspec/class_check.rb +101 -0
  19. data/lib/rubocop/cop/rspec/context_method.rb +2 -1
  20. data/lib/rubocop/cop/rspec/context_wording.rb +49 -18
  21. data/lib/rubocop/cop/rspec/describe_class.rb +1 -1
  22. data/lib/rubocop/cop/rspec/describe_method.rb +1 -0
  23. data/lib/rubocop/cop/rspec/described_class.rb +5 -15
  24. data/lib/rubocop/cop/rspec/dialect.rb +1 -0
  25. data/lib/rubocop/cop/rspec/empty_example_group.rb +19 -4
  26. data/lib/rubocop/cop/rspec/empty_hook.rb +4 -5
  27. data/lib/rubocop/cop/rspec/empty_line_after_example.rb +4 -9
  28. data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +1 -1
  29. data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +2 -1
  30. data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +32 -2
  31. data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +2 -1
  32. data/lib/rubocop/cop/rspec/example_length.rb +3 -2
  33. data/lib/rubocop/cop/rspec/example_without_description.rb +3 -2
  34. data/lib/rubocop/cop/rspec/example_wording.rb +2 -1
  35. data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +1 -0
  36. data/lib/rubocop/cop/rspec/expect_actual.rb +5 -0
  37. data/lib/rubocop/cop/rspec/expect_change.rb +9 -9
  38. data/lib/rubocop/cop/rspec/expect_in_hook.rb +4 -1
  39. data/lib/rubocop/cop/rspec/expect_output.rb +1 -0
  40. data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +2 -1
  41. data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +50 -13
  42. data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +1 -0
  43. data/lib/rubocop/cop/rspec/factory_bot/syntax_methods.rb +1 -1
  44. data/lib/rubocop/cop/rspec/file_path.rb +8 -4
  45. data/lib/rubocop/cop/rspec/focus.rb +20 -4
  46. data/lib/rubocop/cop/rspec/hook_argument.rb +10 -5
  47. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +10 -9
  48. data/lib/rubocop/cop/rspec/identical_equality_assertion.rb +0 -1
  49. data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +1 -0
  50. data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -3
  51. data/lib/rubocop/cop/rspec/instance_spy.rb +1 -1
  52. data/lib/rubocop/cop/rspec/instance_variable.rb +0 -1
  53. data/lib/rubocop/cop/rspec/it_behaves_like.rb +3 -2
  54. data/lib/rubocop/cop/rspec/iterated_expectation.rb +16 -0
  55. data/lib/rubocop/cop/rspec/leading_subject.rb +15 -15
  56. data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
  57. data/lib/rubocop/cop/rspec/let_before_examples.rb +7 -8
  58. data/lib/rubocop/cop/rspec/let_setup.rb +4 -4
  59. data/lib/rubocop/cop/rspec/message_chain.rb +1 -1
  60. data/lib/rubocop/cop/rspec/message_expectation.rb +1 -1
  61. data/lib/rubocop/cop/rspec/message_spies.rb +7 -1
  62. data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +2 -1
  63. data/lib/rubocop/cop/rspec/mixin/css_selector.rb +99 -0
  64. data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +13 -4
  65. data/lib/rubocop/cop/rspec/mixin/namespace.rb +23 -0
  66. data/lib/rubocop/cop/rspec/multiple_describes.rb +1 -0
  67. data/lib/rubocop/cop/rspec/multiple_expectations.rb +19 -3
  68. data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +1 -3
  69. data/lib/rubocop/cop/rspec/multiple_subjects.rb +17 -2
  70. data/lib/rubocop/cop/rspec/named_subject.rb +2 -1
  71. data/lib/rubocop/cop/rspec/nested_groups.rb +45 -25
  72. data/lib/rubocop/cop/rspec/no_expectation_example.rb +64 -0
  73. data/lib/rubocop/cop/rspec/not_to_not.rb +13 -1
  74. data/lib/rubocop/cop/rspec/overwriting_setup.rb +2 -1
  75. data/lib/rubocop/cop/rspec/pending.rb +1 -0
  76. data/lib/rubocop/cop/rspec/predicate_matcher.rb +2 -1
  77. data/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +1 -2
  78. data/lib/rubocop/cop/rspec/rails/have_http_status.rb +47 -0
  79. data/lib/rubocop/cop/rspec/receive_counts.rb +14 -15
  80. data/lib/rubocop/cop/rspec/receive_never.rb +4 -5
  81. data/lib/rubocop/cop/rspec/repeated_description.rb +25 -26
  82. data/lib/rubocop/cop/rspec/repeated_example.rb +1 -1
  83. data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +28 -29
  84. data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +28 -29
  85. data/lib/rubocop/cop/rspec/repeated_include_example.rb +32 -33
  86. data/lib/rubocop/cop/rspec/return_from_stub.rb +12 -12
  87. data/lib/rubocop/cop/rspec/scattered_let.rb +1 -5
  88. data/lib/rubocop/cop/rspec/scattered_setup.rb +2 -2
  89. data/lib/rubocop/cop/rspec/shared_context.rb +1 -1
  90. data/lib/rubocop/cop/rspec/stubbed_mock.rb +0 -1
  91. data/lib/rubocop/cop/rspec/subject_declaration.rb +0 -1
  92. data/lib/rubocop/cop/rspec/subject_stub.rb +2 -2
  93. data/lib/rubocop/cop/rspec/unspecified_exception.rb +15 -15
  94. data/lib/rubocop/cop/rspec/variable_definition.rb +1 -0
  95. data/lib/rubocop/cop/rspec/variable_name.rb +6 -7
  96. data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -0
  97. data/lib/rubocop/cop/rspec/void_expect.rb +2 -1
  98. data/lib/rubocop/cop/rspec/yield.rb +3 -2
  99. data/lib/rubocop/cop/rspec_cops.rb +5 -0
  100. data/lib/rubocop/rspec/config_formatter.rb +14 -3
  101. data/lib/rubocop/rspec/inject.rb +1 -3
  102. data/lib/rubocop/rspec/language/node_pattern.rb +4 -0
  103. data/lib/rubocop/rspec/language.rb +6 -1
  104. data/lib/rubocop/rspec/node.rb +1 -1
  105. data/lib/rubocop/rspec/version.rb +1 -1
  106. data/lib/rubocop/rspec/wording.rb +2 -2
  107. data/lib/rubocop/rspec.rb +14 -0
  108. data/lib/rubocop-rspec.rb +3 -0
  109. 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 wont run anyway } }
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
- add_offense(node.send_node) if offensive?(body)
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
- range = range_with_surrounding_space(
40
- range: node.loc.expression,
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.line_count == 1 && next_one_line_example?(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 = next_sibling(node)
71
+ next_sibling = node.right_sibling
73
72
  return unless next_sibling
74
73
  return unless example?(next_sibling)
75
74
 
76
- next_sibling.line_count == 1
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
- # before { do_something }
25
+ # after { do_something }
23
26
  #
24
27
  # it { does_something }
25
28
  #
26
- # # good
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 behaviour, e.g. with a `let` block, or a helper
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)
@@ -22,6 +22,7 @@ module RuboCop
22
22
  # # good
23
23
  # context 'when a condition is met' do
24
24
  # end
25
+ #
25
26
  class ExcessiveDocstringSpacing < Base
26
27
  extend AutoCorrector
27
28
 
@@ -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: block`
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)
@@ -14,6 +14,7 @@ module RuboCop
14
14
  #
15
15
  # # good
16
16
  # expect { my_app.print_report }.to output('Hello World').to_stdout
17
+ #
17
18
  class ExpectOutput < Base
18
19
  MSG = 'Use `expect { ... }.to output(...).to_%<name>s` ' \
19
20
  'instead of mutating $%<name>s.'
@@ -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
- # # good
19
- # 3.times { |n| create :user, created_at: n.months.ago }
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 n_times_block_without_arg?(node)
37
- def_node_matcher :n_times_block_without_arg?, <<-PATTERN
43
+ # @!method array_new_or_n_times_block?(node)
44
+ def_node_matcher :array_new_or_n_times_block?, <<-PATTERN
38
45
  (block
39
- (send (int _) :times)
40
- (args)
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
- return unless n_times_block_without_arg?(node)
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.receiver.source)
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.receiver.source}"
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
- format_singeline_block(node)
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 format_singeline_block(node)
245
+ def format_singleline_block(node)
209
246
  " { #{node.arguments.source} #{node.body.source} }"
210
247
  end
211
248
  end
@@ -19,6 +19,7 @@ module RuboCop
19
19
  # # good
20
20
  # factory :foo, class: 'Foo' do
21
21
  # end
22
+ #
22
23
  class FactoryClassName < Base
23
24
  extend AutoCorrector
24
25
 
@@ -7,7 +7,7 @@ module RuboCop
7
7
  # Use shorthands from `FactoryBot::Syntax::Methods` in your specs.
8
8
  #
9
9
  # @safety
10
- # The auto-correction is marked as unsafe because the cop
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/, '')}" unless ignore_methods?
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
- constant.const_name.split('::').map do |name|
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 = range_with_surrounding_space(
73
- range: focus.loc.expression,
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