rubocop-rspec 1.13.0 → 1.14.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 94ad662f54f32cf6cbde51f8c2fdd788fa44e989
4
- data.tar.gz: d0c3723b84a23c6589aa10d9f379b7d56b332bcc
3
+ metadata.gz: 0d76ad6b5a03029a44d0df0b733fd13816be3ffd
4
+ data.tar.gz: 430a2169a27502c780f3ab10d9e0bae261a31f94
5
5
  SHA512:
6
- metadata.gz: fbc83814064a1e25163689e9da12bcfcac4c8f0849c62fe34adb13b6fa7a569f8a37a627bd04fe067f28bec140c4d8f89c9b2bed537b21eaafdeac9ad32c8663
7
- data.tar.gz: cf26853505de97b2ba385add43eb5cbf71cac5395c9f773208f93d4bd02b9650e023ee9a27b4c0f23e0ee7909370d8c8060fa05fa2299aa639ba3837054cdfb1
6
+ metadata.gz: 54815c238a360be303b16144d9dcb3338770948de917b0a5a6f292dd25721b9d48c042edab0361f203b050be82cb18bcd2dcd1250b4ee111f9e3f3d15dd1ed1d
7
+ data.tar.gz: 1d39b6af29a27b1cda1ae5f223e74dfba11f494381920ae821941546322d3688cd30e3666a245535c6bc8998c2b7bb13c4aafc378ebc7b3469ee434b60741db3
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 1.14.0 (2017-03-24)
6
+
7
+ * Add `RSpec/OverwritingSetup` cop. ([@Darhazer][])
8
+ * Add autocorrect support for `RSpec/LeadingSubject` cop. ([@Darhazer][])
9
+ * Add `RSpec/ScatteredLet` cop. ([@Darhazer][])
10
+ * Add `RSpec/IteratedExpectation` cop. ([@Darhazer][])
11
+ * Add `RSpec/EmptyLineAfterSubject` cop. ([@Darhazer][])
12
+ * Add `RSpec/EmptyLineAfterFinalLet` cop. ([@Darhazer][])
13
+
5
14
  ## 1.13.0 (2017-03-07)
6
15
 
7
16
  * Add repeated 'it' detection to `RSpec/ExampleWording` cop. ([@dgollahon][])
@@ -42,11 +42,23 @@ RSpec/DescribeMethod:
42
42
  Description: Checks that the second argument to `describe` specifies a method.
43
43
  Enabled: true
44
44
 
45
+ RSpec/IteratedExpectation:
46
+ Description: Check that `all` matcher is used instead of iterating over an array.
47
+ Enabled: true
48
+
45
49
  RSpec/EmptyExampleGroup:
46
50
  Description: Checks if an example group does not include any tests.
47
51
  Enabled: true
48
52
  CustomIncludeMethods: []
49
53
 
54
+ RSpec/EmptyLineAfterFinalLet:
55
+ Description: Checks if there is an empty line after the last let block.
56
+ Enabled: true
57
+
58
+ RSpec/EmptyLineAfterSubject:
59
+ Description: Checks if there is an empty line after subject block.
60
+ Enabled: true
61
+
50
62
  RSpec/ExampleLength:
51
63
  Description: Checks for long examples.
52
64
  Enabled: true
@@ -171,6 +183,10 @@ RSpec/NotToNot:
171
183
  - to_not
172
184
  Enabled: true
173
185
 
186
+ RSpec/OverwritingSetup:
187
+ Enabled: true
188
+ Description: Checks if there is a let/subject that overwrites an existing one.
189
+
174
190
  RSpec/RepeatedDescription:
175
191
  Enabled: true
176
192
  Description: Check for repeated description strings in example groups.
@@ -187,6 +203,10 @@ RSpec/SingleArgumentMessageChain:
187
203
  Description: Checks that chains of messages contain more than one element.
188
204
  Enabled: true
189
205
 
206
+ RSpec/ScatteredLet:
207
+ Description: Checks for let scattered across the example group.
208
+ Enabled: true
209
+
190
210
  RSpec/ScatteredSetup:
191
211
  Description: Checks for setup scattered across multiple hooks in an example group.
192
212
  Enabled: true
@@ -28,6 +28,8 @@ require 'rubocop/cop/rspec/describe_class'
28
28
  require 'rubocop/cop/rspec/describe_method'
29
29
  require 'rubocop/cop/rspec/described_class'
30
30
  require 'rubocop/cop/rspec/empty_example_group'
31
+ require 'rubocop/cop/rspec/empty_line_after_final_let'
32
+ require 'rubocop/cop/rspec/empty_line_after_subject'
31
33
  require 'rubocop/cop/rspec/example_length'
32
34
  require 'rubocop/cop/rspec/example_wording'
