rubocop-rspec 1.21.0 → 1.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/Rakefile +19 -0
  4. data/config/default.yml +19 -0
  5. data/lib/rubocop-rspec.rb +17 -72
  6. data/lib/rubocop/cop/rspec/context_wording.rb +2 -2
  7. data/lib/rubocop/cop/rspec/describe_class.rb +1 -1
  8. data/lib/rubocop/cop/rspec/describe_symbol.rb +1 -1
  9. data/lib/rubocop/cop/rspec/described_class.rb +2 -4
  10. data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +6 -10
  11. data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +4 -4
  12. data/lib/rubocop/cop/rspec/example_without_description.rb +89 -0
  13. data/lib/rubocop/cop/rspec/expect_change.rb +102 -0
  14. data/lib/rubocop/cop/rspec/hook_argument.rb +9 -9
  15. data/lib/rubocop/cop/rspec/instance_variable.rb +9 -0
  16. data/lib/rubocop/cop/rspec/leading_subject.rb +1 -8
  17. data/lib/rubocop/cop/rspec/let_before_examples.rb +46 -6
  18. data/lib/rubocop/cop/rspec/multiple_describes.rb +2 -2
  19. data/lib/rubocop/cop/rspec/multiple_expectations.rb +2 -4
  20. data/lib/rubocop/cop/rspec/multiple_subjects.rb +1 -2
  21. data/lib/rubocop/cop/rspec/nested_groups.rb +2 -2
  22. data/lib/rubocop/cop/rspec/overwriting_setup.rb +11 -13
  23. data/lib/rubocop/cop/rspec/return_from_stub.rb +85 -0
  24. data/lib/rubocop/cop/rspec/scattered_let.rb +9 -13
  25. data/lib/rubocop/cop/rspec/shared_context.rb +2 -2
  26. data/lib/rubocop/cop/rspec_cops.rb +59 -0
  27. data/lib/rubocop/rspec/description_extractor.rb +13 -1
  28. data/lib/rubocop/rspec/version.rb +1 -1
  29. data/rubocop-rspec.gemspec +1 -1
  30. data/spec/rubocop/cop/rspec/describe_class_spec.rb +7 -0
  31. data/spec/rubocop/cop/rspec/example_without_description_spec.rb +82 -0
  32. data/spec/rubocop/cop/rspec/expect_change_spec.rb +78 -0
  33. data/spec/rubocop/cop/rspec/instance_variable_spec.rb +18 -0
  34. data/spec/rubocop/cop/rspec/let_before_examples_spec.rb +48 -0
  35. data/spec/rubocop/cop/rspec/return_from_stub_spec.rb +65 -0
  36. data/spec/rubocop/rspec/description_extractor_spec.rb +6 -2
  37. metadata +11 -4
@@ -19,6 +19,7 @@ module RuboCop
19
19
 
20
20
  # Decorator of a YARD code object for working with documented rspec cops
21
21
  class CodeObject
22
+ COP_CLASS_NAMES = %w[RuboCop::Cop RuboCop::Cop::RSpec::Cop].freeze
22
23
  RSPEC_NAMESPACE = 'RuboCop::Cop::RSpec'.freeze
23
24
 
24
25
  def initialize(yardoc)
@@ -29,7 +30,10 @@ module RuboCop
29
30
  #
30
31
  # @return [Boolean]
31
32
  def rspec_cop?
32
- class_documentation? && rspec_cop_namespace? && !abstract?
33
+ class_documentation? &&
34
+ rspec_cop_namespace? &&
35
+ cop_subclass? &&
36
+ !abstract?
33
37
  end
34
38
 
35
39
  # Configuration for the documented cop that would live in default.yml
@@ -61,6 +65,14 @@ module RuboCop
61
65
  yardoc.to_s
62
66
  end
63
67
 
68
+ def cop_subclass?
69
+ # YARD superclass resolution is a bit flaky: All classes loaded before
70
+ # RuboCop::Cop::WorkaroundCop are shown as having RuboCop::Cop as
71
+ # superclass, while all the following classes are listed as having
72
+ # RuboCop::Cop::RSpec::Cop as their superclass.
73
+ COP_CLASS_NAMES.include?(yardoc.superclass.path)
74
+ end
75
+
64
76
  def abstract?
