rubocop-rspec 1.22.2 → 1.23.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45305dc24c290781dd6ea63a81c7ec1c99badf079e3f52cce42f92da63c360b4
4
- data.tar.gz: e2532b3fd549df87cccbd1e060f6a7dbb01b94ed290a3ee32b63961a4cfc57bd
3
+ metadata.gz: 3b88289ae95383f02044f1bf61e01950e5637c1b7d5b454a58e025a31f7562c7
4
+ data.tar.gz: 066a150e7e974240b6678f29c6104e157a634b753602c9f41b746fa2a3f0733b
5
5
  SHA512:
6
- metadata.gz: 462eb5bf9cfd3aa17eddf02aca0a223fecb50f915adf6715c1484c7153b8b650b2205d9d2e6d12989c8097acd68d07e03104c6809f0ed67d901972efe9edf7ac
7
- data.tar.gz: 01662e9fa466a98a282eb5d2256bf5f1c7c9680390c22c2b8e8af0a7eb5313dcf2ada617cda57f2d682b661ea04652548869cd711e1990f9e739df08071aa2d5
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 :dynamic_defined_statically?, <<-PATTERN
34
- (send nil? _ (send ... ))
26
+ def_node_matcher :value_matcher, <<-PATTERN
27
+ (send nil? _ $...)
35
28
  PATTERN
36
29
 
37
30
  def_node_search :factory_attributes, <<-PATTERN
38
- (block (send nil? {:factory :trait} ...) _ { (begin $...) $(send ...) } )
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 dynamic_defined_statically?(attribute)
45
- add_offense(attribute, location: :expression)
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 autocorrect_replacing_parens(node)
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
@@ -92,7 +92,7 @@ module RuboCop
92
92
  end
93
93
 
94
94
  def dynamic?(node)
95
- !node.recursive_literal?
95
+ !node.recursive_literal? && !node.const_type?
96
96
  end
97
97
 
98
98
  # :nodoc:
@@ -9,13 +9,18 @@ module RuboCop
9
9
  #
10
10
  # @example
11
11
  # # bad
12
- # it '...' do
13
- # widget = double("Widget")
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
- # it '...' do
18
- # widget = instance_double("Widget")
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 = /^(#{Regexp.union('RSpec', 'Capybara', 'FactoryBot')})/
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)
@@ -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.22.2'.freeze
7
+ STRING = '1.23.0'.freeze
8
8
  end
9
9
  end
10
10
  end
@@ -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
- 'rspec', '{capybara/,,factory_bot/}*.rb')
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.22.2
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-01 00:00:00.000000000 Z
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.4
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