33
35
  require 'rubocop/cop/rspec/expect_actual'
@@ -39,6 +41,7 @@ require 'rubocop/cop/rspec/implicit_expect'
39
41
  require 'rubocop/cop/rspec/instance_spy'
40
42
  require 'rubocop/cop/rspec/instance_variable'
41
43
  require 'rubocop/cop/rspec/it_behaves_like'
44
+ require 'rubocop/cop/rspec/iterated_expectation'
42
45
  require 'rubocop/cop/rspec/leading_subject'
43
46
  require 'rubocop/cop/rspec/let_setup'
44
47
  require 'rubocop/cop/rspec/message_chain'
@@ -49,8 +52,10 @@ require 'rubocop/cop/rspec/multiple_expectations'
49
52
  require 'rubocop/cop/rspec/named_subject'
50
53
  require 'rubocop/cop/rspec/nested_groups'
51
54
  require 'rubocop/cop/rspec/not_to_not'
55
+ require 'rubocop/cop/rspec/overwriting_setup'
52
56
  require 'rubocop/cop/rspec/repeated_description'
53
57
  require 'rubocop/cop/rspec/repeated_example'
58
+ require 'rubocop/cop/rspec/scattered_let'
54
59
  require 'rubocop/cop/rspec/scattered_setup'
55
60
  require 'rubocop/cop/rspec/shared_context'
56
61
  require 'rubocop/cop/rspec/single_argument_message_chain'
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks if there is an empty line after the last let block.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # let(:foo) { bar }
11
+ # let(:something) { other }
12
+ # it do
13
+ # ...
14
+ # end
15
+ #
16
+ # # good
17
+ # let(:foo) { bar }
18
+ # let(:something) { other }
19
+ #
20
+ # it do
21
+ # ...
22
+ # end
23
+ class EmptyLineAfterFinalLet < Cop
24
+ MSG = 'Add an empty line after the last `let` block.'.freeze
25
+
26
+ def_node_matcher :let?, '(block $(send nil {:let :let!} ...) args ...)'
27
+
28
+ def on_block(node)
29
+ return unless let?(node) && !in_spec_block?(node)
30
+
31
+ latest_let = node
32
+ node.parent.each_child_node do |sibling|
33
+ latest_let = sibling if let?(sibling)
34
+ end
35
+
36
+ return if latest_let.equal?(node.parent.children.last)
37
+
38
+ no_new_line_after(latest_let) do
39
+ add_offense(latest_let, :expression)
40
+ end
41
+ end
42
+
43
+ def autocorrect(node)
44
+ loc = last_node_loc(node)
45
+ ->(corrector) { corrector.insert_after(loc.end, "\n") }
46
+ end
47
+
48
+ private
49
+
50
+ def no_new_line_after(node)
51
+ loc = last_node_loc(node)
52
+
53
+ next_line = processed_source[loc.line]
54
+
55
+ yield unless next_line.blank?
56
+ end
57
+
58
+ def last_node_loc(node)
59
+ last_line = node.loc.end.line
60
+ heredoc_line(node) do |loc|
61
+ return loc if loc.line > last_line
62
+ end
63
+ node.loc.end
64
+ end
65
+
66
+ def heredoc_line(node, &block)
67
+ yield node.loc.heredoc_end if node.loc.respond_to?(:heredoc_end)
68
+
69
+ node.each_child_node { |child| heredoc_line(child, &block) }
70
+ end
71
+
72
+ def in_spec_block?(node)
73
+ node.each_ancestor(:block).any? do |ancestor|
74
+ Examples::ALL.include?(ancestor.method_name)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks if there is an empty line after subject block.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # subject(:obj) { described_class }
11
+ # let(:foo) { bar }
12
+ #
13
+ # # good
14
+ # subject(:obj) { described_class }
15
+ #
16
+ # let(:foo) { bar }
17
+ class EmptyLineAfterSubject < Cop
18
+ MSG = 'Add empty line after `subject`.'.freeze
19
+
20
+ def_node_matcher :subject?, '(block $(send nil :subject ...) args ...)'
21
+
22
+ def on_block(node)
23
+ return unless subject?(node) && !in_spec_block?(node)
24
+ return if node.equal?(node.parent.children.last)
25
+
26
+ send_line = node.loc.end.line
27
+ next_line = processed_source[send_line]
28
+ return if next_line.blank?
29
+
30
+ add_offense(node, :expression, MSG)
31
+ end
32
+
33
+ def autocorrect(node)
34
+ ->(corrector) { corrector.insert_after(node.loc.end, "\n") }
35
+ end
36
+
37
+ private
38
+
39
+ def in_spec_block?(node)
40
+ node.each_ancestor(:block).any? do |ancestor|
41
+ Examples::ALL.include?(ancestor.method_name)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,52 @@
1
+ module RuboCop
2
+ module Cop
3
+ module RSpec
4
+ # Check that `all` matcher is used instead of iterating over an array.
5
+ #
6
+ # @example
7
+ # # bad
8
+ # it 'validates users' do
9
+ # [user1, user2, user3].each { |user| expect(user).to be_valid }
10
+ # end
11
+ #
12
+ # # good
13
+ # it 'validates users' do
14
+ # expect([user1, user2, user3]).to all(be_valid)
15
+ # end
16
+ class IteratedExpectation < Cop
17
+ MSG = 'Prefer using the `all` matcher instead ' \
18
+ 'of iterating over an array.'.freeze
19
+
20
+ def_node_matcher :each?, <<-PATTERN
21
+ (block
22
+ (send ... :each)
23
+ (args (arg $_))
24
+ $(...)
25
+ )
26
+ PATTERN
27
+
28
+ def_node_matcher :expectation?, <<-PATTERN
29
+ (send (send nil :expect (lvar %)) :to ...)
30
+ PATTERN
31
+
32
+ def on_block(node)
33
+ each?(node) do |arg, body|
34
+ if single_expectation?(body, arg) || only_expectations?(body, arg)
35
+ add_offense(node.children.first, :expression)
36
+ end
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def single_expectation?(body, arg)
43
+ expectation?(body, arg)
44
+ end
45
+
46
+ def only_expectations?(body, arg)
47
+ body.children.all? { |child| expectation?(child, arg) }
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -37,14 +37,37 @@ module RuboCop
37
37
  node.parent.each_child_node do |sibling|
