rubocop-rspec 1.27.0 → 1.28.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +1 -1
- data/config/default.yml +15 -10
- data/lib/rubocop/cop/rspec/describe_method.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_example_group.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +2 -4
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +1 -3
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +1 -3
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +1 -3
- data/lib/rubocop/cop/rspec/example_without_description.rb +3 -4
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +8 -23
- data/lib/rubocop/cop/rspec/expect_output.rb +0 -2
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +146 -0
- data/lib/rubocop/cop/rspec/instance_spy.rb +0 -2
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/leading_subject.rb +1 -6
- data/lib/rubocop/cop/rspec/let_before_examples.rb +0 -2
- data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +35 -0
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +4 -4
- data/lib/rubocop/cop/rspec/nested_groups.rb +1 -1
- data/lib/rubocop/cop/rspec/pending.rb +1 -1
- data/lib/rubocop/cop/rspec/receive_never.rb +43 -0
- data/lib/rubocop/cop/rspec/scattered_let.rb +0 -2
- data/lib/rubocop/cop/rspec/shared_context.rb +3 -3
- data/lib/rubocop/cop/rspec/void_expect.rb +1 -1
- data/lib/rubocop/cop/rspec_cops.rb +4 -3
- data/lib/rubocop/rspec/align_let_brace.rb +1 -3
- data/lib/rubocop/rspec/blank_line_separation.rb +6 -0
- data/lib/rubocop/rspec/example_group.rb +0 -7
- data/lib/rubocop/rspec/language/node_pattern.rb +6 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- data/rubocop-rspec.gemspec +2 -2
- data/spec/project/project_requires_spec.rb +13 -3
- data/spec/rubocop/cop/rspec/before_after_all_spec.rb +2 -2
- data/spec/rubocop/cop/rspec/empty_line_after_example_group_spec.rb +15 -0
- data/spec/rubocop/cop/rspec/factory_bot/attribute_defined_statically_spec.rb +156 -0
- data/spec/rubocop/cop/rspec/let_before_examples_spec.rb +0 -5
- data/spec/rubocop/cop/rspec/missing_example_group_argument_spec.rb +55 -0
- data/spec/rubocop/cop/rspec/overwriting_setup_spec.rb +0 -5
- data/spec/rubocop/cop/rspec/receive_never_spec.rb +45 -0
- data/spec/rubocop/cop/rspec/scattered_let_spec.rb +0 -5
- data/spec/shared/smoke_test_examples.rb +25 -0
- data/spec/smoke_tests/empty_spec.rb +0 -0
- data/spec/smoke_tests/factory_bot_spec.rb +11 -0
- data/spec/smoke_tests/no_tests_spec.rb +4 -0
- data/spec/smoke_tests/weird_rspec_spec.rb +233 -0
- data/spec/spec_helper.rb +4 -0
- metadata +24 -11
- data/lib/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically.rb +0 -93
- data/lib/rubocop/cop/rspec/factory_bot/static_attribute_defined_dynamically.rb +0 -81
- data/spec/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically_spec.rb +0 -139
- data/spec/rubocop/cop/rspec/factory_bot/static_attribute_defined_dynamically_spec.rb +0 -107
@@ -1,93 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module RSpec
|
6
|
-
module FactoryBot
|
7
|
-
# Prefer declaring dynamic attribute values in a block.
|
8
|
-
#
|
9
|
-
# @see StaticAttributeDefinedDynamically
|
10
|
-
#
|
11
|
-
# @example
|
12
|
-
# # bad
|
13
|
-
# kind [:active, :rejected].sample
|
14
|
-
#
|
15
|
-
# # good
|
16
|
-
# kind { [:active, :rejected].sample }
|
17
|
-
#
|
18
|
-
# # bad
|
19
|
-
# closed_at 1.day.from_now
|
20
|
-
#
|
21
|
-
# # good
|
22
|
-
# closed_at { 1.day.from_now }
|
23
|
-
class DynamicAttributeDefinedStatically < Cop
|
24
|
-
MSG = 'Use a block to set a dynamic value to an attribute.'.freeze
|
25
|
-
|
26
|
-
def_node_matcher :value_matcher, <<-PATTERN
|
27
|
-
(send nil? _ $...)
|
28
|
-
PATTERN
|
29
|
-
|
30
|
-
def_node_search :factory_attributes, <<-PATTERN
|
31
|
-
(block (send nil? {:factory :trait} ...) _ { (begin $...) $(send ...) } )
|
32
|
-
PATTERN
|
33
|
-
|
34
|
-
def on_block(node)
|
35
|
-
factory_attributes(node).to_a.flatten.each do |attribute|
|
36
|
-
next if static_or_proc?(attribute)
|
37
|
-
add_offense(attribute, location: :expression)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def autocorrect(node)
|
42
|
-
if !method_uses_parens?(node.location)
|
43
|
-
autocorrect_without_parens(node)
|
44
|
-
elsif value_hash_without_braces?(node.descendants.first)
|
45
|
-
autocorrect_hash_without_braces(node)
|
46
|
-
else
|
47
|
-
autocorrect_replacing_parens(node)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def static_or_proc?(attribute)
|
54
|
-
value_matcher(attribute).to_a.all? do |value|
|
55
|
-
value.block_pass_type? || value.recursive_literal_or_const?
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def value_hash_without_braces?(node)
|
60
|
-
node.hash_type? && !node.braces?
|
61
|
-
end
|
62
|
-
|
63
|
-
def method_uses_parens?(location)
|
64
|
-
return false unless location.begin && location.end
|
65
|
-
location.begin.source == '(' && location.end.source == ')'
|
66
|
-
end
|
67
|
-
|
68
|
-
def autocorrect_hash_without_braces(node)
|
69
|
-
autocorrect_replacing_parens(node, ' { { ', ' } }')
|
70
|
-
end
|
71
|
-
|
72
|
-
def autocorrect_replacing_parens(node,
|
73
|
-
start_token = ' { ',
|
74
|
-
end_token = ' }')
|
75
|
-
lambda do |corrector|
|
76
|
-
corrector.replace(node.location.begin, start_token)
|
77
|
-
corrector.replace(node.location.end, end_token)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def autocorrect_without_parens(node)
|
82
|
-
lambda do |corrector|
|
83
|
-
arguments = node.descendants.first
|
84
|
-
expression = arguments.location.expression
|
85
|
-
corrector.insert_before(expression, '{ ')
|
86
|
-
corrector.insert_after(expression, ' }')
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module RSpec
|
6
|
-
module FactoryBot
|
7
|
-
# Prefer declaring static attribute values without a block.
|
8
|
-
#
|
9
|
-
# @see DynamicAttributeDefinedStatically
|
10
|
-
#
|
11
|
-
# @example
|
12
|
-
# # bad
|
13
|
-
# kind { :static }
|
14
|
-
#
|
15
|
-
# # good
|
16
|
-
# kind :static
|
17
|
-
#
|
18
|
-
# # bad
|
19
|
-
# comments_count { 0 }
|
20
|
-
#
|
21
|
-
# # good
|
22
|
-
# comments_count 0
|
23
|
-
#
|
24
|
-
# # bad
|
25
|
-
# type { User::MAGIC }
|
26
|
-
#
|
27
|
-
# # good
|
28
|
-
# type User::MAGIC
|
29
|
-
class StaticAttributeDefinedDynamically < Cop
|
30
|
-
MSG = 'Do not use a block to set a static value ' \
|
31
|
-
'to an attribute.'.freeze
|
32
|
-
|
33
|
-
def_node_matcher :block_value_matcher, <<-PATTERN
|
34
|
-
(block (send nil? _) _ $...)
|
35
|
-
PATTERN
|
36
|
-
|
37
|
-
def_node_search :factory_attributes, <<-PATTERN
|
38
|
-
(block (send nil? { :factory :trait } ...) _ { (begin $...) $(send ...) $(block ...) } )
|
39
|
-
PATTERN
|
40
|
-
|
41
|
-
def on_block(node)
|
42
|
-
factory_attributes(node).to_a.flatten.each do |attribute|
|
43
|
-
values = block_value_matcher(attribute)
|
44
|
-
next if values.to_a.all? { |v| dynamic?(v) }
|
45
|
-
add_offense(attribute, location: :expression)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def autocorrect(node)
|
50
|
-
lambda do |corrector|
|
51
|
-
corrector.replace(
|
52
|
-
node.loc.expression,
|
53
|
-
autocorrected_source(node)
|
54
|
-
)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def dynamic?(node)
|
61
|
-
node && !node.recursive_literal_or_const?
|
62
|
-
end
|
63
|
-
|
64
|
-
def autocorrected_source(node)
|
65
|
-
"#{node.send_node.source}#{autocorrected_attribute(node.body)}"
|
66
|
-
end
|
67
|
-
|
68
|
-
def autocorrected_attribute(body)
|
69
|
-
if body.nil?
|
70
|
-
' nil'
|
71
|
-
elsif body.hash_type?
|
72
|
-
"(#{body.source})"
|
73
|
-
else
|
74
|
-
' ' + body.source
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
@@ -1,139 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# rubocop:disable Metrics/LineLength
|
4
|
-
RSpec.describe RuboCop::Cop::RSpec::FactoryBot::DynamicAttributeDefinedStatically do
|
5
|
-
# rubocop:enable Metrics/LineLength
|
6
|
-
|
7
|
-
subject(:cop) { described_class.new(config) }
|
8
|
-
|
9
|
-
let(:config) { RuboCop::Config.new }
|
10
|
-
|
11
|
-
%w[FactoryBot FactoryGirl].each do |factory_bot|
|
12
|
-
context "when using #{factory_bot}" do
|
13
|
-
it 'registers an offense for offending code' do
|
14
|
-
expect_offense(<<-RUBY)
|
15
|
-
#{factory_bot}.define do
|
16
|
-
factory :post do
|
17
|
-
published_at 1.day.from_now
|
18
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use a block to set a dynamic value to an attribute.
|
19
|
-
status [:draft, :published].sample
|
20
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use a block to set a dynamic value to an attribute.
|
21
|
-
created_at 1.day.ago
|
22
|
-
^^^^^^^^^^^^^^^^^^^^ Use a block to set a dynamic value to an attribute.
|
23
|
-
update_times [Time.current]
|
24
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use a block to set a dynamic value to an attribute.
|
25
|
-
meta_tags(foo: Time.current)
|
26
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use a block to set a dynamic value to an attribute.
|
27
|
-
end
|
28
|
-
end
|
29
|
-
RUBY
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'registers an offense in a trait' do
|
33
|
-
expect_offense(<<-RUBY)
|
34
|
-
#{factory_bot}.define do
|
35
|
-
factory :post do
|
36
|
-
title "Something"
|
37
|
-
trait :published do
|
38
|
-
published_at 1.day.from_now
|
39
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use a block to set a dynamic value to an attribute.
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
RUBY
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'accepts valid factory definitions' do
|
47
|
-
expect_no_offenses(<<-RUBY)
|
48
|
-
#{factory_bot}.define do
|
49
|
-
factory :post do
|
50
|
-
trait :published do
|
51
|
-
published_at { 1.day.from_now }
|
52
|
-
end
|
53
|
-
created_at { 1.day.ago }
|
54
|
-
status :draft
|
55
|
-
comments_count 0
|
56
|
-
title "Static"
|
57
|
-
description { FFaker::Lorem.paragraph(10) }
|
58
|
-
recent_statuses [:published, :draft]
|
59
|
-
meta_tags(like_count: 2)
|
60
|
-
other_tags({ foo: nil })
|
61
|
-
|
62
|
-
before(:create, &:initialize_something)
|
63
|
-
after(:create, &:rebuild_cache)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
RUBY
|
67
|
-
end
|
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
|
-
|
80
|
-
it 'does not add offense if out of factory girl block' do
|
81
|
-
expect_no_offenses(<<-RUBY)
|
82
|
-
status [:draft, :published].sample
|
83
|
-
published_at 1.day.from_now
|
84
|
-
created_at 1.day.ago
|
85
|
-
update_times [Time.current]
|
86
|
-
meta_tags(foo: Time.current)
|
87
|
-
RUBY
|
88
|
-
end
|
89
|
-
|
90
|
-
it 'accepts valid sequence definition' do
|
91
|
-
expect_no_offenses(<<-RUBY)
|
92
|
-
#{factory_bot}.define do
|
93
|
-
factory :post do
|
94
|
-
sequence :negative_numbers, &:-@
|
95
|
-
end
|
96
|
-
end
|
97
|
-
RUBY
|
98
|
-
end
|
99
|
-
|
100
|
-
bad = <<-RUBY
|
101
|
-
#{factory_bot}.define do
|
102
|
-
factory :post do
|
103
|
-
status([:draft, :published].sample)
|
104
|
-
published_at 1.day.from_now
|
105
|
-
created_at(1.day.ago)
|
106
|
-
updated_at Time.current
|
107
|
-
update_times [Time.current]
|
108
|
-
meta_tags(foo: Time.current)
|
109
|
-
other_tags({ foo: Time.current })
|
110
|
-
|
111
|
-
trait :old do
|
112
|
-
published_at 1.week.ago
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
RUBY
|
117
|
-
|
118
|
-
corrected = <<-RUBY
|
119
|
-
#{factory_bot}.define do
|
120
|
-
factory :post do
|
121
|
-
status { [:draft, :published].sample }
|
122
|
-
published_at { 1.day.from_now }
|
123
|
-
created_at { 1.day.ago }
|
124
|
-
updated_at { Time.current }
|
125
|
-
update_times { [Time.current] }
|
126
|
-
meta_tags { { foo: Time.current } }
|
127
|
-
other_tags { { foo: Time.current } }
|
128
|
-
|
129
|
-
trait :old do
|
130
|
-
published_at { 1.week.ago }
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
RUBY
|
135
|
-
|
136
|
-
include_examples 'autocorrect', bad, corrected
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
@@ -1,107 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# rubocop:disable Metrics/LineLength
|
4
|
-
RSpec.describe RuboCop::Cop::RSpec::FactoryBot::StaticAttributeDefinedDynamically do
|
5
|
-
# rubocop:enable Metrics/LineLength
|
6
|
-
|
7
|
-
subject(:cop) { described_class.new(config) }
|
8
|
-
|
9
|
-
let(:config) { RuboCop::Config.new }
|
10
|
-
|
11
|
-
%w[FactoryBot FactoryGirl].each do |factory_bot|
|
12
|
-
context "when using #{factory_bot}" do
|
13
|
-
it 'registers an offense for offending code' do
|
14
|
-
expect_offense(<<-RUBY)
|
15
|
-
#{factory_bot}.define do
|
16
|
-
factory :post do
|
17
|
-
kind { :static }
|
18
|
-
^^^^^^^^^^^^^^^^ Do not use a block to set a static value to an attribute.
|
19
|
-
comments_count { 0 }
|
20
|
-
^^^^^^^^^^^^^^^^^^^^ Do not use a block to set a static value to an attribute.
|
21
|
-
type { User::MAGIC }
|
22
|
-
^^^^^^^^^^^^^^^^^^^^ Do not use a block to set a static value to an attribute.
|
23
|
-
description { nil }
|
24
|
-
^^^^^^^^^^^^^^^^^^^ Do not use a block to set a static value to an attribute.
|
25
|
-
recent_statuses { [:published, :draft] }
|
26
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use a block to set a static value to an attribute.
|
27
|
-
meta_tags { { foo: 1 } }
|
28
|
-
^^^^^^^^^^^^^^^^^^^^^^^^ Do not use a block to set a static value to an attribute.
|
29
|
-
title {}
|
30
|
-
^^^^^^^^ Do not use a block to set a static value to an attribute.
|
31
|
-
end
|
32
|
-
end
|
33
|
-
RUBY
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'registers an offense in a trait' do
|
37
|
-
expect_offense(<<-RUBY)
|
38
|
-
#{factory_bot}.define do
|
39
|
-
factory :post do
|
40
|
-
title "Something"
|
41
|
-
trait :something_else do
|
42
|
-
title { "Something Else" }
|
43
|
-
^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use a block to set a static value to an attribute.
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
RUBY
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'accepts valid factory definitions' do
|
51
|
-
expect_no_offenses(<<-RUBY)
|
52
|
-
#{factory_bot}.define do
|
53
|
-
factory :post do
|
54
|
-
trait :something_else do
|
55
|
-
title "Something Else"
|
56
|
-
end
|
57
|
-
title "Something"
|
58
|
-
comments_count 0
|
59
|
-
description { FFaker::Lorem.paragraph(10) }
|
60
|
-
tag Tag::MAGIC
|
61
|
-
recent_updates { [Time.current] }
|
62
|
-
meta_tags { { first_like: Time.current } }
|
63
|
-
before(:create) { 'foo' }
|
64
|
-
end
|
65
|
-
end
|
66
|
-
RUBY
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'does not add offense if out of factory girl block' do
|
70
|
-
expect_no_offenses(<<-RUBY)
|
71
|
-
kind { :static }
|
72
|
-
comments_count { 0 }
|
73
|
-
type { User::MAGIC }
|
74
|
-
description { nil }
|
75
|
-
RUBY
|
76
|
-
end
|
77
|
-
|
78
|
-
bad = <<-RUBY
|
79
|
-
#{factory_bot}.define do
|
80
|
-
factory :post do
|
81
|
-
comments_count { 0 }
|
82
|
-
type { User::MAGIC }
|
83
|
-
description { nil }
|
84
|
-
title {}
|
85
|
-
recent_statuses { [:published, :draft] }
|
86
|
-
meta_tags { { foo: 1 } }
|
87
|
-
end
|
88
|
-
end
|
89
|
-
RUBY
|
90
|
-
|
91
|
-
corrected = <<-RUBY
|
92
|
-
#{factory_bot}.define do
|
93
|
-
factory :post do
|
94
|
-
comments_count 0
|
95
|
-
type User::MAGIC
|
96
|
-
description nil
|
97
|
-
title nil
|
98
|
-
recent_statuses [:published, :draft]
|
99
|
-
meta_tags({ foo: 1 })
|
100
|
-
end
|
101
|
-
end
|
102
|
-
RUBY
|
103
|
-
|
104
|
-
include_examples 'autocorrect', bad, corrected
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|