rubocop-rspec 1.24.0 → 1.25.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 (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