65
77
  yardoc.tags.any? { |tag| tag.tag_name.eql?('abstract') }
66
78
  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.21.0'.freeze
7
+ STRING = '1.22.0'.freeze
8
8
  end
9
9
  end
10
10
  end
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.test_files = spec.files.grep(%r{^spec/})
33
33
  spec.extra_rdoc_files = ['MIT-LICENSE.md', 'README.md']
34
34
 
35
- spec.add_runtime_dependency 'rubocop', '>= 0.52.0'
35
+ spec.add_runtime_dependency 'rubocop', '>= 0.52.1'
36
36
 
37
37
  spec.add_development_dependency 'rake'
38
38
  spec.add_development_dependency 'rspec', '>= 3.4'
@@ -56,6 +56,13 @@ RSpec.describe RuboCop::Cop::RSpec::DescribeClass do
56
56
  RUBY
57
57
  end
58
58
 
59
+ it 'ignores system specs' do
60
+ expect_no_offenses(<<-RUBY)
61
+ describe 'my new system test', type: :system do
62
+ end
63
+ RUBY
64
+ end
65
+
59
66
  it 'ignores feature specs when RSpec.describe is used' do
60
67
  expect_no_offenses(<<-RUBY)
61
68
  RSpec.describe 'my new feature', type: :feature do
