rubocop-rspec 1.13.0 → 1.14.0

Sign up to get free protection for your applications and to get access to all the features.
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