rubocop-rspec 1.24.0 → 1.25.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/Gemfile +1 -2
  4. data/README.md +7 -4
  5. data/Rakefile +18 -3
  6. data/config/default.yml +25 -0
  7. data/lib/rubocop-rspec.rb +3 -0
  8. data/lib/rubocop/cop/rspec/be.rb +35 -0
  9. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +34 -0
  10. data/lib/rubocop/cop/rspec/describe_symbol.rb +2 -2
  11. data/lib/rubocop/cop/rspec/empty_example_group.rb +3 -3
  12. data/lib/rubocop/cop/rspec/example_without_description.rb +1 -2
  13. data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +148 -0
  14. data/lib/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically.rb +1 -3
  15. data/lib/rubocop/cop/rspec/factory_bot/static_attribute_defined_dynamically.rb +3 -3
  16. data/lib/rubocop/cop/rspec/instance_variable.rb +2 -2
  17. data/lib/rubocop/cop/rspec/multiple_expectations.rb +2 -2
  18. data/lib/rubocop/cop/rspec/nested_groups.rb +6 -3
  19. data/lib/rubocop/cop/rspec/pending.rb +71 -0
  20. data/lib/rubocop/cop/rspec/predicate_matcher.rb +11 -13
  21. data/lib/rubocop/cop/rspec/return_from_stub.rb +9 -16
  22. data/lib/rubocop/cop/rspec/shared_examples.rb +76 -0
  23. data/lib/rubocop/cop/rspec_cops.rb +4 -0
  24. data/lib/rubocop/rspec/example.rb +1 -1
  25. data/lib/rubocop/rspec/node.rb +19 -0
  26. data/lib/rubocop/rspec/top_level_describe.rb +3 -6
  27. data/lib/rubocop/rspec/version.rb +1 -1
  28. data/rubocop-rspec.gemspec +6 -1
  29. data/spec/rubocop/cop/rspec/be_spec.rb +33 -0
  30. data/spec/rubocop/cop/rspec/capybara/feature_methods_spec.rb +75 -18
  31. data/spec/rubocop/cop/rspec/cop_spec.rb +0 -4
  32. data/spec/rubocop/cop/rspec/described_class_spec.rb +1 -1
  33. data/spec/rubocop/cop/rspec/example_without_description_spec.rb +8 -0
  34. data/spec/rubocop/cop/rspec/factory_bot/create_list_spec.rb +140 -0
  35. data/spec/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically_spec.rb +11 -1
  36. data/spec/rubocop/cop/rspec/nested_groups_spec.rb +15 -0
  37. data/spec/rubocop/cop/rspec/pending_spec.rb +162 -0
  38. data/spec/rubocop/cop/rspec/predicate_matcher_spec.rb +13 -9
  39. data/spec/rubocop/cop/rspec/return_from_stub_spec.rb +9 -0
  40. data/spec/rubocop/cop/rspec/shared_examples_spec.rb +93 -0
  41. data/spec/spec_helper.rb +1 -1
  42. metadata +19 -4
@@ -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.24.0'.freeze
7
+ STRING = '1.25.0'.freeze
8
8
  end
9
9
  end
10
10
  end
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  Code style checking for RSpec files.
9
9
  A plugin for the RuboCop code style enforcing & linting tool.
10
10
  DESCRIPTION
11
- spec.homepage = 'http://github.com/backus/rubocop-rspec'
11
+ spec.homepage = 'https://github.com/rubocop-rspec/rubocop-rspec'
12
12
  spec.authors = ['John Backus', 'Ian MacLeod', 'Nils Gemeinhardt']