@@ -0,0 +1,82 @@
1
+ RSpec.describe RuboCop::Cop::RSpec::ExampleWithoutDescription, :config do
2
+ subject(:cop) { described_class.new(config) }
3
+
4
+ let(:cop_config) do
5
+ { 'EnforcedStyle' => enforced_style }
6
+ end
7
+
8
+ context 'with EnforcedStyle `always_allow`' do
9
+ let(:enforced_style) { 'always_allow' }
10
+
11
+ it 'flags empty strings for description' do
12
+ expect_offense(<<-RUBY)
13
+ it '' do
14
+ ^^ Omit the argument when you want to have auto-generated description.
15
+ expect(subject).to be_good
16
+ end
17
+ RUBY
18
+ end
19
+
20
+ it 'ignores `it` with a description' do
21
+ expect_no_offenses(<<-RUBY)
22
+ it 'is good' do
23
+ expect(subject).to be_good
24
+ end
25
+ RUBY
26
+ end
27
+
28
+ it 'ignores `it` without an argument' do
29
+ expect_no_offenses(<<-RUBY)
30
+ it do
31
+ expect(subject).to be_good
32
+ end
33
+ RUBY
34
+ end
35
+ end
36
+
37
+ context 'with EnforcedStyle `single_line_only`' do
38
+ let(:enforced_style) { 'single_line_only' }
39
+
40
+ it 'flags missing description in multi-line examples' do
41
+ expect_offense(<<-RUBY)
42
+ it do
43
+ ^^ Add a description.
44
+ expect(subject).to be_good
45
+ end
46
+ RUBY
47
+ end
48
+
49
+ it 'ignores missing description in single-line examples' do
50
+ expect_no_offenses(<<-RUBY)
51
+ it { expect(subject).to be_good }
52
+ RUBY
53
+ end
54
+
55
+ it 'flags example with an empty string for description' do
56
+ expect_offense(<<-RUBY)
57
+ it('') { expect(subject).to be_good }
58
+ ^^ Omit the argument when you want to have auto-generated description.
59
+ RUBY
60
+ end
61
+ end
62
+
63
+ context 'with EnforcedStyle `disallow`' do
64
+ let(:enforced_style) { 'disallow' }
65
+
66
+ it 'flags missing description in multi-line examples' do
67
+ expect_offense(<<-RUBY)
68
+ it do
69
+ ^^ Add a description.
70
+ expect(subject).to be_good
71
+ end
72
+ RUBY
73
+ end
74
+
75
+ it 'flags missing description in single-line examples' do
76
+ expect_offense(<<-RUBY)
77
+ it { expect(subject).to be_good }
78
+ ^^ Add a description.
79
+ RUBY
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,78 @@
1
+ RSpec.describe RuboCop::Cop::RSpec::ExpectChange, :config do
2
+ subject(:cop) { described_class.new(config) }
3
+
4
+ let(:cop_config) do
5
+ { 'EnforcedStyle' => enforced_style }
6
+ end
7
+
8
+ context 'with EnforcedStyle `method_call`' do
9
+ let(:enforced_style) { 'method_call' }
10
+
11
+ it 'finds blocks that contain simple message sending' do
12
+ expect_offense(<<-RUBY)
13
+ it do
14
+ expect(run).to change { User.count }
15
+ ^^^^^^^^^^^^^^^^^^^^^ Prefer `change(User, :count)`.
16
+ end
17
+ RUBY
18
+ end
19
+
20
+ it 'ignores blocks that cannot be converted to obj/attribute pair' do
21
+ expect_no_offenses(<<-RUBY)
22
+ it do
23
+ expect(run).to change { User.sum(:points) }
24
+ end
25
+ RUBY
26
+ end
27
+
28
+ it 'ignores change method of object that happens to receive a block' do
29
+ expect_no_offenses(<<-RUBY)
30
+ it do
31
+ Record.change { User.count }
32
+ end
33
+ RUBY
34
+ end
35
+
36
+ include_examples(
37
+ 'autocorrect',
38
+ 'expect(run).to change { User.count }.by(1)',
39
+ 'expect(run).to change(User, :count).by(1)'
40
+ )
41
+ end
42
+
43
+ context 'with EnforcedStyle `block`' do
44
+ let(:enforced_style) { 'block' }
45
+
46
+ it 'finds change matcher without block' do
47
+ expect_offense(<<-RUBY)
48
+ it do
49
+ expect(run).to change(User, :count)
50
+ ^^^^^^^^^^^^^^^^^^^^ Prefer `change { User.count }`.
51
+ end
52
+ RUBY
53
+ end
54
+
55
+ it 'finds change matcher when receiver is a variable' do
56
+ expect_offense(<<-RUBY)
57
+ it do
58
+ expect(run).to change(user, :count)
59
+ ^^^^^^^^^^^^^^^^^^^^ Prefer `change { user.count }`.
60
+ end
61
+ RUBY
62
+ end
63
+
64
+ it 'ignores methods called change' do
65
+ expect_no_offenses(<<-RUBY)
66
+ it do
67
+ record.change(user, :count)
68
+ end
69
+ RUBY
70
+ end
71
+
72
+ include_examples(
73
+ 'autocorrect',
74
+ 'expect(run).to change(User, :count).by(1)',
75
+ 'expect(run).to change { User.count }.by(1)'
76
+ )
77
+ end
78
+ end
@@ -36,6 +36,24 @@ RSpec.describe RuboCop::Cop::RSpec::InstanceVariable do
36
36
  RUBY
37
37
  end
38
38
 
39
+ it 'ignores an instance variable inside a dynamic class' do
40
+ expect_no_offenses(<<-RUBY)
41
+ describe MyClass do
42
+ let(:object) do
43
+ Class.new(OtherClass) do
44
+ def initialize(resource)
45
+ @resource = resource
46
+ end
47
+
48
+ def serialize
49
+ @resource.to_json
50
+ end
51
+ end
52
+ end
53
+ end
54
+ RUBY
55
+ end
56
+
39
57
  # Regression test for nevir/rubocop-rspec#115
40
58
  it 'ignores instance variables outside of specs' do
41
59
  expect_no_offenses(<<-RUBY, 'lib/source_code.rb')
@@ -90,4 +90,52 @@ RSpec.describe RuboCop::Cop::RSpec::LetBeforeExamples do
90
90
  expect { inspect_source('RSpec.describe(User) do end', 'a_spec.rb') }
91
91
  .not_to raise_error
92
92
  end