38
38
  break if sibling.equal?(node)
39
39
 
40
- if sibling.method_name.equal?(:let)
41
- break add_offense(node, :expression)
42
- end
40
+ break add_offense(node, :expression) if let?(sibling)
41
+ end
42
+ end
43
+
44
+ def autocorrect(node)
45
+ lambda do |corrector|
46
+ first_let = find_first_let(node)
47
+ first_let_position = first_let.loc.expression
48
+ indent = "\n" + ' ' * first_let.loc.column
49
+ corrector.insert_before(first_let_position, node.source + indent)
50
+ corrector.remove(node_range(node))
43
51
  end
44
52
  end
45
53
 
46
54
  private
47
55
 
56
+ def let?(node)
57
+ [:let, :let!].include?(node.method_name)
58
+ end
59
+
60
+ def find_first_let(node)
61
+ node.parent.children.find { |sibling| let?(sibling) }
62
+ end
63
+
64
+ def node_range(node)
65
+ range = node.source_range
66
+ range = range_with_surrounding_space(range, :left, false)
67
+ range = range_with_surrounding_space(range, :right, true)
68
+ range
69
+ end
70
+
48
71
  def in_spec_block?(node)
49
72
  node.each_ancestor(:block).any? do |ancestor|
50
73
  Examples::ALL.include?(ancestor.method_name)
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks if there is a let/subject that overwrites an existing one.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # let(:foo) { bar }
11
+ # let(:foo) { baz }
12
+ #
13
+ # subject(:foo) { bar }
14
+ # let(:foo) { baz }
15
+ #
16
+ # let(:foo) { bar }
17
+ # let!(:foo) { baz }
18
+ #
19
+ # # good
20
+ # subject(:test) { something }
21
+ # let(:foo) { bar }
22
+ # let(:baz) { baz }
23
+ # let!(:other) { other }
24
+ class OverwritingSetup < Cop
25
+ MSG = '`%{name}` is already defined.'.freeze
26
+
27
+ def_node_matcher :setup?, <<-PATTERN
28
+ (block (send nil {:let :let! :subject} (sym $_)) ...)
29
+ PATTERN
30
+
31
+ def on_block(node)
32
+ return unless example_group?(node)
33
+
34
+ _describe, _args, body = *node
35
+
36
+ find_duplicates(body) do |duplicate, name|
37
+ add_offense(duplicate, :expression, format(MSG, name: name))
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def find_duplicates(node)
44
+ setup_expressions = Set.new
45
+ node.each_child_node do |child|
46
+ setup?(child) do |name|
47
+ yield child, name unless setup_expressions.add?(name)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks for let scattered across the example group.
7
+ #
8
+ # Group lets together
9
+ #
10
+ # @example
11
+ # # bad
12
+ # describe Foo do
13
+ # let(:foo) { 1 }
14
+ # subject { Foo }
15
+ # let(:bar) { 2 }
16
+ # before { prepare }
17
+ # let!(:baz) { 3 }
18
+ # end
19
+ #
20
+ # # good
21
+ # describe Foo do
22
+ # subject { Foo }
23
+ # before { prepare }
24
+ # let(:foo) { 1 }
25
+ # let(:bar) { 2 }
26
+ # let!(:baz) { 3 }
27
+ # end
28
+ #
29
+ class ScatteredLet < Cop
30
+ MSG = 'Group all let/let! blocks in the example group together.'.freeze
31
+
32
+ def_node_matcher :let?, '(block (send nil {:let :let!} ...) ...)'
33
+
34
+ def on_block(node)
35
+ return unless example_group?(node)
36
+
37
+ _describe, _args, body = *node
38
+
39
+ check_let_declarations(body)
40
+ end
41
+
42
+ def check_let_declarations(node)
43
+ let_found = false
44
+ mix_found = false
45
+
46
+ node.each_child_node do |child|
47
+ if let?(child)
48
+ add_offense(child, :expression) if mix_found
49
+ let_found = true
50
+ elsif let_found
51
+ mix_found = true
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module RSpec
5
5
  # Version information for the RSpec RuboCop plugin.
