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 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