Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,5 @@ RSpec/Rails/AvoidSetupHook:
Enabled: true
RSpec/Rails/HaveHttpStatus:
Enabled: true
RSpec/Rails/InferredSpecType:
Enabled: true
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* Add `AllowedPatterns` configuration option to `RSpec/NoExpectationExample`. ([@ydah][])
* Improve `RSpec/NoExpectationExample` cop to ignore examples skipped or pending via metatada. ([@pirj][])
* Add `RSpec/FactoryBot/ConsistentParenthesesStyle` cop. ([@Liberatys][])
* Add `RSpec/Rails/InferredSpecType` cop. ([@r7kamura][])

## 2.13.2 (2022-09-23)

Expand Down
23 changes: 23 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,29 @@ RSpec/Rails/HaveHttpStatus:
VersionAdded: '2.12'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HaveHttpStatus

RSpec/Rails/InferredSpecType:
Description: Identifies redundant spec type.
Enabled: pending
Safe: false
VersionAdded: '2.14'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/InferredSpecType
Inferences:
channels: channel
controllers: controller
features: feature
generator: generator
helpers: helper
jobs: job
mailboxes: mailbox
mailers: mailer
models: model
requests: request
integration: request
api: request
routing: routing
system: system
views: view

RSpec/Rails/HttpStatus:
Description: Enforces use of symbolic or numeric value to describe HTTP status.
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/cops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,6 @@
* xref:cops_rspec_rails.adoc#rspecrails/avoidsetuphook[RSpec/Rails/AvoidSetupHook]
* xref:cops_rspec_rails.adoc#rspecrails/havehttpstatus[RSpec/Rails/HaveHttpStatus]
* xref:cops_rspec_rails.adoc#rspecrails/httpstatus[RSpec/Rails/HttpStatus]
* xref:cops_rspec_rails.adoc#rspecrails/inferredspectype[RSpec/Rails/InferredSpecType]

// END_COP_LIST
83 changes: 83 additions & 0 deletions docs/modules/ROOT/pages/cops_rspec_rails.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,86 @@ it { is_expected.to have_http_status :error }
=== References

* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HttpStatus

== RSpec/Rails/InferredSpecType

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| No
| Yes (Unsafe)
| 2.14
| -
|===

Identifies redundant spec type.

After setting up rspec-rails, you will have enabled
`config.infer_spec_type_from_file_location!` by default in
spec/rails_helper.rb. This cop works in conjunction with this config.
If you disable this config, disable this cop as well.

=== Safety

This cop is marked as unsafe because
`config.infer_spec_type_from_file_location!` may not be enabled.

=== Examples

[source,ruby]
----
# bad
# spec/models/user_spec.rb
RSpec.describe User, type: :model do
end

# good
# spec/models/user_spec.rb
RSpec.describe User do
end

# good
# spec/models/user_spec.rb
RSpec.describe User, type: :common do
end
----

==== `Inferences` configuration

[source,ruby]
----
# .rubocop.yml
# RSpec/InferredSpecType:
# Inferences:
# services: service

# bad
# spec/services/user_spec.rb
RSpec.describe User, type: :service do
end

# good
# spec/services/user_spec.rb
RSpec.describe User do
end

# good
# spec/services/user_spec.rb
RSpec.describe User, type: :common do
end
----

=== Configurable attributes

|===
| Name | Default value | Configurable values

| Inferences
| `{"channels"=>"channel", "controllers"=>"controller", "features"=>"feature", "generator"=>"generator", "helpers"=>"helper", "jobs"=>"job", "mailboxes"=>"mailbox", "mailers"=>"mailer", "models"=>"model", "requests"=>"request", "integration"=>"request", "api"=>"request", "routing"=>"routing", "system"=>"system", "views"=>"view"}`
|
|===

=== References

* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/InferredSpecType
135 changes: 135 additions & 0 deletions lib/rubocop/cop/rspec/rails/inferred_spec_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# frozen_string_literal: true

module RuboCop
module Cop
module RSpec
module Rails
# Identifies redundant spec type.
Comment thread
bquorning marked this conversation as resolved.
#
# After setting up rspec-rails, you will have enabled
# `config.infer_spec_type_from_file_location!` by default in
# spec/rails_helper.rb. This cop works in conjunction with this config.
# If you disable this config, disable this cop as well.
#
# @safety
# This cop is marked as unsafe because
# `config.infer_spec_type_from_file_location!` may not be enabled.
#
# @example
# # bad
# # spec/models/user_spec.rb
# RSpec.describe User, type: :model do
# end
#
# # good
# # spec/models/user_spec.rb
# RSpec.describe User do
# end
#
# # good
# # spec/models/user_spec.rb
# RSpec.describe User, type: :common do
# end
#
# @example `Inferences` configuration
# # .rubocop.yml
# # RSpec/InferredSpecType:
# # Inferences:
# # services: service
#
# # bad
# # spec/services/user_spec.rb
# RSpec.describe User, type: :service do
# end
#
# # good
# # spec/services/user_spec.rb
# RSpec.describe User do
# end
#
# # good
# # spec/services/user_spec.rb
# RSpec.describe User, type: :common do
# end
class InferredSpecType < Base
extend AutoCorrector

MSG = 'Remove redundant spec type.'

# @param [RuboCop::AST::BlockNode] node
def on_block(node)
return unless example_group?(node)

pair_node = describe_with_type(node)
return unless pair_node
return unless inferred_type?(pair_node)

removable_node = detect_removable_node(pair_node)
add_offense(removable_node) do |corrector|
autocorrect(corrector, removable_node)
end
end
alias on_numblock on_block

private

# @!method describe_with_type(node)
# @param [RuboCop::AST::BlockNode] node
# @return [RuboCop::AST::PairNode, nil]
def_node_matcher :describe_with_type, <<~PATTERN
(block
(send #rspec? #ExampleGroups.all
...
(hash <$(pair (sym :type) sym) ...>)
)
...
)
PATTERN

# @param [RuboCop::AST::Corrector] corrector
# @param [RuboCop::AST::Node] node
def autocorrect(corrector, node)
corrector.remove(
node.location.expression.with(
begin_pos: node.left_sibling.location.expression.end_pos
)
)
end

# @param [RuboCop::AST::PairNode] node
# @return [RuboCop::AST::Node]
def detect_removable_node(node)
if node.parent.pairs.size == 1
node.parent
else
node
end
end

# @return [String]
def file_path
processed_source.file_path
end

# @param [RuboCop::AST::PairNode] node
# @return [Boolean]
def inferred_type?(node)
inferred_type_from_file_path.inspect == node.value.source
end

# @return [Symbol, nil]
def inferred_type_from_file_path
inferences.find do |prefix, type|
break type.to_sym if file_path.include?("spec/#{prefix}/")
end
end

# @return [Hash]
def inferences
cop_config['Inferences'] || {}
end
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/rspec_cops.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
rescue LoadError
# Rails/HttpStatus cannot be loaded if rack/utils is unavailable.
end
require_relative 'rspec/rails/inferred_spec_type'

require_relative 'rspec/align_left_let_brace'
require_relative 'rspec/align_right_let_brace'
Expand Down
Loading