93
+
94
+ bad_code = <<-RUBY
95
+ RSpec.describe User do
96
+ include_examples('should be after let')
97
+ context 'another one' do
98
+ let(:foo) { baz }
99
+ include_examples('should be ok')
100
+ end
101
+
102
+ let(:foo) { bar }
103
+ end
104
+ RUBY
105
+
106
+ good_code = <<-RUBY
107
+ RSpec.describe User do
108
+ let(:foo) { bar }
109
+ include_examples('should be after let')
110
+ context 'another one' do
111
+ let(:foo) { baz }
112
+ include_examples('should be ok')
113
+ end
114
+
115
+ end
116
+ RUBY
117
+
118
+ include_examples 'autocorrect', bad_code, good_code
119
+
120
+ bad_code = <<-RUBY
121
+ RSpec.describe User do
122
+ include_examples('should be after let')
123
+
124
+ let(:foo) { (<<-SOURCE) }
125
+ some long text here
126
+ SOURCE
127
+ end
128
+ RUBY
129
+
130
+ good_code = <<-RUBY
131
+ RSpec.describe User do
132
+ let(:foo) { (<<-SOURCE) }
133
+ some long text here
134
+ SOURCE
135
+ include_examples('should be after let')
136
+
137
+ end
138
+ RUBY
139
+
140
+ include_examples 'autocorrect', bad_code, good_code
93
141
  end
@@ -115,6 +115,31 @@ RSpec.describe RuboCop::Cop::RSpec::ReturnFromStub, :config do
115
115
  end
116
116
  RUBY
117
117
  end
118
+
119
+ include_examples 'autocorrect',
120
+ 'allow(Foo).to receive(:bar) { 42 }',
121
+ 'allow(Foo).to receive(:bar).and_return(42)'
122
+
123
+ include_examples 'autocorrect',
124
+ 'allow(Foo).to receive(:bar) { { foo: 42 } }',
125
+ 'allow(Foo).to receive(:bar).and_return({ foo: 42 })'
126
+
127
+ include_examples 'autocorrect',
128
+ 'allow(Foo).to receive(:bar) {}',
129
+ 'allow(Foo).to receive(:bar).and_return(nil)'
130
+
131
+ original = <<-RUBY
132
+ allow(Foo).to receive(:bar) do
133
+ 'You called ' \\
134
+ 'me'
135
+ end
136
+ RUBY
137
+ corrected = <<-RUBY
138
+ allow(Foo).to receive(:bar).and_return('You called ' \\
139
+ 'me')
140
+ RUBY
141
+
142
+ include_examples 'autocorrect', original, corrected
118
143
  end
119
144
 
120
145
  context 'with EnforcedStyle `block`' do
@@ -153,5 +178,45 @@ RSpec.describe RuboCop::Cop::RSpec::ReturnFromStub, :config do
153
178
  end
154
179
  RUBY
155
180
  end
181
+
182
+ include_examples 'autocorrect',
183
+ 'allow(Foo).to receive(:bar).and_return(42)',
184
+ 'allow(Foo).to receive(:bar) { 42 }'
185
+
186
+ include_examples 'autocorrect',
187
+ 'allow(Foo).to receive(:bar).and_return({ foo: 42 })',
188
+ 'allow(Foo).to receive(:bar) { { foo: 42 } }'
189
+
190
+ include_examples 'autocorrect',
191
+ 'allow(Foo).to receive(:bar).and_return(foo: 42)',
192
+ 'allow(Foo).to receive(:bar) { { foo: 42 } }'
193
+
194
+ original = <<-RUBY
195
+ allow(Foo).to receive(:bar).and_return(
196
+ a: 42,
197
+ b: 43
198
+ )
199
+ RUBY
200
+ corrected = <<-RUBY # Not perfect, but good enough.
201
+ allow(Foo).to receive(:bar) { { a: 42,
202
+ b: 43 } }
203
+ RUBY
204
+
205
+ include_examples 'autocorrect', original, corrected
206
+
207
+ include_examples 'autocorrect',
208
+ 'allow(Foo).to receive(:bar).and_return(nil)',
209
+ 'allow(Foo).to receive(:bar) { nil }'
210
+
211
+ original = <<-RUBY
212
+ allow(Foo).to receive(:bar).and_return('You called ' \\
213
+ 'me')
214
+ RUBY
215
+ corrected = <<-RUBY
216
+ allow(Foo).to receive(:bar) { 'You called ' \\
217
+ 'me' }
218
+ RUBY
219
+
220
+ include_examples 'autocorrect', original, corrected
156
221
  end
