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 +4 -4
- data/CHANGELOG.md +9 -0
- data/config/default.yml +20 -0
- data/lib/rubocop-rspec.rb +5 -0
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +80 -0
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +47 -0
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +52 -0
- data/lib/rubocop/cop/rspec/leading_subject.rb +26 -3
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +54 -0
- data/lib/rubocop/cop/rspec/scattered_let.rb +58 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- data/spec/project/changelog_spec.rb +5 -12
- data/spec/rubocop/cop/rspec/empty_line_after_final_let_spec.rb +142 -0
- data/spec/rubocop/cop/rspec/empty_line_after_subject_spec.rb +77 -0
- data/spec/rubocop/cop/rspec/iterated_expectation_spec.rb +72 -0
- data/spec/rubocop/cop/rspec/leading_subject_spec.rb +57 -0
- data/spec/rubocop/cop/rspec/overwriting_setup_spec.rb +46 -0
- data/spec/rubocop/cop/rspec/scattered_let_spec.rb +26 -0
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d76ad6b5a03029a44d0df0b733fd13816be3ffd
|
4
|
+
data.tar.gz: 430a2169a27502c780f3ab10d9e0bae261a31f94
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54815c238a360be303b16144d9dcb3338770948de917b0a5a6f292dd25721b9d48c042edab0361f203b050be82cb18bcd2dcd1250b4ee111f9e3f3d15dd1ed1d
|
7
|
+
data.tar.gz: 1d39b6af29a27b1cda1ae5f223e74dfba11f494381920ae821941546322d3688cd30e3666a245535c6bc8998c2b7bb13c4aafc378ebc7b3469ee434b60741db3
|
data/CHANGELOG.md
CHANGED
@@ -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][])
|
data/config/default.yml
CHANGED
@@ -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
|
data/lib/rubocop-rspec.rb
CHANGED
@@ -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
|
41
|
-
|
42
|
-
|
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
|
@@ -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.
|
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.
|
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.
|
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.
|
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.
|
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-
|
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.
|
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
|