6
6
  module Version
7
- STRING = '1.13.0'.freeze
7
+ STRING = '1.14.0'.freeze
8
8
  end
9
9
  end
10
10
  end
@@ -10,18 +10,15 @@ RSpec.describe 'CHANGELOG.md' do
10
10
 
11
11
  describe 'entry' do
12
12
  subject(:entries) { lines.grep(/^\*/).map(&:chomp) }
13
+
13
14
  let(:lines) { changelog.each_line }
14
15
 
15
16
  it 'has a whitespace between the * and the body' do
16
- entries.each do |entry|
17
- expect(entry).to match(/^\* \S/)
18
- end
17
+ expect(entries).to all(match(/^\* \S/))
19
18
  end
20
19
 
21
20
  it 'has a link to the contributors at the end' do
22
- entries.each do |entry|
23
- expect(entry).to match(/\(\[@\S+\]\[\](?:, \[@\S+\]\[\])*\)$/)
24
- end
21
+ expect(entries).to all(match(/\(\[@\S+\]\[\](?:, \[@\S+\]\[\])*\)$/))
25
22
  end
26
23
 
27
24
  describe 'link to related issue on github' do
@@ -50,9 +47,7 @@ RSpec.describe 'CHANGELOG.md' do
50
47
  entry.match(/^\*\s*\[/)
51
48
  end
52
49
 
53
- entries_including_issue_link.each do |entry|
54
- expect(entry).to include('): ')
55
- end
50
+ expect(entries_including_issue_link).to all(include('): '))
56
51
  end
57
52
  end
58
53
 
@@ -72,9 +67,7 @@ RSpec.describe 'CHANGELOG.md' do
72
67
  end
73
68
 
74
69
  it 'ends with a punctuation' do
75
- bodies.each do |body|
76
- expect(body).to match(/[\.\!]$/)
77
- end
70
+ expect(bodies).to all(match(/[\.\!]$/))
78
71
  end
79
72
  end
80
73
  end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RuboCop::Cop::RSpec::EmptyLineAfterFinalLet do
4
+ subject(:cop) { described_class.new }
5
+
6
+ it 'checks for empty line after last let' do
7
+ expect_violation(<<-RUBY)
8
+ RSpec.describe User do
9
+ let(:a) { a }
10
+ let(:b) { b }
11
+ ^^^^^^^^^^^^^ Add an empty line after the last `let` block.
12
+ it { expect(a).to eq(b) }
13
+ end
14
+ RUBY
15
+ end
16
+
17
+ it 'check for empty line after the last `let!`' do
18
+ expect_violation(<<-RUBY)
19
+ RSpec.describe User do
20
+ let(:a) { a }
21
+ let!(:b) do
22
+ ^^^^^^^^^^^ Add an empty line after the last `let` block.
23
+ b
24
+ end
25
+ it { expect(a).to eq(b) }
26
+ end
27
+ RUBY
28
+ end
29
+
30
+ it 'approves empty line after let' do
31
+ expect_no_violations(<<-RUBY)
32
+ RSpec.describe User do
33
+ let(:a) { a }
34
+ let(:b) { b }
35
+
36
+ it { expect(a).to eq(b) }
37
+ end
38
+ RUBY
39
+ end
40
+
41
+ it 'ignores empty lines between the lets' do
42
+ expect_violation(<<-RUBY)
43
+ RSpec.describe User do
44
+ let(:a) { a }
45
+
46
+ subject { described_class }
47
+
48
+ let!(:b) { b }
49
+ ^^^^^^^^^^^^^^ Add an empty line after the last `let` block.
50
+ it { expect(a).to eq(b) }
51
+ end
52
+ RUBY
53
+ end
54
+
55
+ it 'handles let in tests' do
56
+ expect_no_violations(<<-RUBY)
57
+ RSpec.describe User do
58
+ # This shouldn't really ever happen in a sane codebase but I still
59
+ # want to avoid false positives
60
+ it "doesn't mind me calling a method called let in the test" do
61
+ let(foo)
62
+ subject { bar }
63
+ end
64
+ end
65
+ RUBY
66
+ end
67
+
68
+ it 'handles multiline let block' do
69
+ expect_no_violations(<<-RUBY)
70
+ RSpec.describe User do
71
+ let(:a) { a }
72
+ let(:b) do
73
+ b
74
+ end
75
+
76
+ it { expect(a).to eq(b) }
77
+ end
78
+ RUBY
79
+ end
80
+
81
+ it 'handles let being the latest node' do
82
+ expect_no_violations(<<-RUBY)
83
+ RSpec.describe User do
84
+ let(:a) { a }
85
+ let(:b) { b }
86
+ end
87
+ RUBY
88
+ end
89
+
90
+ it 'handles HEREDOC for let' do
91
+ expect_no_violations(<<-RUBY)
92
+ RSpec.describe User do
93
+ let(:foo) do
94
+ <<-BAR
95
+ hello
96
+ world
97
+ BAR
98
+ end
99
+
100
+ it 'uses heredoc' do
101
+ expect(foo).to eql(" hello\n world\n")
102
+ end
103
+ end
104
+ RUBY
105
+ end
106
+
107
+ it 'handles silly HEREDOC syntax for let' do
108
+ expect_no_violations(<<-RUBY)
109
+ RSpec.describe 'silly heredoc syntax' do
110
+ let(:foo) { <<-BAR }
111
+ hello
112
+ world
113
+ BAR
114
+
115
+ it 'has tricky syntax' do
116
+ expect(foo).to eql(" hello\n world\n")
117
+ end
118
+ end
119
+ RUBY
120
+ end
121
+
122
+ bad_example = <<-RUBY
123
+ RSpec.describe User do
124
+ let(:params) { foo }
125
+ it 'has a new line' do
126
+ end
127
+ end
128
+ RUBY
129
+
130
+ good_example = <<-RUBY
131
+ RSpec.describe User do
132
+ let(:params) { foo }
133
+
134
+ it 'has a new line' do
135
+ end
136
+ end
137
+ RUBY
138
+
139
+ include_examples 'autocorrect',
140
+ bad_example,
141
+ good_example
142
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RuboCop::Cop::RSpec::EmptyLineAfterSubject do
4
+ subject(:cop) { described_class.new }
5
+
6
+ it 'checks for empty line after subject' do
7
+ expect_violation(<<-RUBY)
8
+ RSpec.describe User do
9
+ subject { described_class.new }
10
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Add empty line after `subject`.
11
+ let(:params) { foo }
12
+ end
13
+ RUBY
14
+ end
15
+
16
+ it 'approves empty line after subject' do
17
+ expect_no_violations(<<-RUBY)
18
+ RSpec.describe User do
19
+ subject { described_class.new }
20
+
21
+ let(:params) { foo }
22
+ end
23
+ RUBY
24
+ end
25
+
26
+ it 'handles subjects in tests' do
27
+ expect_no_violations(<<-RUBY)
28
+ RSpec.describe User do
29
+ # This shouldn't really ever happen in a sane codebase but I still
30
+ # want to avoid false positives
31
+ it "doesn't mind me calling a method called subject in the test" do
32
+ subject { bar }
33
+ let(foo)
34
+ end
35
+ end
36
+ RUBY
37
+ end
38
+
39
+ it 'handles multiline subject block' do
40
+ expect_no_violations(<<-RUBY)
41
+ RSpec.describe User do
42
+ subject do
43
+ described_class.new
44
+ end
45
+
46
+ let(:params) { foo }
47
+ end
48
+ RUBY
49
+ end
50
+
51
+ it 'handles let being the latest node' do
52
+ expect_no_violations(<<-RUBY)
53
+ RSpec.describe User do
54
+ subject { described_user }
55
+ end
56
+ RUBY
57
+ end
58
+
59
+ bad_example = <<-RUBY
60
+ RSpec.describe User do
61
+ subject { described_class.new }
62
+ let(:params) { foo }
63
+ end
64
+ RUBY
65
+
66
+ good_example = <<-RUBY
67
+ RSpec.describe User do
68
+ subject { described_class.new }
69
+
70
+ let(:params) { foo }
71
+ end
72
+ RUBY
73
+
74
+ include_examples 'autocorrect',
75
+ bad_example,
76
+ good_example
77
+ end
@@ -0,0 +1,72 @@
1
+ RSpec.describe RuboCop::Cop::RSpec::IteratedExpectation do
2
+ subject(:cop) { described_class.new }
3
+
4
+ it 'flags `each` with an expectation' do
5
+ expect_violation(<<-RUBY)
6
+ it 'validates users' do
7
+ [user1, user2, user3].each { |user| expect(user).to be_valid }
8
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using the `all` matcher instead of iterating over an array.
9
+ end
10
+ RUBY
11
+ end
12
+
13
+ it 'flags `each` when expectation calls method with arguments' do
14
+ expect_violation(<<-RUBY)
15
+ it 'validates users' do
16
+ [user1, user2, user3].each { |user| expect(user).to be_a(User) }
17
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using the `all` matcher instead of iterating over an array.
18
+ end
19
+ RUBY
20
+ end
21
+
22
+ it 'ignores `each` without expectation' do
23
+ expect_no_violations(<<-RUBY)
24
+ it 'validates users' do
25
+ [user1, user2, user3].each { |user| allow(user).to receive(:method) }
26
+ end
27
+ RUBY
28
+ end
29
+
30
+ it 'flags `each` with multiple expectations' do
31
+ expect_violation(<<-RUBY)
32
+ it 'validates users' do
33
+ [user1, user2, user3].each do |user|
34
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer using the `all` matcher instead of iterating over an array.
35
+ expect(user).to receive(:method)
36
+ expect(user).to receive(:other_method)
37
+ end
38
+ end
39
+ RUBY
40
+ end
41
+
42
+ it 'ignore `each` when the body does not contain only expectations' do
43
+ expect_no_violations(<<-RUBY)
44
+ it 'validates users' do
45
+ [user1, user2, user3].each do |user|
46
+ allow(Something).to receive(:method).and_return(user)
47
+ expect(user).to receive(:method)
48
+ expect(user).to receive(:other_method)
49
+ end
50
+ end
51
+ RUBY
52
+ end
53
+
54
+ it 'ignores `each` with expectation on property' do
55
+ expect_no_violations(<<-RUBY)
56
+ it 'validates users' do
57
+ [user1, user2, user3].each { |user| expect(user.name).to be }
58
+ end
59
+ RUBY
60
+ end
61
+
62
+ it 'ignores `each` when there is a negative expectation' do
63
+ expect_no_violations(<<-RUBY)
64
+ it 'validates users' do
65
+ [user1, user2, user3].each do |user|
66
+ expect(user).not_to receive(:method)
67
+ expect(user).to receive(:other_method)
68
+ end
69
+ end
70
+ RUBY
71
+ end
72
+ end
@@ -14,6 +14,17 @@ RSpec.describe RuboCop::Cop::RSpec::LeadingSubject do
14
14
  RUBY
15
15
  end
16
16
 
17
+ it 'checks subject below let!' do
18
+ expect_violation(<<-RUBY)
19
+ RSpec.describe User do
20
+ let!(:params) { foo }
21
+
22
+ subject { described_class.new }
23
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Declare `subject` above any other `let` declarations.
24
+ end
25
+ RUBY
26
+ end
27
+
17
28
  it 'approves of subject above let' do
18
29
  expect_no_violations(<<-RUBY)
19
30
  RSpec.describe User do
@@ -51,4 +62,50 @@ RSpec.describe RuboCop::Cop::RSpec::LeadingSubject do
51
62
  end
52
63
  RUBY
53
64
  end
65
+
66
+ bad_code = <<-RUBY
67
+ RSpec.describe User do
68
+ let(:params) { foo }
69
+ let(:bar) { baz }
70
+
71
+ subject { described_class.new }
72
+ it { is_expected.to do_something }
73
+ end
74
+ RUBY
75
+
76
+ good_code = <<-RUBY
77
+ RSpec.describe User do
78
+ subject { described_class.new }
79
+ let(:params) { foo }
80
+ let(:bar) { baz }
81
+
82
+ it { is_expected.to do_something }
83
+ end
84
+ RUBY
85
+
86
+ include_examples 'autocorrect', bad_code, good_code
87
+
88
+ bad_code = <<-RUBY
89
+ RSpec.describe User do
90
+ let(:params) { foo }
91
+ let(:bar) { baz }
92
+ subject do
93
+ described_class.new
94
+ end
95
+ it { is_expected.to do_something }
96
+ end
97
+ RUBY
98
+
99
+ good_code = <<-RUBY
100
+ RSpec.describe User do
101
+ subject do
102
+ described_class.new
103
+ end
104
+ let(:params) { foo }
105
+ let(:bar) { baz }
106
+ it { is_expected.to do_something }
107
+ end
108
+ RUBY
109
+
110
+ include_examples 'autocorrect', bad_code, good_code
54
111
  end
@@ -0,0 +1,46 @@
1
+ RSpec.describe RuboCop::Cop::RSpec::OverwritingSetup do
2
+ subject(:cop) { described_class.new }
3
+
4
+ it 'finds overwriten `let`' do
5
+ expect_violation(<<-RUBY)
6
+ RSpec.describe User do
7
+ let(:a) { a }
8
+ let(:a) { b }
9
+ ^^^^^^^^^^^^^ `a` is already defined.
10
+ end
11
+ RUBY
12
+ end
13
+
14
+ it 'finds overwriten `subject`' do
15
+ expect_violation(<<-RUBY)
16
+ RSpec.describe User do
17
+ subject(:a) { a }
18
+
19
+ let(:a) { b }
20
+ ^^^^^^^^^^^^^ `a` is already defined.
21
+ end
22
+ RUBY
23
+ end
24
+
25
+ it 'finds `let!` overwriting `let`' do
26
+ expect_violation(<<-RUBY)
27
+ RSpec.describe User do
28
+ let(:a) { b }
29
+ let!(:a) { b }
30
+ ^^^^^^^^^^^^^^ `a` is already defined.
31
+ end
32
+ RUBY
33
+ end
34
+
35
+ it 'ignores overwriting in different context' do
36
+ expect_no_violations(<<-RUBY)
37
+ RSpec.describe User do
38
+ let(:a) { a }
39
+
40
+ context `different` do
41
+ let(:a) { b }
42
+ end
43
+ end
44
+ RUBY
45
+ end
46
+ end
@@ -0,0 +1,26 @@
1
+ RSpec.describe RuboCop::Cop::RSpec::ScatteredLet do
2
+ subject(:cop) { described_class.new }
3
+
4
+ it 'flags `let` after the first different node ' do
5
+ expect_violation(<<-RUBY)
6
+ RSpec.describe User do
7
+ let(:a) { a }
8
+ subject { User }
9
+ let(:b) { b }
10
+ ^^^^^^^^^^^^^ Group all let/let! blocks in the example group together.
11
+ end
12
+ RUBY
13
+ end
14
+
15
+ it 'doesnt flag `let!` in the middle of multiple `let`s' do
16
+ expect_no_violations(<<-RUBY)
17
+ RSpec.describe User do
18
+ subject { User }
19
+
20
+ let(:a) { a }
21
+ let!(:b) { b }
22
+ let(:c) { c }
23
+ end
24
+ RUBY
25
+ end
26
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.13.0
4
+ version: 1.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Backus
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-03-07 00:00:00.000000000 Z
13
+ date: 2017-03-24 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubocop
@@ -153,6 +153,8 @@ files:
153
153
  - lib/rubocop/cop/rspec/describe_method.rb
154
154
  - lib/rubocop/cop/rspec/described_class.rb
155
155
  - lib/rubocop/cop/rspec/empty_example_group.rb
156
+ - lib/rubocop/cop/rspec/empty_line_after_final_let.rb
157
+ - lib/rubocop/cop/rspec/empty_line_after_subject.rb
156
158
  - lib/rubocop/cop/rspec/example_length.rb
157
159
  - lib/rubocop/cop/rspec/example_wording.rb
158
160
  - lib/rubocop/cop/rspec/expect_actual.rb
@@ -164,6 +166,7 @@ files:
164
166
  - lib/rubocop/cop/rspec/instance_spy.rb
165
167
  - lib/rubocop/cop/rspec/instance_variable.rb
166
168
  - lib/rubocop/cop/rspec/it_behaves_like.rb
169
+ - lib/rubocop/cop/rspec/iterated_expectation.rb
167
170
  - lib/rubocop/cop/rspec/leading_subject.rb
168
171
  - lib/rubocop/cop/rspec/let_setup.rb
169
172
  - lib/rubocop/cop/rspec/message_chain.rb
@@ -174,8 +177,10 @@ files:
174
177
  - lib/rubocop/cop/rspec/named_subject.rb
175
178
  - lib/rubocop/cop/rspec/nested_groups.rb
176
179
  - lib/rubocop/cop/rspec/not_to_not.rb
180
+ - lib/rubocop/cop/rspec/overwriting_setup.rb
177
181
  - lib/rubocop/cop/rspec/repeated_description.rb
178
182
  - lib/rubocop/cop/rspec/repeated_example.rb
183
+ - lib/rubocop/cop/rspec/scattered_let.rb
179
184
  - lib/rubocop/cop/rspec/scattered_setup.rb
180
185
  - lib/rubocop/cop/rspec/shared_context.rb
181
186
  - lib/rubocop/cop/rspec/single_argument_message_chain.rb
@@ -209,6 +214,8 @@ files:
209
214
  - spec/rubocop/cop/rspec/describe_method_spec.rb
210
215
  - spec/rubocop/cop/rspec/described_class_spec.rb
211
216
  - spec/rubocop/cop/rspec/empty_example_group_spec.rb
217
+ - spec/rubocop/cop/rspec/empty_line_after_final_let_spec.rb
218
+ - spec/rubocop/cop/rspec/empty_line_after_subject_spec.rb
212
219
  - spec/rubocop/cop/rspec/example_length_spec.rb
213
220
  - spec/rubocop/cop/rspec/example_wording_spec.rb
214
221
  - spec/rubocop/cop/rspec/expect_actual_spec.rb
@@ -220,6 +227,7 @@ files:
220
227
  - spec/rubocop/cop/rspec/instance_spy_spec.rb
221
228
  - spec/rubocop/cop/rspec/instance_variable_spec.rb
222
229
  - spec/rubocop/cop/rspec/it_behaves_like_spec.rb
230
+ - spec/rubocop/cop/rspec/iterated_expectation_spec.rb
223
231
  - spec/rubocop/cop/rspec/leading_subject_spec.rb
224
232
  - spec/rubocop/cop/rspec/let_setup_spec.rb
225
233
  - spec/rubocop/cop/rspec/message_chain_spec.rb
@@ -230,8 +238,10 @@ files:
230
238
  - spec/rubocop/cop/rspec/named_subject_spec.rb
231
239
  - spec/rubocop/cop/rspec/nested_groups_spec.rb
232
240
  - spec/rubocop/cop/rspec/not_to_not_spec.rb
241
+ - spec/rubocop/cop/rspec/overwriting_setup_spec.rb
233
242
  - spec/rubocop/cop/rspec/repeated_description_spec.rb
234
243
  - spec/rubocop/cop/rspec/repeated_example_spec.rb
244
+ - spec/rubocop/cop/rspec/scattered_let_spec.rb
235
245
  - spec/rubocop/cop/rspec/scattered_setup_spec.rb
236
246
  - spec/rubocop/cop/rspec/shared_context_spec.rb
237
247
  - spec/rubocop/cop/rspec/single_argument_message_chain_spec.rb
@@ -269,7 +279,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
269
279
  version: '0'
270
280
  requirements: []
271
281
  rubyforge_project:
272
- rubygems_version: 2.5.1
282
+ rubygems_version: 2.5.2
273
283
  signing_key:
274
284
  specification_version: 4
275
285
  summary: Code style checking for RSpec files
@@ -287,6 +297,8 @@ test_files:
287
297
  - spec/rubocop/cop/rspec/describe_method_spec.rb
288
298
  - spec/rubocop/cop/rspec/described_class_spec.rb
289
299
  - spec/rubocop/cop/rspec/empty_example_group_spec.rb
300
+ - spec/rubocop/cop/rspec/empty_line_after_final_let_spec.rb
301
+ - spec/rubocop/cop/rspec/empty_line_after_subject_spec.rb
290
302
  - spec/rubocop/cop/rspec/example_length_spec.rb
291
303
  - spec/rubocop/cop/rspec/example_wording_spec.rb
292
304
  - spec/rubocop/cop/rspec/expect_actual_spec.rb
@@ -298,6 +310,7 @@ test_files:
298
310
  - spec/rubocop/cop/rspec/instance_spy_spec.rb
299
311
  - spec/rubocop/cop/rspec/instance_variable_spec.rb
300
312
  - spec/rubocop/cop/rspec/it_behaves_like_spec.rb
313
+ - spec/rubocop/cop/rspec/iterated_expectation_spec.rb
301
314
  - spec/rubocop/cop/rspec/leading_subject_spec.rb
302
315
  - spec/rubocop/cop/rspec/let_setup_spec.rb
303
316
  - spec/rubocop/cop/rspec/message_chain_spec.rb
@@ -308,8 +321,10 @@ test_files:
308
321
  - spec/rubocop/cop/rspec/named_subject_spec.rb
309
322
  - spec/rubocop/cop/rspec/nested_groups_spec.rb
310
323
  - spec/rubocop/cop/rspec/not_to_not_spec.rb
324
+ - spec/rubocop/cop/rspec/overwriting_setup_spec.rb
311
325
  - spec/rubocop/cop/rspec/repeated_description_spec.rb
312
326
  - spec/rubocop/cop/rspec/repeated_example_spec.rb
327
+ - spec/rubocop/cop/rspec/scattered_let_spec.rb
313
328
  - spec/rubocop/cop/rspec/scattered_setup_spec.rb
314
329
  - spec/rubocop/cop/rspec/shared_context_spec.rb
315
330
  - spec/rubocop/cop/rspec/single_argument_message_chain_spec.rb