13
13
  spec.email = [
14
14
  'johncbackus@gmail.com',
@@ -32,6 +32,11 @@ 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.metadata = {
36
+ 'changelog_uri' => 'https://github.com/rubocop-rspec/rubocop-rspec/blob/master/CHANGELOG.md',
37
+ 'documentation_uri' => 'https://rubocop-rspec.readthedocs.io/'
38
+ }
39
+
35
40
  spec.add_runtime_dependency 'rubocop', '>= 0.53.0'
36
41
 
37
42
  spec.add_development_dependency 'rack'
@@ -0,0 +1,33 @@
1
+ RSpec.describe RuboCop::Cop::RSpec::Be do
2
+ subject(:cop) { described_class.new }
3
+
4
+ it 'registers an offense for `be` without an argument' do
5
+ expect_offense(<<-RUBY)
6
+ it { expect(foo).to be }
7
+ ^^ Don't use `be` without an argument.
8
+ RUBY
9
+ end
10
+
11
+ it 'registers an offense for not_to be' do
12
+ expect_offense(<<-RUBY)
13
+ it { expect(foo).not_to be }
14
+ ^^ Don't use `be` without an argument.
15
+ it { expect(foo).to_not be }
16
+ ^^ Don't use `be` without an argument.
17
+ RUBY
18
+ end
19
+
20
+ it 'allows `be` with an argument' do
21
+ expect_no_offenses(<<-RUBY)
22
+ it { expect(foo).to be(1) }
23
+ it { expect(foo).not_to be(0) }
24
+ RUBY
25
+ end
26
+
27
+ it 'allows specific `be_` matchers' do
28
+ expect_no_offenses(<<-RUBY)
29
+ it { expect(foo).to be_truthy }
30
+ it { expect(foo).not_to be_falsy }
31
+ RUBY
32
+ end
33
+ end
@@ -1,38 +1,50 @@
1
- RSpec.describe RuboCop::Cop::RSpec::Capybara::FeatureMethods do
2
- subject(:cop) { described_class.new }
1
+ RSpec.describe RuboCop::Cop::RSpec::Capybara::FeatureMethods, :config do
2
+ subject(:cop) { described_class.new(config) }
3
+
4
+ let(:cop_config) { { 'EnabledMethods' => [] } }
3
5
 
4
6
  it 'flags violations for `background`' do
5
7
  expect_offense(<<-RUBY)
6
- background do; end
7
- ^^^^^^^^^^ Use `before` instead of `background`.
8
+ describe 'some feature' do
9
+ background do; end
10
+ ^^^^^^^^^^ Use `before` instead of `background`.
11
+ end
8
12
  RUBY
9
13
  end
10
14
 
11
15
  it 'flags violations for `scenario`' do
12
16
  expect_offense(<<-RUBY)
13
- scenario 'Foo' do; end
14
- ^^^^^^^^ Use `it` instead of `scenario`.
17
+ RSpec.describe 'some feature' do
18
+ scenario 'Foo' do; end
19
+ ^^^^^^^^ Use `it` instead of `scenario`.
20
+ end
15
21
  RUBY
16
22
  end
17
23
 
18
24
  it 'flags violations for `xscenario`' do
19
25
  expect_offense(<<-RUBY)
20
- RSpec.xscenario 'Foo' do; end
21
- ^^^^^^^^^ Use `xit` instead of `xscenario`.
26
+ describe 'Foo' do
27
+ RSpec.xscenario 'Baz' do; end
28
+ ^^^^^^^^^ Use `xit` instead of `xscenario`.
29
+ end
22
30
  RUBY
23
31
  end
24
32
 
25
33
  it 'flags violations for `given`' do
26
34
  expect_offense(<<-RUBY)
27
- given(:foo) { :foo }
28
- ^^^^^ Use `let` instead of `given`.
35
+ RSpec.describe 'Foo' do
36
+ given(:foo) { :foo }
37
+ ^^^^^ Use `let` instead of `given`.
38
+ end
29
39
  RUBY
30
40
  end
31
41
 
32
42
  it 'flags violations for `given!`' do
33
43
  expect_offense(<<-RUBY)
34
- given!(:foo) { :foo }
35
- ^^^^^^ Use `let!` instead of `given!`.
44
+ describe 'Foo' do
45
+ given!(:foo) { :foo }
46
+ ^^^^^^ Use `let!` instead of `given!`.
47
+ end
36
48
  RUBY
37
49
  end
38
50
 
@@ -53,10 +65,55 @@ RSpec.describe RuboCop::Cop::RSpec::Capybara::FeatureMethods do
53
65
  RUBY
54
66
  end
55
67
 
56
- include_examples 'autocorrect', 'background { }', 'before { }'
57
- include_examples 'autocorrect', 'scenario { }', 'it { }'
58
- include_examples 'autocorrect', 'xscenario { }', 'xit { }'
59
- include_examples 'autocorrect', 'given(:foo) { }', 'let(:foo) { }'
60
- include_examples 'autocorrect', 'given!(:foo) { }', 'let!(:foo) { }'
61
- include_examples 'autocorrect', 'RSpec.feature { }', 'RSpec.describe { }'
68
+ it 'ignores feature calls outside spec' do
69
+ expect_no_offenses(<<-RUBY)
70
+ FactoryBot.define do
71
+ factory :company do
72
+ feature { "a company" }
73
+ background { Faker::Lorem.sentence }
74
+ end
75
+ end
76
+ RUBY
77
+ end
78
+
79
+ context 'with configured `EnabledMethods`' do
80
+ let(:cop_config) { { 'EnabledMethods' => %w[feature] } }
81
+
82
+ it 'ignores usage of the enabled method' do
83
+ expect_no_offenses(<<-RUBY)
84
+ RSpec.feature 'feature is enabled' do; end
85
+ RUBY
86
+ end
87
+
88
+ it 'flags other methods' do
89
+ expect_offense(<<-RUBY)
90
+ RSpec.feature 'feature is enabled' do
91
+ given(:foo) { :foo }
92
+ ^^^^^ Use `let` instead of `given`.
93
+ end
94
+ RUBY
95
+ end
96
+ end
97
+
98
+ shared_examples 'autocorrect_spec' do |original, corrected|
99
+ original = <<-RUBY
100
+ describe Foo do
101
+ #{original}
102
+ end
103
+ RUBY
104
+ corrected = <<-RUBY
105
+ describe Foo do
106
+ #{corrected}
107
+ end
108
+ RUBY
109
+
110
+ include_examples 'autocorrect', original, corrected
111
+ end
112
+
113
+ include_examples 'autocorrect_spec', 'background { }', 'before { }'
114
+ include_examples 'autocorrect_spec', 'scenario { }', 'it { }'
115
+ include_examples 'autocorrect_spec', 'xscenario { }', 'xit { }'
116
+ include_examples 'autocorrect_spec', 'given(:foo) { }', 'let(:foo) { }'
117
+ include_examples 'autocorrect_spec', 'given!(:foo) { }', 'let!(:foo) { }'
118
+ include_examples 'autocorrect_spec', 'RSpec.feature { }', 'RSpec.describe { }'
62
119
  end
@@ -23,10 +23,6 @@ RSpec.describe RuboCop::Cop::RSpec::Cop do
23
23
  stub_const('RuboCop::RSpec', Module.new)
24
24
  # rubocop:disable ClassAndModuleChildren
25
25
  class RuboCop::RSpec::FakeCop < described_class
26
- def self.name
27
- 'RuboCop::RSpec::FakeCop'
28
- end
29
-
30
26
  def on_send(node)
31
27
  add_offense(node, location: :expression, message: 'I flag everything')
32
28
  end
@@ -190,7 +190,7 @@ RSpec.describe RuboCop::Cop::RSpec::DescribedClass, :config do
190
190
  end
191
191
 
192
192
  it 'checks for the use of described class with module' do
193
- skip
193
+ pending
194
194
 
195
195
  expect_offense(<<-RUBY)
196
196
  module MyNamespace
@@ -78,5 +78,13 @@ RSpec.describe RuboCop::Cop::RSpec::ExampleWithoutDescription, :config do
78
78
  ^^ Add a description.
79
79
  RUBY
80
80
  end
81
+
82
+ it 'ignores `it` with a description' do
83
+ expect_no_offenses(<<-RUBY)
84
+ it 'is good' do
85
+ expect(subject).to be_good
86
+ end
87
+ RUBY
88
+ end
81
89
  end
82
90
  end
@@ -0,0 +1,140 @@
1
+ RSpec.describe RuboCop::Cop::RSpec::FactoryBot::CreateList, :config do
2
+ subject(:cop) { described_class.new(config) }
3
+
4
+ let(:cop_config) do
5
+ { 'EnforcedStyle' => enforced_style }
6
+ end
7
+
8
+ context 'when EnforcedStyle is :create_list' do
9
+ let(:enforced_style) { :create_list }
10
+
11
+ it 'flags usage of n.times with no arguments' do
12
+ expect_offense(<<-RUBY)
13
+ 3.times { create :user }
14
+ ^^^^^^^ Prefer create_list.
15
+ RUBY
16
+ end
17
+
18
+ it 'flags usage of n.times when FactoryGirl.create is used' do
19
+ expect_offense(<<-RUBY)
20
+ 3.times { FactoryGirl.create :user }
21
+ ^^^^^^^ Prefer create_list.
22
+ RUBY
23
+ end
24
+
25
+ it 'flags usage of n.times when FactoryBot.create is used' do
26
+ expect_offense(<<-RUBY)
27
+ 3.times { FactoryBot.create :user }
28
+ ^^^^^^^ Prefer create_list.
29
+ RUBY
30
+ end
31
+
32
+ it 'ignores create method of other object' do
33
+ expect_no_offenses(<<-RUBY)
34
+ 3.times { SomeFactory.create :user }
35
+ RUBY
36
+ end
37
+
38
+ it 'ignores create in other block' do
39
+ expect_no_offenses(<<-RUBY)
40
+ allow(User).to receive(:create) { create :user }
41
+ RUBY
42
+ end
43
+
44
+ it 'flags n.times with argument' do
45
+ expect_offense(<<-RUBY)
46
+ 3.times { |n| create :user, created_at: n.days.ago }
47
+ ^^^^^^^ Prefer create_list.
48
+ RUBY
49
+ end
50
+
51
+ it 'ignores n.times when there is no create call inside' do
52
+ expect_no_offenses(<<-RUBY)
53
+ 3.times { do_something }
54
+ RUBY
55
+ end
56
+
57
+ it 'ignores n.times when there is other calls but create' do
58
+ expect_no_offenses(<<-RUBY)
59
+ used_passwords = []
60
+ 3.times do
61
+ u = create :user
62
+ expect(used_passwords).not_to include(u.password)
63
+ used_passwords << u.password
64
+ end
65
+ RUBY
66
+ end
67
+
68
+ it 'flags FactoryGirl.create calls with a block' do
69
+ expect_offense(<<-RUBY)
70
+ 3.times do
71
+ ^^^^^^^ Prefer create_list.
72
+ create(:user) { |user| create :account, user: user }
73
+ end
74
+ RUBY
75
+ end
76
+
77
+ include_examples 'autocorrect',
78
+ '5.times { create :user }',
79
+ 'create_list :user, 5'
80
+
81
+ include_examples 'autocorrect',
82
+ '5.times { create(:user, :trait) }',
83
+ 'create_list(:user, 5, :trait)'
84
+
85
+ include_examples 'autocorrect',
86
+ '5.times { create :user, :trait, key: val }',
87
+ 'create_list :user, 5, :trait, key: val'
88
+
89
+ include_examples 'autocorrect',
90
+ '5.times { FactoryGirl.create :user }',
91
+ 'FactoryGirl.create_list :user, 5'
92
+ end
93
+
94
+ context 'when EnforcedStyle is :n_times' do
95
+ let(:enforced_style) { :n_times }
96
+
97
+ it 'flags usage of create_list' do
98
+ expect_offense(<<-RUBY)
99
+ create_list :user, 3
100
+ ^^^^^^^^^^^ Prefer 3.times.
101
+ RUBY
102
+ end
103
+
104
+ it 'flags usage of FactoryGirl.create_list' do
105
+ expect_offense(<<-RUBY)
106
+ FactoryGirl.create_list :user, 3
107
+ ^^^^^^^^^^^ Prefer 3.times.
108
+ RUBY
109
+ end
110
+
111
+ it 'flags usage of FactoryGirl.create_list with a block' do
112
+ expect_offense(<<-RUBY)
113
+ FactoryGirl.create_list(:user, 3) { |user| user.points = rand(1000) }
114
+ ^^^^^^^^^^^ Prefer 3.times.
115
+ RUBY
116
+ end
117
+
118
+ it 'ignores create method of other object' do
119
+ expect_no_offenses(<<-RUBY)
120
+ SomeFactory.create_list :user, 3
121
+ RUBY
122
+ end
123
+
124
+ include_examples 'autocorrect',
125
+ 'create_list :user, 5',
126
+ '5.times { create :user }'
127
+
128
+ include_examples 'autocorrect',
129
+ 'create_list(:user, 5, :trait)',
130
+ '5.times { create(:user, :trait) }'
131
+
132
+ include_examples 'autocorrect',
133
+ 'create_list :user, 5, :trait, key: val',
134
+ '5.times { create :user, :trait, key: val }'
135
+
136
+ include_examples 'autocorrect',
137
+ 'FactoryGirl.create_list :user, 5',
138
+ '5.times { FactoryGirl.create :user }'
139
+ end
140
+ end
@@ -55,7 +55,6 @@ RSpec.describe RuboCop::Cop::RSpec::FactoryBot::DynamicAttributeDefinedStaticall
55
55
  comments_count 0
56
56
  title "Static"
57
57
  description { FFaker::Lorem.paragraph(10) }
58
- tag Tag::MAGIC
59
58
  recent_statuses [:published, :draft]
60
59
  meta_tags(like_count: 2)
61
60
  other_tags({ foo: nil })
@@ -67,6 +66,17 @@ RSpec.describe RuboCop::Cop::RSpec::FactoryBot::DynamicAttributeDefinedStaticall
67
66
  RUBY
68
67
  end
69
68
 
69
+ it 'accepts const as a static value' do
70
+ expect_no_offenses(<<-RUBY)
71
+ #{factory_bot}.define do
72
+ factory(:post, class: PrivatePost) do
73
+ tag Tag::MAGIC
74
+ options({priority: Priotity::HIGH})
75
+ end
76
+ end
77
+ RUBY
78
+ end
79
+
70
80
  it 'does not add offense if out of factory girl block' do
71
81
  expect_no_offenses(<<-RUBY)
72
82
  status [:draft, :published].sample
@@ -22,6 +22,21 @@ RSpec.describe RuboCop::Cop::RSpec::NestedGroups, :config do
22
22
  RUBY
23
23
  end
24
24
 
25
+ it 'support --auto-gen-config' do
26
+ inspect_source(<<-RUBY, 'spec/foo_spec.rb')
27
+ describe MyClass do
28
+ context 'when foo' do
29
+ context 'when bar' do
30
+ context 'when baz' do
31
+ end
32
+ end
33
+ end
34
+ end
35
+ RUBY
36
+
37
+ expect(cop.config_to_allow_offenses).to eq('Max' => 4)
38
+ end
39
+
25
40
  it 'ignores non-spec context methods' do
26
41
  expect_no_offenses(<<-RUBY)
27
42
  class MyThingy
@@ -0,0 +1,162 @@
1
+ RSpec.describe RuboCop::Cop::RSpec::Pending do
2
+ subject(:cop) { described_class.new }
3
+
4
+ it 'flags xcontext' do
5
+ expect_offense(<<-RUBY)
6
+ xcontext 'test' do
7
+ ^^^^^^^^^^^^^^^ Pending spec found.
8
+ end
9
+ RUBY
10
+ end
11
+
12
+ it 'flags xdescribe' do
13
+ expect_offense(<<-RUBY)
14
+ xdescribe 'test' do
15
+ ^^^^^^^^^^^^^^^^ Pending spec found.
16
+ end
17
+ RUBY
18
+ end
19
+
20
+ it 'flags xexample' do
21
+ expect_offense(<<-RUBY)
22
+ xexample 'test' do
23
+ ^^^^^^^^^^^^^^^ Pending spec found.
24
+ end
25
+ RUBY
26
+ end
27
+
28
+ it 'flags xfeature' do
29
+ expect_offense(<<-RUBY)
30
+ xfeature 'test' do
31
+ ^^^^^^^^^^^^^^^ Pending spec found.
32
+ end
33
+ RUBY
34
+ end
35
+
36
+ it 'flags xit' do
37
+ expect_offense(<<-RUBY)
38
+ xit 'test' do
39
+ ^^^^^^^^^^ Pending spec found.
40
+ end
41
+ RUBY
42
+ end
43
+
44
+ it 'flags xscenario' do
45
+ expect_offense(<<-RUBY)
46
+ xscenario 'test' do
47
+ ^^^^^^^^^^^^^^^^ Pending spec found.
48
+ end
49
+ RUBY
50
+ end
51
+
52
+ it 'flags xspecify' do
53
+ expect_offense(<<-RUBY)
54
+ xspecify 'test' do
55
+ ^^^^^^^^^^^^^^^ Pending spec found.
56
+ end
57
+ RUBY
58
+ end
59
+
60
+ it 'flags skip inside of an it' do
61
+ expect_offense(<<-RUBY)
62
+ it 'test' do
63
+ skip
64
+ ^^^^ Pending spec found.
65
+ end
66
+ RUBY
67
+ end
68
+
69
+ it 'flags skip blocks' do
70
+ expect_offense(<<-RUBY)
71
+ skip 'test' do
72
+ ^^^^^^^^^^^ Pending spec found.
73
+ end
74
+ RUBY
75
+ end
76
+
77
+ it 'flags blocks with skip symbol metadata' do
78
+ expect_offense(<<-RUBY)
79
+ it 'test', :skip do
80
+ ^^^^^^^^^^^^^^^^ Pending spec found.
81
+ end
82
+ RUBY
83
+ end
84
+
85
+ it 'flags blocks with pending symbol metadata' do
86
+ expect_offense(<<-RUBY)
87
+ it 'test', :pending do
88
+ ^^^^^^^^^^^^^^^^^^^ Pending spec found.
89
+ end
90
+ RUBY
91
+ end
92
+
93
+ it 'flags blocks with skip: true metadata' do
94
+ expect_offense(<<-RUBY)
95
+ it 'test', skip: true do
96
+ ^^^^^^^^^^^^^^^^^^^^^ Pending spec found.
97
+ end
98
+ RUBY
99
+ end
100
+
101
+ it 'flags pending blocks' do
102
+ expect_offense(<<-RUBY)
103
+ pending 'test' do
104
+ ^^^^^^^^^^^^^^ Pending spec found.
105
+ end
106
+ RUBY
107
+ end
108
+
109
+ it 'does not flag describe' do
110
+ expect_no_offenses(<<-RUBY)
111
+ describe 'test' do; end
112
+ RUBY
113
+ end
114
+
115
+ it 'does not flag example' do
116
+ expect_no_offenses(<<-RUBY)
117
+ example 'test' do; end
118
+ RUBY
119
+ end
120
+
121
+ it 'does not flag scenario' do
122
+ expect_no_offenses(<<-RUBY)
123
+ scenario 'test' do; end
124
+ RUBY
125
+ end
126
+
127
+ it 'does not flag specify' do
128
+ expect_no_offenses(<<-RUBY)
129
+ specify 'test' do; end
130
+ RUBY
131
+ end
132
+
133
+ it 'does not flag feature' do
134
+ expect_no_offenses(<<-RUBY)
135
+ feature 'test' do; end
136
+ RUBY
137
+ end
138
+
139
+ it 'does not flag context' do
140
+ expect_no_offenses(<<-RUBY)
141
+ context 'test' do; end
142
+ RUBY
143
+ end
144
+
145
+ it 'does not flag it' do
146
+ expect_no_offenses(<<-RUBY)
147
+ it 'test' do; end
148
+ RUBY
149
+ end
150
+
151
+ it 'does not flag it with skip: false metadata' do
152
+ expect_no_offenses(<<-RUBY)
153
+ it 'test', skip: false do; end
154
+ RUBY
155
+ end
156
+
157
+ it 'does not flag example_group' do
158
+ expect_no_offenses(<<-RUBY)
159
+ example_group 'test' do; end
160
+ RUBY
161
+ end
162
+ end