rubocop-rspec 1.22.2 → 1.23.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 +10 -0
- data/config/default.yml +14 -0
- data/lib/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically.rb +29 -22
- data/lib/rubocop/cop/rspec/factory_bot/static_attribute_defined_dynamically.rb +75 -0
- data/lib/rubocop/cop/rspec/rails/http_status.rb +162 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +1 -1
- data/lib/rubocop/cop/rspec/verified_doubles.rb +9 -4
- data/lib/rubocop/cop/rspec_cops.rb +3 -0
- data/lib/rubocop/rspec/config_formatter.rb +1 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- data/rubocop-rspec.gemspec +1 -0
- data/spec/project/default_config_spec.rb +4 -3
- data/spec/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically_spec.rb +24 -1
- data/spec/rubocop/cop/rspec/factory_bot/static_attribute_defined_dynamically_spec.rb +102 -0
- data/spec/rubocop/cop/rspec/rails/http_status_spec.rb +106 -0
- data/spec/rubocop/cop/rspec/return_from_stub_spec.rb +9 -0
- metadata +23 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b88289ae95383f02044f1bf61e01950e5637c1b7d5b454a58e025a31f7562c7
|
4
|
+
data.tar.gz: 066a150e7e974240b6678f29c6104e157a634b753602c9f41b746fa2a3f0733b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2cf65077bc9fa485cf1b734918a0279f7925185ecc21196488d24740e5f0d9151672a87521abde59429a5306c7148cd489309c40f6999dedfff0e26972f5e724
|
7
|
+
data.tar.gz: 1173b7e16b85c33f08df3998b70f8accfd39da5f40b61c4bdf8c988c5a6169a26761395035de4919808078a3c26976e0a9a8d67b1585cde081ee0c35c8634bf2
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
## Master (Unreleased)
|
4
4
|
|
5
|
+
## 1.23.0 (2018-02-23)
|
6
|
+
|
7
|
+
* Add `RSpec/Rails/HttpStatus` cop to enforce consistent usage of the status format (numeric or symbolic). ([@anthony-robin][], [@jojos003][])
|
8
|
+
* Fix false negative in `RSpec/ReturnFromStub` when a constant is being returned by the stub. ([@Darhazer][])
|
9
|
+
* Fix `FactoryBot/DynamicAttributeDefinedStatically` to handle dynamic attributes inside arrays/hashes. ([@abrom][])
|
10
|
+
* Add `FactoryBot/StaticAttributeDefinedDynamically` (based on dynamic attribute cop). ([@abrom][])
|
11
|
+
|
5
12
|
## 1.22.2 (2018-02-01)
|
6
13
|
|
7
14
|
* Fix error in `RSpec/DescribedClass` when working on an empty `describe` block. ([@bquorning][])
|
@@ -298,3 +305,6 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
|
|
298
305
|
[@pirj]: https://github.com/pirj
|
299
306
|
[@telmofcosta]: https://github.com/telmofcosta
|
300
307
|
[@EliseFitz15]: https://github.com/EliseFitz15
|
308
|
+
[@anthony-robin]: https://github.com/anthony-robin
|
309
|
+
[@jojos003]: https://github.com/jojos003
|
310
|
+
[@abrom]: https://github.com/abrom
|
data/config/default.yml
CHANGED
@@ -368,3 +368,17 @@ FactoryBot/DynamicAttributeDefinedStatically:
|
|
368
368
|
Description: Prefer declaring dynamic attribute values in a block.
|
369
369
|
Enabled: true
|
370
370
|
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/DynamicAttributeDefinedStatically
|
371
|
+
|
372
|
+
FactoryBot/StaticAttributeDefinedDynamically:
|
373
|
+
Description: Prefer declaring static attribute values without a block.
|
374
|
+
Enabled: true
|
375
|
+
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/StaticAttributeDefinedDynamically
|
376
|
+
|
377
|
+
Rails/HttpStatus:
|
378
|
+
Description: Enforces use of symbolic or numeric value to describe HTTP status.
|
379
|
+
Enabled: true
|
380
|
+
EnforcedStyle: symbolic
|
381
|
+
SupportedStyles:
|
382
|
+
- numeric
|
383
|
+
- symbolic
|
384
|
+
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HttpStatus
|
@@ -6,6 +6,8 @@ module RuboCop
|
|
6
6
|
module FactoryBot
|
7
7
|
# Prefer declaring dynamic attribute values in a block.
|
8
8
|
#
|
9
|
+
# @see StaticAttributeDefinedDynamically
|
10
|
+
#
|
9
11
|
# @example
|
10
12
|
# # bad
|
11
13
|
# kind [:active, :rejected].sample
|
@@ -18,54 +20,59 @@ module RuboCop
|
|
18
20
|
#
|
19
21
|
# # good
|
20
22
|
# closed_at { 1.day.from_now }
|
21
|
-
#
|
22
|
-
# # good
|
23
|
-
# kind :static
|
24
|
-
#
|
25
|
-
# # good
|
26
|
-
# comments_count 0
|
27
|
-
#
|
28
|
-
# # good
|
29
|
-
# type User::MAGIC
|
30
23
|
class DynamicAttributeDefinedStatically < Cop
|
31
24
|
MSG = 'Use a block to set a dynamic value to an attribute.'.freeze
|
32
25
|
|
33
|
-
def_node_matcher :
|
34
|
-
|
26
|
+
def_node_matcher :value_matcher, <<-PATTERN
|
27
|
+
(send nil? _ $...)
|
35
28
|
PATTERN
|
36
29
|
|
37
30
|
def_node_search :factory_attributes, <<-PATTERN
|
38
|
-
|
31
|
+
(block (send nil? {:factory :trait} ...) _ { (begin $...) $(send ...) } )
|
39
32
|
PATTERN
|
40
33
|
|
41
34
|
def on_block(node)
|
42
|
-
return if node.method_name == :trait
|
43
35
|
factory_attributes(node).to_a.flatten.each do |attribute|
|
44
|
-
if
|
45
|
-
|
46
|
-
end
|
36
|
+
next if value_matcher(attribute).to_a.all? { |v| static?(v) }
|
37
|
+
add_offense(attribute, location: :expression)
|
47
38
|
end
|
48
39
|
end
|
49
40
|
|
50
41
|
def autocorrect(node)
|
51
|
-
if method_uses_parens?(node.location)
|
52
|
-
autocorrect_replacing_parens(node)
|
53
|
-
else
|
42
|
+
if !method_uses_parens?(node.location)
|
54
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)
|
55
48
|
end
|
56
49
|
end
|
57
50
|
|
58
51
|
private
|
59
52
|
|
53
|
+
def static?(node)
|
54
|
+
node.recursive_literal? || node.const_type?
|
55
|
+
end
|
56
|
+
|
57
|
+
def value_hash_without_braces?(node)
|
58
|
+
node.hash_type? && !node.braces?
|
59
|
+
end
|
60
|
+
|
60
61
|
def method_uses_parens?(location)
|
61
62
|
return false unless location.begin && location.end
|
62
63
|
location.begin.source == '(' && location.end.source == ')'
|
63
64
|
end
|
64
65
|
|
65
|
-
def
|
66
|
+
def autocorrect_hash_without_braces(node)
|
67
|
+
autocorrect_replacing_parens(node, ' { { ', ' } }')
|
68
|
+
end
|
69
|
+
|
70
|
+
def autocorrect_replacing_parens(node,
|
71
|
+
start_token = ' { ',
|
72
|
+
end_token = ' }')
|
66
73
|
lambda do |corrector|
|
67
|
-
corrector.replace(node.location.begin,
|
68
|
-
corrector.replace(node.location.end,
|
74
|
+
corrector.replace(node.location.begin, start_token)
|
75
|
+
corrector.replace(node.location.end, end_token)
|
69
76
|
end
|
70
77
|
end
|
71
78
|
|
@@ -0,0 +1,75 @@
|
|
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.none? { |v| static?(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 static?(node)
|
61
|
+
node.recursive_literal? || node.const_type?
|
62
|
+
end
|
63
|
+
|
64
|
+
def autocorrected_source(node)
|
65
|
+
if node.body.hash_type?
|
66
|
+
"#{node.send_node.source}(#{node.body.source})"
|
67
|
+
else
|
68
|
+
"#{node.send_node.source} #{node.body.source}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
module Rails
|
7
|
+
# Enforces use of symbolic or numeric value to describe HTTP status.
|
8
|
+
#
|
9
|
+
# @example `EnforcedStyle: symbolic` (default)
|
10
|
+
# # bad
|
11
|
+
# it { is_expected.to have_http_status 200 }
|
12
|
+
# it { is_expected.to have_http_status 404 }
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# it { is_expected.to have_http_status :ok }
|
16
|
+
# it { is_expected.to have_http_status :not_found }
|
17
|
+
# it { is_expected.to have_http_status :success }
|
18
|
+
# it { is_expected.to have_http_status :error }
|
19
|
+
#
|
20
|
+
# @example `EnforcedStyle: numeric`
|
21
|
+
# # bad
|
22
|
+
# it { is_expected.to have_http_status :ok }
|
23
|
+
# it { is_expected.to have_http_status :not_found }
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# it { is_expected.to have_http_status 200 }
|
27
|
+
# it { is_expected.to have_http_status 404 }
|
28
|
+
# it { is_expected.to have_http_status :success }
|
29
|
+
# it { is_expected.to have_http_status :error }
|
30
|
+
#
|
31
|
+
class HttpStatus < Cop
|
32
|
+
begin
|
33
|
+
require 'rack/utils'
|
34
|
+
RACK_LOADED = true
|
35
|
+
rescue LoadError
|
36
|
+
RACK_LOADED = false
|
37
|
+
end
|
38
|
+
|
39
|
+
include ConfigurableEnforcedStyle
|
40
|
+
|
41
|
+
def_node_matcher :http_status, <<-PATTERN
|
42
|
+
(send nil? :have_http_status ${int sym})
|
43
|
+
PATTERN
|
44
|
+
|
45
|
+
def on_send(node)
|
46
|
+
http_status(node) do |ast_node|
|
47
|
+
checker = checker_class.new(ast_node)
|
48
|
+
return unless checker.offensive?
|
49
|
+
add_offense(checker.node, message: checker.message)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def support_autocorrect?
|
54
|
+
RACK_LOADED
|
55
|
+
end
|
56
|
+
|
57
|
+
def autocorrect(node)
|
58
|
+
lambda do |corrector|
|
59
|
+
checker = checker_class.new(node)
|
60
|
+
corrector.replace(node.loc.expression, checker.preferred_style)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def checker_class
|
67
|
+
case style
|
68
|
+
when :symbolic
|
69
|
+
SymbolicStyleChecker
|
70
|
+
when :numeric
|
71
|
+
NumericStyleChecker
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# :nodoc:
|
76
|
+
class SymbolicStyleChecker
|
77
|
+
MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
|
78
|
+
'to describe HTTP status code.'.freeze
|
79
|
+
DEFAULT_MSG = 'Prefer `symbolic` over `numeric` ' \
|
80
|
+
'to describe HTTP status code.'.freeze
|
81
|
+
|
82
|
+
attr_reader :node
|
83
|
+
def initialize(node)
|
84
|
+
@node = node
|
85
|
+
end
|
86
|
+
|
87
|
+
def offensive?
|
88
|
+
!node.sym_type?
|
89
|
+
end
|
90
|
+
|
91
|
+
def message
|
92
|
+
if RACK_LOADED
|
93
|
+
format(MSG, prefer: preferred_style, current: number.to_s)
|
94
|
+
else
|
95
|
+
DEFAULT_MSG
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def preferred_style
|
100
|
+
symbol.inspect
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def symbol
|
106
|
+
::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number)
|
107
|
+
end
|
108
|
+
|
109
|
+
def number
|
110
|
+
node.source.to_i
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# :nodoc:
|
115
|
+
class NumericStyleChecker
|
116
|
+
MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
|
117
|
+
'to describe HTTP status code.'.freeze
|
118
|
+
DEFAULT_MSG = 'Prefer `numeric` over `symbolic` ' \
|
119
|
+
'to describe HTTP status code.'.freeze
|
120
|
+
|
121
|
+
WHITELIST_STATUS = %i[error success missing redirect].freeze
|
122
|
+
|
123
|
+
attr_reader :node
|
124
|
+
def initialize(node)
|
125
|
+
@node = node
|
126
|
+
end
|
127
|
+
|
128
|
+
def offensive?
|
129
|
+
!node.int_type? && !whitelisted_symbol?
|
130
|
+
end
|
131
|
+
|
132
|
+
def message
|
133
|
+
if RACK_LOADED
|
134
|
+
format(MSG, prefer: preferred_style, current: symbol.inspect)
|
135
|
+
else
|
136
|
+
DEFAULT_MSG
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def preferred_style
|
141
|
+
number.to_s
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def number
|
147
|
+
::Rack::Utils::SYMBOL_TO_STATUS_CODE[symbol]
|
148
|
+
end
|
149
|
+
|
150
|
+
def symbol
|
151
|
+
node.value
|
152
|
+
end
|
153
|
+
|
154
|
+
def whitelisted_symbol?
|
155
|
+
node.sym_type? && WHITELIST_STATUS.include?(node.value)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -9,13 +9,18 @@ module RuboCop
|
|
9
9
|
#
|
10
10
|
# @example
|
11
11
|
# # bad
|
12
|
-
#
|
13
|
-
#
|
12
|
+
# let(:foo) do
|
13
|
+
# double(method_name: 'returned value')
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# let(:foo) do
|
18
|
+
# double("ClassName", method_name: 'returned value')
|
14
19
|
# end
|
15
20
|
#
|
16
21
|
# # good
|
17
|
-
#
|
18
|
-
#
|
22
|
+
# let(:foo) do
|
23
|
+
# instance_double("ClassName", method_name: 'returned value')
|
19
24
|
# end
|
20
25
|
class VerifiedDoubles < Cop
|
21
26
|
MSG = 'Prefer using verifying doubles over normal doubles.'.freeze
|
@@ -2,6 +2,9 @@ require_relative 'rspec/capybara/current_path_expectation'
|
|
2
2
|
require_relative 'rspec/capybara/feature_methods'
|
3
3
|
|
4
4
|
require_relative 'rspec/factory_bot/dynamic_attribute_defined_statically'
|
5
|
+
require_relative 'rspec/factory_bot/static_attribute_defined_dynamically'
|
6
|
+
|
7
|
+
require_relative 'rspec/rails/http_status'
|
5
8
|
|
6
9
|
require_relative 'rspec/align_left_let_brace'
|
7
10
|
require_relative 'rspec/align_right_let_brace'
|
@@ -4,7 +4,7 @@ module RuboCop
|
|
4
4
|
module RSpec
|
5
5
|
# Builds a YAML config file from two config hashes
|
6
6
|
class ConfigFormatter
|
7
|
-
NAMESPACES = /^(
|
7
|
+
NAMESPACES = /^(RSpec|Capybara|FactoryBot|Rails)/
|
8
8
|
STYLE_GUIDE_BASE_URL = 'http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/'.freeze
|
9
9
|
|
10
10
|
def initialize(config, descriptions)
|
data/rubocop-rspec.gemspec
CHANGED
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
|
|
34
34
|
|
35
35
|
spec.add_runtime_dependency 'rubocop', '>= 0.52.1'
|
36
36
|
|
37
|
+
spec.add_development_dependency 'rack'
|
37
38
|
spec.add_development_dependency 'rake'
|
38
39
|
spec.add_development_dependency 'rspec', '>= 3.4'
|
39
40
|
spec.add_development_dependency 'simplecov'
|
@@ -7,10 +7,11 @@ RSpec.describe 'config/default.yml' do
|
|
7
7
|
namespaces = {
|
8
8
|
'rspec' => 'RSpec',
|
9
9
|
'capybara' => 'Capybara',
|
10
|
-
'factory_bot' => 'FactoryBot'
|
10
|
+
'factory_bot' => 'FactoryBot',
|
11
|
+
'rails' => 'Rails'
|
11
12
|
}
|
12
|
-
glob = SpecHelper::ROOT.join('lib', 'rubocop', 'cop',
|
13
|
-
'
|
13
|
+
glob = SpecHelper::ROOT.join('lib', 'rubocop', 'cop', 'rspec',
|
14
|
+
'{,capybara,factory_bot,rails}', '*.rb')
|
14
15
|
cop_names =
|
15
16
|
Pathname.glob(glob).map do |file|
|
16
17
|
file_name = file.basename('.rb').to_s
|
@@ -20,6 +20,10 @@ RSpec.describe RuboCop::Cop::RSpec::FactoryBot::DynamicAttributeDefinedStaticall
|
|
20
20
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use a block to set a dynamic value to an attribute.
|
21
21
|
created_at 1.day.ago
|
22
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.
|
23
27
|
end
|
24
28
|
end
|
25
29
|
RUBY
|
@@ -39,7 +43,7 @@ RSpec.describe RuboCop::Cop::RSpec::FactoryBot::DynamicAttributeDefinedStaticall
|
|
39
43
|
RUBY
|
40
44
|
end
|
41
45
|
|
42
|
-
it 'accepts' do
|
46
|
+
it 'accepts valid factory definitions' do
|
43
47
|
expect_no_offenses(<<-RUBY)
|
44
48
|
#{factory_bot}.define do
|
45
49
|
factory :post do
|
@@ -52,6 +56,9 @@ RSpec.describe RuboCop::Cop::RSpec::FactoryBot::DynamicAttributeDefinedStaticall
|
|
52
56
|
title "Static"
|
53
57
|
description { FFaker::Lorem.paragraph(10) }
|
54
58
|
tag Tag::MAGIC
|
59
|
+
recent_statuses [:published, :draft]
|
60
|
+
meta_tags(like_count: 2)
|
61
|
+
other_tags({ foo: nil })
|
55
62
|
end
|
56
63
|
end
|
57
64
|
RUBY
|
@@ -62,6 +69,8 @@ RSpec.describe RuboCop::Cop::RSpec::FactoryBot::DynamicAttributeDefinedStaticall
|
|
62
69
|
status [:draft, :published].sample
|
63
70
|
published_at 1.day.from_now
|
64
71
|
created_at 1.day.ago
|
72
|
+
update_times [Time.current]
|
73
|
+
meta_tags(foo: Time.current)
|
65
74
|
RUBY
|
66
75
|
end
|
67
76
|
|
@@ -72,6 +81,13 @@ RSpec.describe RuboCop::Cop::RSpec::FactoryBot::DynamicAttributeDefinedStaticall
|
|
72
81
|
published_at 1.day.from_now
|
73
82
|
created_at(1.day.ago)
|
74
83
|
updated_at Time.current
|
84
|
+
update_times [Time.current]
|
85
|
+
meta_tags(foo: Time.current)
|
86
|
+
other_tags({ foo: Time.current })
|
87
|
+
|
88
|
+
trait :old do
|
89
|
+
published_at 1.week.ago
|
90
|
+
end
|
75
91
|
end
|
76
92
|
end
|
77
93
|
RUBY
|
@@ -83,6 +99,13 @@ RSpec.describe RuboCop::Cop::RSpec::FactoryBot::DynamicAttributeDefinedStaticall
|
|
83
99
|
published_at { 1.day.from_now }
|
84
100
|
created_at { 1.day.ago }
|
85
101
|
updated_at { Time.current }
|
102
|
+
update_times { [Time.current] }
|
103
|
+
meta_tags { { foo: Time.current } }
|
104
|
+
other_tags { { foo: Time.current } }
|
105
|
+
|
106
|
+
trait :old do
|
107
|
+
published_at { 1.week.ago }
|
108
|
+
end
|
86
109
|
end
|
87
110
|
end
|
88
111
|
RUBY
|
@@ -0,0 +1,102 @@
|
|
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
|
+
end
|
30
|
+
end
|
31
|
+
RUBY
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'registers an offense in a trait' do
|
35
|
+
expect_offense(<<-RUBY)
|
36
|
+
#{factory_bot}.define do
|
37
|
+
factory :post do
|
38
|
+
title "Something"
|
39
|
+
trait :something_else do
|
40
|
+
title { "Something Else" }
|
41
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use a block to set a static value to an attribute.
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
RUBY
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'accepts valid factory definitions' do
|
49
|
+
expect_no_offenses(<<-RUBY)
|
50
|
+
#{factory_bot}.define do
|
51
|
+
factory :post do
|
52
|
+
trait :something_else do
|
53
|
+
title "Something Else"
|
54
|
+
end
|
55
|
+
title "Something"
|
56
|
+
comments_count 0
|
57
|
+
description { FFaker::Lorem.paragraph(10) }
|
58
|
+
tag Tag::MAGIC
|
59
|
+
recent_updates { [Time.current] }
|
60
|
+
meta_tags { { first_like: Time.current } }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
RUBY
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'does not add offense if out of factory girl block' do
|
67
|
+
expect_no_offenses(<<-RUBY)
|
68
|
+
kind { :static }
|
69
|
+
comments_count { 0 }
|
70
|
+
type { User::MAGIC }
|
71
|
+
description { nil }
|
72
|
+
RUBY
|
73
|
+
end
|
74
|
+
|
75
|
+
bad = <<-RUBY
|
76
|
+
#{factory_bot}.define do
|
77
|
+
factory :post do
|
78
|
+
comments_count { 0 }
|
79
|
+
type { User::MAGIC }
|
80
|
+
description { nil }
|
81
|
+
recent_statuses { [:published, :draft] }
|
82
|
+
meta_tags { { foo: 1 } }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
RUBY
|
86
|
+
|
87
|
+
corrected = <<-RUBY
|
88
|
+
#{factory_bot}.define do
|
89
|
+
factory :post do
|
90
|
+
comments_count 0
|
91
|
+
type User::MAGIC
|
92
|
+
description nil
|
93
|
+
recent_statuses [:published, :draft]
|
94
|
+
meta_tags({ foo: 1 })
|
95
|
+
end
|
96
|
+
end
|
97
|
+
RUBY
|
98
|
+
|
99
|
+
include_examples 'autocorrect', bad, corrected
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe RuboCop::Cop::RSpec::Rails::HttpStatus, :config do
|
4
|
+
subject(:cop) { described_class.new(config) }
|
5
|
+
|
6
|
+
context 'when EnforcedStyle is `symbolic`' do
|
7
|
+
let(:cop_config) { { 'EnforcedStyle' => 'symbolic' } }
|
8
|
+
|
9
|
+
it 'registers an offense when using numeric value' do
|
10
|
+
expect_offense(<<-RUBY)
|
11
|
+
it { is_expected.to have_http_status 200 }
|
12
|
+
^^^ Prefer `:ok` over `200` to describe HTTP status code.
|
13
|
+
RUBY
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'does not register an offense when using symbolic value' do
|
17
|
+
expect_no_offenses(<<-RUBY)
|
18
|
+
it { is_expected.to have_http_status :ok }
|
19
|
+
RUBY
|
20
|
+
end
|
21
|
+
|
22
|
+
include_examples 'autocorrect',
|
23
|
+
'it { is_expected.to have_http_status 200 }',
|
24
|
+
'it { is_expected.to have_http_status :ok }'
|
25
|
+
|
26
|
+
include_examples 'autocorrect',
|
27
|
+
'it { is_expected.to have_http_status 404 }',
|
28
|
+
'it { is_expected.to have_http_status :not_found }'
|
29
|
+
|
30
|
+
context 'with parenthesis' do
|
31
|
+
include_examples 'autocorrect',
|
32
|
+
'it { is_expected.to have_http_status(200) }',
|
33
|
+
'it { is_expected.to have_http_status(:ok) }'
|
34
|
+
|
35
|
+
include_examples 'autocorrect',
|
36
|
+
'it { is_expected.to have_http_status(404) }',
|
37
|
+
'it { is_expected.to have_http_status(:not_found) }'
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when rack is not loaded' do
|
41
|
+
before { stub_const("#{described_class}::RACK_LOADED", false) }
|
42
|
+
|
43
|
+
it 'registers an offense when using numeric value' do
|
44
|
+
expect_offense(<<-RUBY)
|
45
|
+
it { is_expected.to have_http_status 200 }
|
46
|
+
^^^ Prefer `symbolic` over `numeric` to describe HTTP status code.
|
47
|
+
RUBY
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when EnforcedStyle is `numeric`' do
|
53
|
+
let(:cop_config) { { 'EnforcedStyle' => 'numeric' } }
|
54
|
+
|
55
|
+
it 'registers an offense when using symbolic value' do
|
56
|
+
expect_offense(<<-RUBY)
|
57
|
+
it { is_expected.to have_http_status :ok }
|
58
|
+
^^^ Prefer `200` over `:ok` to describe HTTP status code.
|
59
|
+
RUBY
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'does not register an offense when using numeric value' do
|
63
|
+
expect_no_offenses(<<-RUBY)
|
64
|
+
it { is_expected.to have_http_status 200 }
|
65
|
+
RUBY
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'does not register an offense when using whitelisted symbols' do
|
69
|
+
expect_no_offenses(<<-RUBY)
|
70
|
+
it { is_expected.to have_http_status :error }
|
71
|
+
it { is_expected.to have_http_status :success }
|
72
|
+
it { is_expected.to have_http_status :missing }
|
73
|
+
it { is_expected.to have_http_status :redirect }
|
74
|
+
RUBY
|
75
|
+
end
|
76
|
+
|
77
|
+
include_examples 'autocorrect',
|
78
|
+
'it { is_expected.to have_http_status :ok }',
|
79
|
+
'it { is_expected.to have_http_status 200 }'
|
80
|
+
|
81
|
+
include_examples 'autocorrect',
|
82
|
+
'it { is_expected.to have_http_status :not_found }',
|
83
|
+
'it { is_expected.to have_http_status 404 }'
|
84
|
+
|
85
|
+
context 'with parenthesis' do
|
86
|
+
include_examples 'autocorrect',
|
87
|
+
'it { is_expected.to have_http_status(:ok) }',
|
88
|
+
'it { is_expected.to have_http_status(200) }'
|
89
|
+
|
90
|
+
include_examples 'autocorrect',
|
91
|
+
'it { is_expected.to have_http_status(:not_found) }',
|
92
|
+
'it { is_expected.to have_http_status(404) }'
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'when rack is not loaded' do
|
96
|
+
before { stub_const("#{described_class}::RACK_LOADED", false) }
|
97
|
+
|
98
|
+
it 'registers an offense when using numeric value' do
|
99
|
+
expect_offense(<<-RUBY)
|
100
|
+
it { is_expected.to have_http_status :ok }
|
101
|
+
^^^ Prefer `numeric` over `symbolic` to describe HTTP status code.
|
102
|
+
RUBY
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -53,6 +53,15 @@ RSpec.describe RuboCop::Cop::RSpec::ReturnFromStub, :config do
|
|
53
53
|
RUBY
|
54
54
|
end
|
55
55
|
|
56
|
+
it 'finds constants returned from block' do
|
57
|
+
expect_offense(<<-RUBY)
|
58
|
+
it do
|
59
|
+
allow(Foo).to receive(:bar) { Life::MEANING }
|
60
|
+
^ Use `and_return` for static values.
|
61
|
+
end
|
62
|
+
RUBY
|
63
|
+
end
|
64
|
+
|
56
65
|
it 'ignores dynamic values returned from block' do
|
57
66
|
expect_no_offenses(<<-RUBY)
|
58
67
|
it do
|
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.
|
4
|
+
version: 1.23.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: 2018-02-
|
13
|
+
date: 2018-02-23 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rubocop
|
@@ -26,6 +26,20 @@ dependencies:
|
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: 0.52.1
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: rack
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
29
43
|
- !ruby/object:Gem::Dependency
|
30
44
|
name: rake
|
31
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -127,6 +141,7 @@ files:
|
|
127
141
|
- lib/rubocop/cop/rspec/expect_in_hook.rb
|
128
142
|
- lib/rubocop/cop/rspec/expect_output.rb
|
129
143
|
- lib/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically.rb
|
144
|
+
- lib/rubocop/cop/rspec/factory_bot/static_attribute_defined_dynamically.rb
|
130
145
|
- lib/rubocop/cop/rspec/file_path.rb
|
131
146
|
- lib/rubocop/cop/rspec/focus.rb
|
132
147
|
- lib/rubocop/cop/rspec/hook_argument.rb
|
@@ -150,6 +165,7 @@ files:
|
|
150
165
|
- lib/rubocop/cop/rspec/not_to_not.rb
|
151
166
|
- lib/rubocop/cop/rspec/overwriting_setup.rb
|
152
167
|
- lib/rubocop/cop/rspec/predicate_matcher.rb
|
168
|
+
- lib/rubocop/cop/rspec/rails/http_status.rb
|
153
169
|
- lib/rubocop/cop/rspec/repeated_description.rb
|
154
170
|
- lib/rubocop/cop/rspec/repeated_example.rb
|
155
171
|
- lib/rubocop/cop/rspec/return_from_stub.rb
|
@@ -207,6 +223,7 @@ files:
|
|
207
223
|
- spec/rubocop/cop/rspec/expect_in_hook_spec.rb
|
208
224
|
- spec/rubocop/cop/rspec/expect_output_spec.rb
|
209
225
|
- spec/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically_spec.rb
|
226
|
+
- spec/rubocop/cop/rspec/factory_bot/static_attribute_defined_dynamically_spec.rb
|
210
227
|
- spec/rubocop/cop/rspec/file_path_spec.rb
|
211
228
|
- spec/rubocop/cop/rspec/focus_spec.rb
|
212
229
|
- spec/rubocop/cop/rspec/hook_argument_spec.rb
|
@@ -230,6 +247,7 @@ files:
|
|
230
247
|
- spec/rubocop/cop/rspec/not_to_not_spec.rb
|
231
248
|
- spec/rubocop/cop/rspec/overwriting_setup_spec.rb
|
232
249
|
- spec/rubocop/cop/rspec/predicate_matcher_spec.rb
|
250
|
+
- spec/rubocop/cop/rspec/rails/http_status_spec.rb
|
233
251
|
- spec/rubocop/cop/rspec/repeated_description_spec.rb
|
234
252
|
- spec/rubocop/cop/rspec/repeated_example_spec.rb
|
235
253
|
- spec/rubocop/cop/rspec/return_from_stub_spec.rb
|
@@ -272,7 +290,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
272
290
|
version: '0'
|
273
291
|
requirements: []
|
274
292
|
rubyforge_project:
|
275
|
-
rubygems_version: 2.7.
|
293
|
+
rubygems_version: 2.7.6
|
276
294
|
signing_key:
|
277
295
|
specification_version: 4
|
278
296
|
summary: Code style checking for RSpec files
|
@@ -305,6 +323,7 @@ test_files:
|
|
305
323
|
- spec/rubocop/cop/rspec/expect_in_hook_spec.rb
|
306
324
|
- spec/rubocop/cop/rspec/expect_output_spec.rb
|
307
325
|
- spec/rubocop/cop/rspec/factory_bot/dynamic_attribute_defined_statically_spec.rb
|
326
|
+
- spec/rubocop/cop/rspec/factory_bot/static_attribute_defined_dynamically_spec.rb
|
308
327
|
- spec/rubocop/cop/rspec/file_path_spec.rb
|
309
328
|
- spec/rubocop/cop/rspec/focus_spec.rb
|
310
329
|
- spec/rubocop/cop/rspec/hook_argument_spec.rb
|
@@ -328,6 +347,7 @@ test_files:
|
|
328
347
|
- spec/rubocop/cop/rspec/not_to_not_spec.rb
|
329
348
|
- spec/rubocop/cop/rspec/overwriting_setup_spec.rb
|
330
349
|
- spec/rubocop/cop/rspec/predicate_matcher_spec.rb
|
350
|
+
- spec/rubocop/cop/rspec/rails/http_status_spec.rb
|
331
351
|
- spec/rubocop/cop/rspec/repeated_description_spec.rb
|
332
352
|
- spec/rubocop/cop/rspec/repeated_example_spec.rb
|
333
353
|
- spec/rubocop/cop/rspec/return_from_stub_spec.rb
|