rubocop-rspec 1.21.0 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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