157
222
  end
@@ -20,13 +20,17 @@ RSpec.describe RuboCop::RSpec::DescriptionExtractor do
20
20
  # Some description
21
21
  #
22
22
  # @note only works with foo
23
- class RuboCop::Cop::RSpec::Foo
23
+ class RuboCop::Cop::RSpec::Foo < RuboCop::Cop::RSpec::Cop
24
24
  # Hello
25
25
  def bar
26
26
  end
27
+
28
+ # :nodoc:
29
+ class HelperClassForFoo
30
+ end
27
31
  end
28
32
 
29
- class RuboCop::Cop::RSpec::Undocumented
33
+ class RuboCop::Cop::RSpec::Undocumented < RuboCop::Cop::RSpec::Cop
30
34
  # Hello
31
35
  def bar
32
36
  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.21.0
4
+ version: 1.22.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-12-13 00:00:00.000000000 Z
13
+ date: 2018-01-10 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubocop
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 0.52.0
21
+ version: 0.52.1
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
- version: 0.52.0
28
+ version: 0.52.1
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: rake
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -120,8 +120,10 @@ files:
120
120
  - lib/rubocop/cop/rspec/empty_line_after_final_let.rb
121
121
  - lib/rubocop/cop/rspec/empty_line_after_subject.rb
122
122
  - lib/rubocop/cop/rspec/example_length.rb
123
+ - lib/rubocop/cop/rspec/example_without_description.rb
123
124
  - lib/rubocop/cop/rspec/example_wording.rb
124
125
  - lib/rubocop/cop/rspec/expect_actual.rb
126
+ - lib/rubocop/cop/rspec/expect_change.rb
125
127
  - lib/rubocop/cop/rspec/expect_in_hook.rb
126
128
  - lib/rubocop/cop/rspec/expect_output.rb
127
129
  - lib/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically.rb
@@ -158,6 +160,7 @@ files:
158
160
  - lib/rubocop/cop/rspec/subject_stub.rb
159
161
  - lib/rubocop/cop/rspec/verified_doubles.rb
160
162
  - lib/rubocop/cop/rspec/void_expect.rb
163
+ - lib/rubocop/cop/rspec_cops.rb
161
164
  - lib/rubocop/rspec.rb
162
165
  - lib/rubocop/rspec/align_let_brace.rb
163
166
  - lib/rubocop/rspec/capybara.rb
@@ -197,8 +200,10 @@ files:
197
200
  - spec/rubocop/cop/rspec/empty_line_after_final_let_spec.rb
198
201
  - spec/rubocop/cop/rspec/empty_line_after_subject_spec.rb
199
202
  - spec/rubocop/cop/rspec/example_length_spec.rb
203
+ - spec/rubocop/cop/rspec/example_without_description_spec.rb
200
204
  - spec/rubocop/cop/rspec/example_wording_spec.rb
201
205
  - spec/rubocop/cop/rspec/expect_actual_spec.rb
206
+ - spec/rubocop/cop/rspec/expect_change_spec.rb
202
207
  - spec/rubocop/cop/rspec/expect_in_hook_spec.rb
203
208
  - spec/rubocop/cop/rspec/expect_output_spec.rb
204
209
  - spec/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically_spec.rb
@@ -293,8 +298,10 @@ test_files:
293
298
  - spec/rubocop/cop/rspec/empty_line_after_final_let_spec.rb
294
299
  - spec/rubocop/cop/rspec/empty_line_after_subject_spec.rb
295
300
  - spec/rubocop/cop/rspec/example_length_spec.rb
301
+ - spec/rubocop/cop/rspec/example_without_description_spec.rb
296
302
  - spec/rubocop/cop/rspec/example_wording_spec.rb
297
303
  - spec/rubocop/cop/rspec/expect_actual_spec.rb
304
+ - spec/rubocop/cop/rspec/expect_change_spec.rb
298
305
  - spec/rubocop/cop/rspec/expect_in_hook_spec.rb
299
306
  - spec/rubocop/cop/rspec/expect_output_spec.rb
300
307
  - spec/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically_spec.rb