diff --git a/.rubocop.yml b/.rubocop.yml index df3d9b9b1..a3d324c18 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -28,6 +28,8 @@ Layout/LineLength: Max: 80 # default: 120 AllowedPatterns: - '^\s*# .*https?:\/\/.+\[.+\]\.?$' # Allow long asciidoc links + Exclude: + - lib/rubocop/cop/rspec/rails/have_http_status.rb Layout/MultilineMethodCallIndentation: EnforcedStyle: indented diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c008527b..81b2f17ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Extract RSpec Rails cops to a separate repository, [`rubocop-rspec_rails`](https://github.com/rubocop/rubocop-rspec_rails). The `rubocop-rspec_rails` repository is a dependency of `rubocop-rspec` and the cops related to rspec-rails are aliased (`RSpec/Rails/Foo` == `RSpecRails/Foo`) until v3.0 is released, so the change will be invisible to users until then. ([@ydah]) + ## 2.27.1 (2024-03-03) - Fix a false positive for `RSpec/RepeatedSubjectCall` when `subject.method_call`. ([@ydah]) diff --git a/Gemfile b/Gemfile index 04687217d..d0e69bd70 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,6 @@ gemspec gem 'bump' gem 'danger' -gem 'rack' gem 'rake' gem 'rspec', '~> 3.11' gem 'rubocop-performance', '~> 1.7' diff --git a/config/obsoletion.yml b/config/obsoletion.yml index d38b0a973..1c4c0f8b8 100644 --- a/config/obsoletion.yml +++ b/config/obsoletion.yml @@ -27,3 +27,10 @@ renamed: RSpec/FactoryBot/FactoryClassName: FactoryBot/FactoryClassName RSpec/FactoryBot/FactoryNameStyle: FactoryBot/FactoryNameStyle RSpec/FactoryBot/SyntaxMethods: FactoryBot/SyntaxMethods + RSpec/Rails/AvoidSetupHook: RSpecRails/AvoidSetupHook + RSpec/Rails/HaveHttpStatus: RSpecRails/HaveHttpStatus + RSpec/Rails/HttpStatus: RSpecRails/HttpStatus + RSpec/Rails/InferredSpecType: RSpecRails/InferredSpecType + RSpec/Rails/MinitestAssertions: RSpecRails/MinitestAssertions + RSpec/Rails/NegationBeValid: RSpecRails/NegationBeValid + RSpec/Rails/TravelAround: RSpecRails/TravelAround diff --git a/docs/modules/ROOT/pages/cops_rspec_rails.adoc b/docs/modules/ROOT/pages/cops_rspec_rails.adoc index b956d2991..af981778f 100644 --- a/docs/modules/ROOT/pages/cops_rspec_rails.adoc +++ b/docs/modules/ROOT/pages/cops_rspec_rails.adoc @@ -18,7 +18,8 @@ | - |=== -Checks that tests use RSpec `before` hook over Rails `setup` method. +Checks that tests use RSpec `before` hook over Rails `setup` +method. === Examples @@ -112,8 +113,8 @@ expect(last_response).to have_http_status(200) Enforces use of symbolic or numeric value to describe HTTP status. This cop inspects only `have_http_status` calls. -So, this cop does not check if a method starting with `be_*` is used -when setting for `EnforcedStyle: symbolic` or +So, this cop does not check if a method starting with `be_*` is +used when setting for `EnforcedStyle: symbolic` or `EnforcedStyle: numeric`. === Examples @@ -201,7 +202,8 @@ 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. +spec/rails_helper.rb. This cop works in conjunction with +this config. If you disable this config, disable this cop as well. === Safety @@ -393,12 +395,12 @@ Prefer to travel in `before` rather than `around`. === Safety -This cop is unsafe because the automatic `travel_back` is only run -on test cases that are considered as Rails related. +This cop is unsafe because the automatic `travel_back` is only +run on test cases that are considered as Rails related. -And also, this cop's autocorrection is unsafe because the order of -execution will change if other steps exist before traveling in -`around`. +And also, this cop's autocorrection is unsafe because the order +of execution will change if other steps exist before traveling +in `around`. === Examples diff --git a/docs/modules/ROOT/pages/departments.adoc b/docs/modules/ROOT/pages/departments.adoc index d65cf7009..e35778b6e 100644 --- a/docs/modules/ROOT/pages/departments.adoc +++ b/docs/modules/ROOT/pages/departments.adoc @@ -35,8 +35,8 @@ There are plans for extracting the following three departments before RuboCop RS |Extracted in https://github.com/rubocop/rubocop-rspec/releases/tag/v2.22.0[v2.22.0] |RSpec/Rails -|rubocop-rspec-rails -|Not yet extracted +|rubocop-rspec_rails +|Extracted in https://github.com/rubocop/rubocop-rspec/releases/tag/v2.28.0[v2.28.0] |=== === Migration manual diff --git a/lib/rubocop-rspec.rb b/lib/rubocop-rspec.rb index 21a2d1f91..156edb586 100644 --- a/lib/rubocop-rspec.rb +++ b/lib/rubocop-rspec.rb @@ -6,6 +6,7 @@ require 'rubocop' require 'rubocop-capybara' require 'rubocop-factory_bot' +require 'rubocop-rspec_rails' require_relative 'rubocop/rspec' require_relative 'rubocop/rspec/inject' diff --git a/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb b/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb index 832df8050..940f8a60c 100644 --- a/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb +++ b/lib/rubocop/cop/rspec/rails/avoid_setup_hook.rb @@ -4,39 +4,23 @@ module RuboCop module Cop module RSpec module Rails - # Checks that tests use RSpec `before` hook over Rails `setup` method. - # - # @example - # # bad - # setup do - # allow(foo).to receive(:bar) - # end - # - # # good - # before do - # allow(foo).to receive(:bar) - # end - # - class AvoidSetupHook < Base - extend AutoCorrector - - MSG = 'Use `before` instead of `setup`.' - - # @!method setup_call(node) - def_node_matcher :setup_call, <<~PATTERN - (block - $(send nil? :setup) - (args) _) - PATTERN - - def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler - setup_call(node) do |setup| - add_offense(node) do |corrector| - corrector.replace setup, 'before' - end - end - end - end + # @!parse + # # Checks that tests use RSpec `before` hook over Rails `setup` + # # method. + # # + # # @example + # # # bad + # # setup do + # # allow(foo).to receive(:bar) + # # end + # # + # # # good + # # before do + # # allow(foo).to receive(:bar) + # # end + # # + # class AvoidSetupHook < RuboCop::Cop::RSpecRails::Base; end + AvoidSetupHook = ::RuboCop::Cop::RSpecRails::AvoidSetupHook end end end diff --git a/lib/rubocop/cop/rspec/rails/have_http_status.rb b/lib/rubocop/cop/rspec/rails/have_http_status.rb index 678b212bc..d94294081 100644 --- a/lib/rubocop/cop/rspec/rails/have_http_status.rb +++ b/lib/rubocop/cop/rspec/rails/have_http_status.rb @@ -4,75 +4,31 @@ module RuboCop module Cop module RSpec module Rails - # Checks that tests use `have_http_status` instead of equality matchers. - # - # @example ResponseMethods: ['response', 'last_response'] (default) - # # bad - # expect(response.status).to be(200) - # expect(last_response.code).to eq("200") - # - # # good - # expect(response).to have_http_status(200) - # expect(last_response).to have_http_status(200) - # - # @example ResponseMethods: ['foo_response'] - # # bad - # expect(foo_response.status).to be(200) - # - # # good - # expect(foo_response).to have_http_status(200) - # - # # also good - # expect(response).to have_http_status(200) - # expect(last_response).to have_http_status(200) - # - class HaveHttpStatus < ::RuboCop::Cop::Base - extend AutoCorrector - - MSG = - 'Prefer `expect(%s).%s ' \ - 'have_http_status(%s)` over `%s`.' - - RUNNERS = %i[to to_not not_to].to_set - RESTRICT_ON_SEND = RUNNERS - - # @!method match_status(node) - def_node_matcher :match_status, <<~PATTERN - (send - (send nil? :expect - $(send $(send nil? #response_methods?) {:status :code}) - ) - $RUNNERS - $(send nil? {:be :eq :eql :equal} ({int str} $_)) - ) - PATTERN - - def on_send(node) # rubocop:disable Metrics/MethodLength - match_status(node) do - |response_status, response_method, to, match, status| - return unless status.to_s.match?(/\A\d+\z/) - - message = format(MSG, response: response_method.method_name, - to: to, status: status, - bad_code: node.source) - add_offense(node, message: message) do |corrector| - corrector.replace(response_status, response_method.method_name) - corrector.replace(match.loc.selector, 'have_http_status') - corrector.replace(match.first_argument, status.to_s) - end - end - end - - private - - def response_methods?(name) - response_methods.include?(name.to_s) - end - - def response_methods - cop_config.fetch('ResponseMethods', []) - end - end + # @!parse + # # Checks that tests use `have_http_status` instead of equality matchers. + # # + # # @example ResponseMethods: ['response', 'last_response'] (default) + # # # bad + # # expect(response.status).to be(200) + # # expect(last_response.code).to eq("200") + # # + # # # good + # # expect(response).to have_http_status(200) + # # expect(last_response).to have_http_status(200) + # # + # # @example ResponseMethods: ['foo_response'] + # # # bad + # # expect(foo_response.status).to be(200) + # # + # # # good + # # expect(foo_response).to have_http_status(200) + # # + # # # also good + # # expect(response).to have_http_status(200) + # # expect(last_response).to have_http_status(200) + # # + # class HaveHttpStatus < ::RuboCop::Cop::Base; end + HaveHttpStatus = ::RuboCop::Cop::RSpecRails::HaveHttpStatus end end end diff --git a/lib/rubocop/cop/rspec/rails/http_status.rb b/lib/rubocop/cop/rspec/rails/http_status.rb index d99e1e409..dc387cc69 100644 --- a/lib/rubocop/cop/rspec/rails/http_status.rb +++ b/lib/rubocop/cop/rspec/rails/http_status.rb @@ -1,213 +1,60 @@ # frozen_string_literal: true -require 'rack/utils' - module RuboCop module Cop module RSpec module Rails - # Enforces use of symbolic or numeric value to describe HTTP status. - # - # This cop inspects only `have_http_status` calls. - # So, this cop does not check if a method starting with `be_*` is used - # when setting for `EnforcedStyle: symbolic` or - # `EnforcedStyle: numeric`. - # - # @example `EnforcedStyle: symbolic` (default) - # # bad - # it { is_expected.to have_http_status 200 } - # it { is_expected.to have_http_status 404 } - # it { is_expected.to have_http_status "403" } - # - # # good - # it { is_expected.to have_http_status :ok } - # it { is_expected.to have_http_status :not_found } - # it { is_expected.to have_http_status :forbidden } - # it { is_expected.to have_http_status :success } - # it { is_expected.to have_http_status :error } - # - # @example `EnforcedStyle: numeric` - # # bad - # it { is_expected.to have_http_status :ok } - # it { is_expected.to have_http_status :not_found } - # it { is_expected.to have_http_status "forbidden" } - # - # # good - # it { is_expected.to have_http_status 200 } - # it { is_expected.to have_http_status 404 } - # it { is_expected.to have_http_status 403 } - # it { is_expected.to have_http_status :success } - # it { is_expected.to have_http_status :error } - # - # @example `EnforcedStyle: be_status` - # # bad - # it { is_expected.to have_http_status :ok } - # it { is_expected.to have_http_status :not_found } - # it { is_expected.to have_http_status "forbidden" } - # it { is_expected.to have_http_status 200 } - # it { is_expected.to have_http_status 404 } - # it { is_expected.to have_http_status "403" } - # - # # good - # it { is_expected.to be_ok } - # it { is_expected.to be_not_found } - # it { is_expected.to have_http_status :success } - # it { is_expected.to have_http_status :error } - # - class HttpStatus < Base - extend AutoCorrector - include ConfigurableEnforcedStyle - RESTRICT_ON_SEND = %i[have_http_status].freeze - - # @!method http_status(node) - def_node_matcher :http_status, <<~PATTERN - (send nil? :have_http_status ${int sym str}) - PATTERN - - def on_send(node) - http_status(node) do |arg| - return if arg.str_type? && arg.heredoc? - - checker = checker_class.new(arg) - return unless checker.offensive? - - add_offense(checker.offense_range, - message: checker.message) do |corrector| - corrector.replace(checker.offense_range, checker.prefer) - end - end - end - - private - - def checker_class - case style - when :symbolic - SymbolicStyleChecker - when :numeric - NumericStyleChecker - when :be_status - BeStatusStyleChecker - end - end - - # :nodoc: - class StyleCheckerBase - MSG = 'Prefer `%s` over `%s` ' \ - 'to describe HTTP status code.' - ALLOWED_STATUSES = %i[error success missing redirect].freeze - - attr_reader :node - - def initialize(node) - @node = node - end - - def message - format(MSG, prefer: prefer, current: current) - end - - def current - offense_range.source - end - - def offense_range - node - end - - def allowed_symbol? - node.sym_type? && ALLOWED_STATUSES.include?(node.value) - end - - def custom_http_status_code? - node.int_type? && - !::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(node.source.to_i) - end - end - - # :nodoc: - class SymbolicStyleChecker < StyleCheckerBase - def offensive? - !node.sym_type? && !custom_http_status_code? - end - - def prefer - symbol.inspect - end - - private - - def symbol - ::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number) - end - - def number - node.value.to_i - end - end - - # :nodoc: - class NumericStyleChecker < StyleCheckerBase - def offensive? - !node.int_type? && !allowed_symbol? - end - - def prefer - number.to_s - end - - private - - def symbol - node.value - end - - def number - ::Rack::Utils::SYMBOL_TO_STATUS_CODE[symbol.to_sym] - end - end - - # :nodoc: - class BeStatusStyleChecker < StyleCheckerBase - def offensive? - (!node.sym_type? && !custom_http_status_code?) || - (!node.int_type? && !allowed_symbol?) - end - - def offense_range - node.parent - end - - def prefer - if node.sym_type? - "be_#{node.value}" - elsif node.int_type? - "be_#{symbol}" - elsif node.str_type? - "be_#{normalize_str}" - end - end - - private - - def symbol - ::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number) - end - - def number - node.value.to_i - end - - def normalize_str - str = node.value.to_s - if str.match?(/\A\d+\z/) - ::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(str.to_i) - else - str - end - end - end - end + # @!parse + # # Enforces use of symbolic or numeric value to describe HTTP status. + # # + # # This cop inspects only `have_http_status` calls. + # # So, this cop does not check if a method starting with `be_*` is + # # used when setting for `EnforcedStyle: symbolic` or + # # `EnforcedStyle: numeric`. + # # + # # @example `EnforcedStyle: symbolic` (default) + # # # bad + # # it { is_expected.to have_http_status 200 } + # # it { is_expected.to have_http_status 404 } + # # it { is_expected.to have_http_status "403" } + # # + # # # good + # # it { is_expected.to have_http_status :ok } + # # it { is_expected.to have_http_status :not_found } + # # it { is_expected.to have_http_status :forbidden } + # # it { is_expected.to have_http_status :success } + # # it { is_expected.to have_http_status :error } + # # + # # @example `EnforcedStyle: numeric` + # # # bad + # # it { is_expected.to have_http_status :ok } + # # it { is_expected.to have_http_status :not_found } + # # it { is_expected.to have_http_status "forbidden" } + # # + # # # good + # # it { is_expected.to have_http_status 200 } + # # it { is_expected.to have_http_status 404 } + # # it { is_expected.to have_http_status 403 } + # # it { is_expected.to have_http_status :success } + # # it { is_expected.to have_http_status :error } + # # + # # @example `EnforcedStyle: be_status` + # # # bad + # # it { is_expected.to have_http_status :ok } + # # it { is_expected.to have_http_status :not_found } + # # it { is_expected.to have_http_status "forbidden" } + # # it { is_expected.to have_http_status 200 } + # # it { is_expected.to have_http_status 404 } + # # it { is_expected.to have_http_status "403" } + # # + # # # good + # # it { is_expected.to be_ok } + # # it { is_expected.to be_not_found } + # # it { is_expected.to have_http_status :success } + # # it { is_expected.to have_http_status :error } + # # + # class HttpStatus < RuboCop::Cop::RSpecRails::Base; end + HttpStatus = ::RuboCop::Cop::RSpecRails::HttpStatus end end end diff --git a/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb b/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb index b253a40e2..2ab64601c 100644 --- a/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb +++ b/lib/rubocop/cop/rspec/rails/inferred_spec_type.rb @@ -4,141 +4,58 @@ module RuboCop module Cop module RSpec module Rails - # 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. - # - # @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/Rails/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(remove_range(node)) - end - - # @param [RuboCop::AST::Node] node - # @return [Parser::Source::Range] - def remove_range(node) - if node.left_sibling - node.source_range.with( - begin_pos: node.left_sibling.source_range.end_pos - ) - elsif node.right_sibling - node.source_range.with( - end_pos: node.right_sibling.source_range.begin_pos - ) - end - 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 + # @!parse + # # 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. + # # + # # @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/Rails/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 < RuboCop::Cop::RSpecRails::Base; end + InferredSpecType = ::RuboCop::Cop::RSpecRails::InferredSpecType end end end diff --git a/lib/rubocop/cop/rspec/rails/minitest_assertions.rb b/lib/rubocop/cop/rspec/rails/minitest_assertions.rb index 50c552e90..aac9af384 100644 --- a/lib/rubocop/cop/rspec/rails/minitest_assertions.rb +++ b/lib/rubocop/cop/rspec/rails/minitest_assertions.rb @@ -4,359 +4,35 @@ module RuboCop module Cop module RSpec module Rails - # Check if using Minitest-like matchers. - # - # Check the use of minitest-like matchers - # starting with `assert_` or `refute_`. - # - # @example - # # bad - # assert_equal(a, b) - # assert_equal a, b, "must be equal" - # assert_not_includes a, b - # refute_equal(a, b) - # assert_nil a - # refute_empty(b) - # assert_true(a) - # assert_false(a) - # - # # good - # expect(b).to eq(a) - # expect(b).to(eq(a), "must be equal") - # expect(a).not_to include(b) - # expect(b).not_to eq(a) - # expect(a).to eq(nil) - # expect(a).not_to be_empty - # expect(a).to be(true) - # expect(a).to be(false) - # - class MinitestAssertions < Base - extend AutoCorrector - - # :nodoc: - class BasicAssertion - extend NodePattern::Macros - - attr_reader :expected, :actual, :failure_message - - def self.minitest_assertion - raise NotImplementedError - end - - def initialize(expected, actual, failure_message) - @expected = expected&.source - @actual = actual.source - @failure_message = failure_message&.source - end - - def replaced(node) - runner = negated?(node) ? 'not_to' : 'to' - if failure_message.nil? - "expect(#{actual}).#{runner} #{assertion}" - else - "expect(#{actual}).#{runner}(#{assertion}, #{failure_message})" - end - end - - def negated?(node) - node.method_name.start_with?('assert_not_', 'refute_') - end - - def assertion - raise NotImplementedError - end - end - - # :nodoc: - class EqualAssertion < BasicAssertion - MATCHERS = %i[ - assert_equal - assert_not_equal - refute_equal - ].freeze - - # @!method minitest_assertion(node) - # @!scope class - def_node_matcher 'self.minitest_assertion', <<~PATTERN - (send nil? {:assert_equal :assert_not_equal :refute_equal} $_ $_ $_?) - PATTERN - - def self.match(expected, actual, failure_message) - new(expected, actual, failure_message.first) - end - - def assertion - "eq(#{expected})" - end - end - - # :nodoc: - class KindOfAssertion < BasicAssertion - MATCHERS = %i[ - assert_kind_of - assert_not_kind_of - refute_kind_of - ].freeze - - # @!method minitest_assertion(node) - # @!scope class - def_node_matcher 'self.minitest_assertion', <<~PATTERN - (send nil? {:assert_kind_of :assert_not_kind_of :refute_kind_of} $_ $_ $_?) - PATTERN - - def self.match(expected, actual, failure_message) - new(expected, actual, failure_message.first) - end - - def assertion - "be_a_kind_of(#{expected})" - end - end - - # :nodoc: - class InstanceOfAssertion < BasicAssertion - MATCHERS = %i[ - assert_instance_of - assert_not_instance_of - refute_instance_of - ].freeze - - # @!method minitest_assertion(node) - # @!scope class - def_node_matcher 'self.minitest_assertion', <<~PATTERN - (send nil? {:assert_instance_of :assert_not_instance_of :refute_instance_of} $_ $_ $_?) - PATTERN - - def self.match(expected, actual, failure_message) - new(expected, actual, failure_message.first) - end - - def assertion - "be_an_instance_of(#{expected})" - end - end - - # :nodoc: - class IncludesAssertion < BasicAssertion - MATCHERS = %i[ - assert_includes - assert_not_includes - refute_includes - ].freeze - - # @!method minitest_assertion(node) - # @!scope class - def_node_matcher 'self.minitest_assertion', <<~PATTERN - (send nil? {:assert_includes :assert_not_includes :refute_includes} $_ $_ $_?) - PATTERN - - def self.match(collection, expected, failure_message) - new(expected, collection, failure_message.first) - end - - def assertion - "include(#{expected})" - end - end - - # :nodoc: - class InDeltaAssertion < BasicAssertion - MATCHERS = %i[ - assert_in_delta - assert_not_in_delta - refute_in_delta - ].freeze - - # @!method minitest_assertion(node) - # @!scope class - def_node_matcher 'self.minitest_assertion', <<~PATTERN - (send nil? {:assert_in_delta :assert_not_in_delta :refute_in_delta} $_ $_ $_? $_?) - PATTERN - - def self.match(expected, actual, delta, failure_message) - new(expected, actual, delta.first, failure_message.first) - end - - def initialize(expected, actual, delta, fail_message) - super(expected, actual, fail_message) - - @delta = delta&.source || '0.001' - end - - def assertion - "be_within(#{@delta}).of(#{expected})" - end - end - - # :nodoc: - class PredicateAssertion < BasicAssertion - MATCHERS = %i[ - assert_predicate - assert_not_predicate - refute_predicate - ].freeze - - # @!method minitest_assertion(node) - # @!scope class - def_node_matcher 'self.minitest_assertion', <<~PATTERN - (send nil? {:assert_predicate :assert_not_predicate :refute_predicate} $_ ${sym} $_?) - PATTERN - - def self.match(subject, predicate, failure_message) - return nil unless predicate.value.end_with?('?') - - new(predicate, subject, failure_message.first) - end - - def assertion - "be_#{expected.delete_prefix(':').delete_suffix('?')}" - end - end - - # :nodoc: - class MatchAssertion < BasicAssertion - MATCHERS = %i[ - assert_match - refute_match - ].freeze - - # @!method minitest_assertion(node) - # @!scope class - def_node_matcher 'self.minitest_assertion', <<~PATTERN - (send nil? {:assert_match :refute_match} $_ $_ $_?) - PATTERN - - def self.match(matcher, actual, failure_message) - new(matcher, actual, failure_message.first) - end - - def assertion - "match(#{expected})" - end - end - - # :nodoc: - class NilAssertion < BasicAssertion - MATCHERS = %i[ - assert_nil - assert_not_nil - refute_nil - ].freeze - - # @!method minitest_assertion(node) - # @!scope class - def_node_matcher 'self.minitest_assertion', <<~PATTERN - (send nil? {:assert_nil :assert_not_nil :refute_nil} $_ $_?) - PATTERN - - def self.match(actual, failure_message) - new(nil, actual, failure_message.first) - end - - def assertion - 'eq(nil)' - end - end - - # :nodoc: - class EmptyAssertion < BasicAssertion - MATCHERS = %i[ - assert_empty - assert_not_empty - refute_empty - ].freeze - - # @!method minitest_assertion(node) - # @!scope class - def_node_matcher 'self.minitest_assertion', <<~PATTERN - (send nil? {:assert_empty :assert_not_empty :refute_empty} $_ $_?) - PATTERN - - def self.match(actual, failure_message) - new(nil, actual, failure_message.first) - end - - def assertion - 'be_empty' - end - end - - # :nodoc: - class TrueAssertion < BasicAssertion - MATCHERS = %i[ - assert_true - ].freeze - - # @!method minitest_assertion(node) - # @!scope class - def_node_matcher 'self.minitest_assertion', <<~PATTERN - (send nil? {:assert_true} $_ $_?) - PATTERN - - def self.match(actual, failure_message) - new(nil, actual, failure_message.first) - end - - def assertion - 'be(true)' - end - end - - # :nodoc: - class FalseAssertion < BasicAssertion - MATCHERS = %i[ - assert_false - ].freeze - - # @!method minitest_assertion(node) - # @!scope class - def_node_matcher 'self.minitest_assertion', <<~PATTERN - (send nil? {:assert_false} $_ $_?) - PATTERN - - def self.match(actual, failure_message) - new(nil, actual, failure_message.first) - end - - def assertion - 'be(false)' - end - end - - MSG = 'Use `%s`.' - - # TODO: replace with `BasicAssertion.subclasses` in Ruby 3.1+ - ASSERTION_MATCHERS = constants(false).filter_map do |c| - const = const_get(c) - - const if const.is_a?(Class) && const.superclass == BasicAssertion - end - - RESTRICT_ON_SEND = ASSERTION_MATCHERS.flat_map { |m| m::MATCHERS } - - def on_send(node) - ASSERTION_MATCHERS.each do |m| - m.minitest_assertion(node) do |*args| - assertion = m.match(*args) - - next if assertion.nil? - - on_assertion(node, assertion) - end - end - end - - def on_assertion(node, assertion) - preferred = assertion.replaced(node) - add_offense(node, message: message(preferred)) do |corrector| - corrector.replace(node, preferred) - end - end - - def message(preferred) - format(MSG, prefer: preferred) - end - end + # @!parse + # # Check if using Minitest-like matchers. + # # + # # Check the use of minitest-like matchers + # # starting with `assert_` or `refute_`. + # # + # # @example + # # # bad + # # assert_equal(a, b) + # # assert_equal a, b, "must be equal" + # # assert_not_includes a, b + # # refute_equal(a, b) + # # assert_nil a + # # refute_empty(b) + # # assert_true(a) + # # assert_false(a) + # # + # # # good + # # expect(b).to eq(a) + # # expect(b).to(eq(a), "must be equal") + # # expect(a).not_to include(b) + # # expect(b).not_to eq(a) + # # expect(a).to eq(nil) + # # expect(a).not_to be_empty + # # expect(a).to be(true) + # # expect(a).to be(false) + # # + # class MinitestAssertions < RuboCop::Cop::RSpecRails::Base; end + MinitestAssertions = ::RuboCop::Cop::RSpecRails::MinitestAssertions end end end diff --git a/lib/rubocop/cop/rspec/rails/negation_be_valid.rb b/lib/rubocop/cop/rspec/rails/negation_be_valid.rb index e2d01358d..67a1fddc3 100644 --- a/lib/rubocop/cop/rspec/rails/negation_be_valid.rb +++ b/lib/rubocop/cop/rspec/rails/negation_be_valid.rb @@ -4,98 +4,35 @@ module RuboCop module Cop module RSpec module Rails - # Enforces use of `be_invalid` or `not_to` for negated be_valid. - # - # @safety - # This cop is unsafe because it cannot guarantee that - # the test target is an instance of `ActiveModel::Validations``. - # - # @example EnforcedStyle: not_to (default) - # # bad - # expect(foo).to be_invalid - # - # # good - # expect(foo).not_to be_valid - # - # # good (with method chain) - # expect(foo).to be_invalid.and be_odd - # - # @example EnforcedStyle: be_invalid - # # bad - # expect(foo).not_to be_valid - # - # # good - # expect(foo).to be_invalid - # - # # good (with method chain) - # expect(foo).to be_invalid.or be_even - # - class NegationBeValid < Base - extend AutoCorrector - include ConfigurableEnforcedStyle - - MSG = 'Use `expect(...).%s %s`.' - RESTRICT_ON_SEND = %i[be_valid be_invalid].freeze - - # @!method not_to?(node) - def_node_matcher :not_to?, <<~PATTERN - (send ... :not_to (send nil? :be_valid ...)) - PATTERN - - # @!method be_invalid?(node) - def_node_matcher :be_invalid?, <<~PATTERN - (send ... :to (send nil? :be_invalid ...)) - PATTERN - - def on_send(node) - return unless offense?(node.parent) - - add_offense(offense_range(node), - message: message(node.method_name)) do |corrector| - corrector.replace(node.parent.loc.selector, replaced_runner) - corrector.replace(node.loc.selector, replaced_matcher) - end - end - - private - - def offense?(node) - case style - when :not_to - be_invalid?(node) - when :be_invalid - not_to?(node) - end - end - - def offense_range(node) - node.parent.loc.selector.with(end_pos: node.loc.selector.end_pos) - end - - def message(_matcher) - format(MSG, - runner: replaced_runner, - matcher: replaced_matcher) - end - - def replaced_runner - case style - when :not_to - 'not_to' - when :be_invalid - 'to' - end - end - - def replaced_matcher - case style - when :not_to - 'be_valid' - when :be_invalid - 'be_invalid' - end - end - end + # @!parse + # # Enforces use of `be_invalid` or `not_to` for negated be_valid. + # # + # # @safety + # # This cop is unsafe because it cannot guarantee that + # # the test target is an instance of `ActiveModel::Validations``. + # # + # # @example EnforcedStyle: not_to (default) + # # # bad + # # expect(foo).to be_invalid + # # + # # # good + # # expect(foo).not_to be_valid + # # + # # # good (with method chain) + # # expect(foo).to be_invalid.and be_odd + # # + # # @example EnforcedStyle: be_invalid + # # # bad + # # expect(foo).not_to be_valid + # # + # # # good + # # expect(foo).to be_invalid + # # + # # # good (with method chain) + # # expect(foo).to be_invalid.or be_even + # # + # class NegationBeValid < RuboCop::Cop::RSpecRails::Base; end + NegationBeValid = ::RuboCop::Cop::RSpecRails::NegationBeValid end end end diff --git a/lib/rubocop/cop/rspec/rails/travel_around.rb b/lib/rubocop/cop/rspec/rails/travel_around.rb index 175879ca2..3e52b5cd5 100644 --- a/lib/rubocop/cop/rspec/rails/travel_around.rb +++ b/lib/rubocop/cop/rspec/rails/travel_around.rb @@ -4,88 +4,30 @@ module RuboCop module Cop module RSpec module Rails - # Prefer to travel in `before` rather than `around`. - # - # @safety - # This cop is unsafe because the automatic `travel_back` is only run - # on test cases that are considered as Rails related. - # - # And also, this cop's autocorrection is unsafe because the order of - # execution will change if other steps exist before traveling in - # `around`. - # - # @example - # # bad - # around do |example| - # freeze_time do - # example.run - # end - # end - # - # # good - # before { freeze_time } - class TravelAround < Base - extend AutoCorrector - - MSG = 'Prefer to travel in `before` rather than `around`.' - - TRAVEL_METHOD_NAMES = %i[ - freeze_time - travel - travel_to - ].to_set.freeze - - # @!method extract_run_in_travel(node) - def_node_matcher :extract_run_in_travel, <<~PATTERN - (block - $(send nil? TRAVEL_METHOD_NAMES ...) - (args ...) - (send _ :run) - ) - PATTERN - - # @!method match_around_each?(node) - def_node_matcher :match_around_each?, <<~PATTERN - (block - (send _ :around (sym :each)?) - ... - ) - PATTERN - - def on_block(node) - run_node = extract_run_in_travel(node) - return unless run_node - - around_node = extract_surrounding_around_block(run_node) - return unless around_node - - add_offense(node) do |corrector| - autocorrect(corrector, node, run_node, around_node) - end - end - alias on_numblock on_block - - private - - def autocorrect(corrector, node, run_node, around_node) - corrector.replace( - node, - node.body.source - ) - corrector.insert_before( - around_node, - "before { #{run_node.source} }\n\n" - ) - end - - # @param node [RuboCop::AST::BlockNode] - # @return [RuboCop::AST::BlockNode, nil] - def extract_surrounding_around_block(node) - node.each_ancestor(:block).find do |ancestor| - match_around_each?(ancestor) - end - end - end + # @!parse + # # Prefer to travel in `before` rather than `around`. + # # + # # @safety + # # This cop is unsafe because the automatic `travel_back` is only + # # run on test cases that are considered as Rails related. + # # + # # And also, this cop's autocorrection is unsafe because the order + # # of execution will change if other steps exist before traveling + # # in `around`. + # # + # # @example + # # # bad + # # around do |example| + # # freeze_time do + # # example.run + # # end + # # end + # # + # # # good + # # before { freeze_time } + # # + # class TravelAround < RuboCop::Cop::RSpecRails::Base; end + TravelAround = ::RuboCop::Cop::RSpecRails::TravelAround end end end diff --git a/lib/rubocop/cop/rspec_cops.rb b/lib/rubocop/cop/rspec_cops.rb index a1a4b45f9..7d74ef8a7 100644 --- a/lib/rubocop/cop/rspec_cops.rb +++ b/lib/rubocop/cop/rspec_cops.rb @@ -18,14 +18,10 @@ require_relative 'rspec/rails/avoid_setup_hook' require_relative 'rspec/rails/have_http_status' -require_relative 'rspec/rails/negation_be_valid' -begin - require_relative 'rspec/rails/http_status' -rescue LoadError - # Rails/HttpStatus cannot be loaded if rack/utils is unavailable. -end +require_relative 'rspec/rails/http_status' require_relative 'rspec/rails/inferred_spec_type' require_relative 'rspec/rails/minitest_assertions' +require_relative 'rspec/rails/negation_be_valid' require_relative 'rspec/rails/travel_around' require_relative 'rspec/align_left_let_brace' diff --git a/lib/rubocop/rspec/config_formatter.rb b/lib/rubocop/rspec/config_formatter.rb index f41985e42..4e9566cee 100644 --- a/lib/rubocop/rspec/config_formatter.rb +++ b/lib/rubocop/rspec/config_formatter.rb @@ -22,6 +22,13 @@ class ConfigFormatter RSpec/FactoryBot/FactoryClassName RSpec/FactoryBot/FactoryNameStyle RSpec/FactoryBot/SyntaxMethods + RSpec/Rails/AvoidSetupHook + RSpec/Rails/HaveHttpStatus + RSpec/Rails/HttpStatus + RSpec/Rails/InferredSpecType + RSpec/Rails/MinitestAssertions + RSpec/Rails/NegationBeValid + RSpec/Rails/TravelAround ) AMENDMENTS = %(Metrics/BlockLength) COP_DOC_BASE_URL = 'https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/' diff --git a/rubocop-rspec.gemspec b/rubocop-rspec.gemspec index 7e24ca3f0..b81a21b6a 100644 --- a/rubocop-rspec.gemspec +++ b/rubocop-rspec.gemspec @@ -40,4 +40,5 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'rubocop', '~> 1.40' spec.add_runtime_dependency 'rubocop-capybara', '~> 2.17' spec.add_runtime_dependency 'rubocop-factory_bot', '~> 2.22' + spec.add_runtime_dependency 'rubocop-rails_rspec', '~> 2.28' end diff --git a/spec/rubocop/cop/rspec/rails/avoid_setup_hook_spec.rb b/spec/rubocop/cop/rspec/rails/avoid_setup_hook_spec.rb deleted file mode 100644 index 01c952752..000000000 --- a/spec/rubocop/cop/rspec/rails/avoid_setup_hook_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe RuboCop::Cop::RSpec::Rails::AvoidSetupHook do - it 'registers an offense for `setup`' do - expect_offense(<<~RUBY) - setup do - ^^^^^^^^ Use `before` instead of `setup`. - allow(foo).to receive(:bar) - end - RUBY - - expect_correction(<<~RUBY) - before do - allow(foo).to receive(:bar) - end - RUBY - end - - it 'does not register an offense for `before`' do - expect_no_offenses(<<~RUBY) - before do - allow(foo).to receive(:bar) - end - RUBY - end - - it 'does not register an offense for an unrelated `setup` call' do - expect_no_offenses(<<~RUBY) - navigation.setup do - direction 'to infinity!' - end - RUBY - end -end diff --git a/spec/rubocop/cop/rspec/rails/have_http_status_spec.rb b/spec/rubocop/cop/rspec/rails/have_http_status_spec.rb deleted file mode 100644 index 9eebeda7a..000000000 --- a/spec/rubocop/cop/rspec/rails/have_http_status_spec.rb +++ /dev/null @@ -1,87 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe RuboCop::Cop::RSpec::Rails::HaveHttpStatus do - it 'registers an offense for `expect(response.status).to be(200)`' do - expect_offense(<<~RUBY) - it { expect(response.status).to be(200) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `expect(response).to have_http_status(200)` over `expect(response.status).to be(200)`. - RUBY - - expect_correction(<<~RUBY) - it { expect(response).to have_http_status(200) } - RUBY - end - - it 'registers an offense for `expect(response.status).not_to eq(404)`' do - expect_offense(<<~RUBY) - it { expect(response.status).not_to eq(404) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `expect(response).not_to have_http_status(404)` over `expect(response.status).not_to eq(404)`. - RUBY - - expect_correction(<<~RUBY) - it { expect(response).not_to have_http_status(404) } - RUBY - end - - it 'registers an offense for `expect(response.code).to eq("200")`' do - expect_offense(<<~RUBY) - it { expect(response.code).to eq("200") } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `expect(response).to have_http_status(200)` over `expect(response.code).to eq("200")`. - RUBY - - expect_correction(<<~RUBY) - it { expect(response).to have_http_status(200) } - RUBY - end - - it 'registers an offense for `expect(last_response.status).to eql("200")`' do - expect_offense(<<~RUBY) - it { expect(last_response.status).to eql("200") } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `expect(last_response).to have_http_status(200)` over `expect(last_response.status).to eql("200")`. - RUBY - - expect_correction(<<~RUBY) - it { expect(last_response).to have_http_status(200) } - RUBY - end - - it 'does not register an offense for `is_expected.to be(200)`' do - expect_no_offenses(<<~RUBY) - it { is_expected.to be(200) } - RUBY - end - - it 'does not register an offense for `expect(res.status).to be(200)`' do - expect_no_offenses(<<~RUBY) - it { expect(res.status).to be(200) } - RUBY - end - - it 'ignores statuses that would not coerce to an integer' do - expect_no_offenses(<<~RUBY) - it { expect(response.status).to eq("404 Not Found") } - RUBY - end - - context 'when configured with ResponseMethods: [foo_response]' do - let(:cop_config) { { 'ResponseMethods' => %w[foo_response] } } - - it 'registers an offense for `expect(foo_response.status).to be(200)`' do - expect_offense(<<~RUBY) - it { expect(foo_response.status).to be(200) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `expect(foo_response).to have_http_status(200)` over `expect(foo_response.status).to be(200)`. - RUBY - - expect_correction(<<~RUBY) - it { expect(foo_response).to have_http_status(200) } - RUBY - end - - it 'does not register an offense for ' \ - '`expect(response.status).to be(200)`' do - expect_no_offenses(<<~RUBY) - it { expect(response.status).to be(200) } - RUBY - end - end -end diff --git a/spec/rubocop/cop/rspec/rails/http_status_spec.rb b/spec/rubocop/cop/rspec/rails/http_status_spec.rb deleted file mode 100644 index eba7e2a0b..000000000 --- a/spec/rubocop/cop/rspec/rails/http_status_spec.rb +++ /dev/null @@ -1,264 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe RuboCop::Cop::RSpec::Rails::HttpStatus do - context 'when EnforcedStyle is `symbolic`' do - let(:cop_config) { { 'EnforcedStyle' => 'symbolic' } } - - it 'registers an offense when using numeric value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status 200 } - ^^^ Prefer `:ok` over `200` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to have_http_status :ok } - RUBY - end - - it 'registers an offense when using double quoted string value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status "200" } - ^^^^^ Prefer `:ok` over `"200"` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to have_http_status :ok } - RUBY - end - - it 'registers an offense when using single quoted string value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status '200' } - ^^^^^ Prefer `:ok` over `'200'` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to have_http_status :ok } - RUBY - end - - it 'registers an offense when using percent string value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status %[200] } - ^^^^^^ Prefer `:ok` over `%[200]` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to have_http_status :ok } - RUBY - end - - it 'does not register an offense when using here document' do - expect_no_offenses(<<~RUBY) - it { is_expected.to have_http_status <<~HTTP } - 200 - HTTP - RUBY - end - - it 'does not register an offense when using symbolic value' do - expect_no_offenses(<<~RUBY) - it { is_expected.to have_http_status :ok } - RUBY - end - - it 'does not register an offense when using custom HTTP code' do - expect_no_offenses(<<~RUBY) - it { is_expected.to have_http_status 550 } - RUBY - end - - context 'with parenthesis' do - it 'registers an offense when using numeric value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status(404) } - ^^^ Prefer `:not_found` over `404` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to have_http_status(:not_found) } - RUBY - end - end - end - - context 'when EnforcedStyle is `numeric`' do - let(:cop_config) { { 'EnforcedStyle' => 'numeric' } } - - it 'registers an offense when using symbolic value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status :ok } - ^^^ Prefer `200` over `:ok` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to have_http_status 200 } - RUBY - end - - it 'registers an offense when using double quoted string value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status "ok" } - ^^^^ Prefer `200` over `"ok"` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to have_http_status 200 } - RUBY - end - - it 'registers an offense when using single quoted string value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status 'ok' } - ^^^^ Prefer `200` over `'ok'` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to have_http_status 200 } - RUBY - end - - it 'does not register an offense when using numeric value' do - expect_no_offenses(<<~RUBY) - it { is_expected.to have_http_status 200 } - RUBY - end - - it 'does not register an offense when using allowed symbols' do - expect_no_offenses(<<~RUBY) - it { is_expected.to have_http_status :error } - it { is_expected.to have_http_status :success } - it { is_expected.to have_http_status :missing } - it { is_expected.to have_http_status :redirect } - RUBY - end - - context 'with parenthesis' do - it 'registers an offense when using symbolic value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status(:not_found) } - ^^^^^^^^^^ Prefer `404` over `:not_found` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to have_http_status(404) } - RUBY - end - end - end - - context 'when EnforcedStyle is `be_status`' do - let(:cop_config) { { 'EnforcedStyle' => 'be_status' } } - - it 'registers an offense when using numeric value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status 200 } - ^^^^^^^^^^^^^^^^^^^^ Prefer `be_ok` over `have_http_status 200` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to be_ok } - RUBY - end - - it 'registers an offense when using symbolic value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status :ok } - ^^^^^^^^^^^^^^^^^^^^ Prefer `be_ok` over `have_http_status :ok` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to be_ok } - RUBY - end - - it 'registers an offense when using double quoted string value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status "200" } - ^^^^^^^^^^^^^^^^^^^^^^ Prefer `be_ok` over `have_http_status "200"` to describe HTTP status code. - it { is_expected.to have_http_status "ok" } - ^^^^^^^^^^^^^^^^^^^^^ Prefer `be_ok` over `have_http_status "ok"` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to be_ok } - it { is_expected.to be_ok } - RUBY - end - - it 'registers an offense when using single quoted string value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status '200' } - ^^^^^^^^^^^^^^^^^^^^^^ Prefer `be_ok` over `have_http_status '200'` to describe HTTP status code. - it { is_expected.to have_http_status 'ok' } - ^^^^^^^^^^^^^^^^^^^^^ Prefer `be_ok` over `have_http_status 'ok'` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to be_ok } - it { is_expected.to be_ok } - RUBY - end - - it 'registers an offense when using percent string value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status %[200] } - ^^^^^^^^^^^^^^^^^^^^^^^ Prefer `be_ok` over `have_http_status %[200]` to describe HTTP status code. - it { is_expected.to have_http_status %[ok] } - ^^^^^^^^^^^^^^^^^^^^^^ Prefer `be_ok` over `have_http_status %[ok]` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to be_ok } - it { is_expected.to be_ok } - RUBY - end - - it 'does not register an offense when using here document' do - expect_no_offenses(<<~RUBY) - it { is_expected.to have_http_status <<~HTTP } - 200 - HTTP - RUBY - end - - it 'does not register an offense when using numeric value' do - expect_no_offenses(<<~RUBY) - it { is_expected.to be_ok } - RUBY - end - - it 'does not register an offense when using allowed symbols' do - expect_no_offenses(<<~RUBY) - it { is_expected.to have_http_status :error } - it { is_expected.to have_http_status :success } - it { is_expected.to have_http_status :missing } - it { is_expected.to have_http_status :redirect } - RUBY - end - - context 'with parenthesis' do - it 'registers an offense when using numeric value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status(404) } - ^^^^^^^^^^^^^^^^^^^^^ Prefer `be_not_found` over `have_http_status(404)` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to be_not_found } - RUBY - end - - it 'registers an offense when using symbolic value' do - expect_offense(<<~RUBY) - it { is_expected.to have_http_status(:not_found) } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `be_not_found` over `have_http_status(:not_found)` to describe HTTP status code. - RUBY - - expect_correction(<<~RUBY) - it { is_expected.to be_not_found } - RUBY - end - end - end -end diff --git a/spec/rubocop/cop/rspec/rails/inferred_spec_type_spec.rb b/spec/rubocop/cop/rspec/rails/inferred_spec_type_spec.rb deleted file mode 100644 index e9c0da51b..000000000 --- a/spec/rubocop/cop/rspec/rails/inferred_spec_type_spec.rb +++ /dev/null @@ -1,144 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe RuboCop::Cop::RSpec::Rails::InferredSpecType do - describe 'with necessary type in keyword arguments' do - it 'does not register any offense' do - expect_no_offenses(<<~RUBY) - RSpec.describe User, type: :model do - end - RUBY - end - end - - describe 'with redundant type in keyword arguments' do - it 'register and corrects an offense' do - expect_offense(<<~RUBY, '/path/to/project/spec/models/user_spec.rb') - RSpec.describe User, type: :model do - ^^^^^^^^^^^^ Remove redundant spec type. - end - RUBY - - expect_correction(<<~RUBY) - RSpec.describe User do - end - RUBY - end - end - - describe 'with redundant type in Hash arguments' do - it 'register and corrects an offense' do - expect_offense(<<~RUBY, '/path/to/project/spec/models/user_spec.rb') - RSpec.describe User, { type: :model } do - ^^^^^^^^^^^^^^^^ Remove redundant spec type. - end - RUBY - - expect_correction(<<~RUBY) - RSpec.describe User do - end - RUBY - end - end - - describe 'with redundant type before other Hash metadata' do - it 'register and corrects an offense' do - expect_offense(<<~RUBY, '/path/to/project/spec/models/user_spec.rb') - RSpec.describe User, type: :model, other: true do - ^^^^^^^^^^^^ Remove redundant spec type. - end - RUBY - - expect_correction(<<~RUBY) - RSpec.describe User, other: true do - end - RUBY - end - end - - describe 'with redundant type after other Hash metadata' do - it 'register and corrects an offense' do - expect_offense(<<~RUBY, '/path/to/project/spec/models/user_spec.rb') - RSpec.describe User, other: true, type: :model do - ^^^^^^^^^^^^ Remove redundant spec type. - end - RUBY - - expect_correction(<<~RUBY) - RSpec.describe User, other: true do - end - RUBY - end - end - - describe 'with redundant type and other Symbol metadata' do - it 'register and corrects an offense' do - expect_offense(<<~RUBY, '/path/to/project/spec/models/user_spec.rb') - RSpec.describe User, :other, type: :model do - ^^^^^^^^^^^^ Remove redundant spec type. - end - RUBY - - expect_correction(<<~RUBY) - RSpec.describe User, :other do - end - RUBY - end - end - - describe 'with redundant type and receiver-less describe' do - it 'register and corrects an offense' do - expect_offense(<<~RUBY, '/path/to/project/spec/models/user_spec.rb') - describe User, type: :model do - ^^^^^^^^^^^^ Remove redundant spec type. - end - RUBY - - expect_correction(<<~RUBY) - describe User do - end - RUBY - end - end - - describe 'with redundant type in inner example group' do - it 'register and corrects an offense' do - expect_offense(<<~RUBY, '/path/to/project/spec/models/user_spec.rb') - RSpec.describe User do - describe 'inner', type: :model do - ^^^^^^^^^^^^ Remove redundant spec type. - end - end - RUBY - - expect_correction(<<~RUBY) - RSpec.describe User do - describe 'inner' do - end - end - RUBY - end - end - - describe 'with Inferences configuration' do - let(:cop_config) do - { - 'Inferences' => { - 'services' => 'service' - } - } - end - - it 'register and corrects an offense' do - expect_offense(<<~RUBY, '/path/to/project/spec/services/user_spec.rb') - RSpec.describe User, type: :service do - ^^^^^^^^^^^^^^ Remove redundant spec type. - end - RUBY - - expect_correction(<<~RUBY) - RSpec.describe User do - end - RUBY - end - end -end diff --git a/spec/rubocop/cop/rspec/rails/minitest_assertions_spec.rb b/spec/rubocop/cop/rspec/rails/minitest_assertions_spec.rb deleted file mode 100644 index f410a2eef..000000000 --- a/spec/rubocop/cop/rspec/rails/minitest_assertions_spec.rb +++ /dev/null @@ -1,950 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe RuboCop::Cop::RSpec::Rails::MinitestAssertions do - context 'with equal assertions' do - it 'registers an offense when using `assert_equal`' do - expect_offense(<<~RUBY) - assert_equal(a, b) - ^^^^^^^^^^^^^^^^^^ Use `expect(b).to eq(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to eq(a) - RUBY - end - - it 'registers an offense when using `assert_equal` with no parentheses' do - expect_offense(<<~RUBY) - assert_equal a, b - ^^^^^^^^^^^^^^^^^ Use `expect(b).to eq(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to eq(a) - RUBY - end - - it 'registers an offense when using `assert_equal` with failure message' do - expect_offense(<<~RUBY) - assert_equal a, b, "must be equal" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to(eq(a), "must be equal")`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to(eq(a), "must be equal") - RUBY - end - - it 'registers an offense when using `assert_equal` with ' \ - 'multi-line arguments' do - expect_offense(<<~RUBY) - assert_equal(a, - ^^^^^^^^^^^^^^^ Use `expect(b).to(eq(a), "must be equal")`. - b, - "must be equal") - RUBY - - expect_correction(<<~RUBY) - expect(b).to(eq(a), "must be equal") - RUBY - end - - it 'registers an offense when using `assert_not_equal`' do - expect_offense(<<~RUBY) - assert_not_equal a, b - ^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).not_to eq(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).not_to eq(a) - RUBY - end - - it 'registers an offense when using `refute_equal`' do - expect_offense(<<~RUBY) - refute_equal a, b - ^^^^^^^^^^^^^^^^^ Use `expect(b).not_to eq(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).not_to eq(a) - RUBY - end - - it 'does not register an offense when using `expect(b).to eq(a)`' do - expect_no_offenses(<<~RUBY) - expect(b).to eq(a) - RUBY - end - - it 'does not register an offense when using `expect(b).not_to eq(a)`' do - expect_no_offenses(<<~RUBY) - expect(b).not_to eq(a) - RUBY - end - end - - context 'with kind_of assertions' do - it 'registers an offense when using `assert_kind_of`' do - expect_offense(<<~RUBY) - assert_kind_of(a, b) - ^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_a_kind_of(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to be_a_kind_of(a) - RUBY - end - - it 'registers an offense when using `assert_kind_of` with ' \ - 'no parentheses' do - expect_offense(<<~RUBY) - assert_kind_of a, b - ^^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_a_kind_of(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to be_a_kind_of(a) - RUBY - end - - it 'registers an offense when using `assert_kind_of` with ' \ - 'failure message' do - expect_offense(<<~RUBY) - assert_kind_of a, b, "must be kind of" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to(be_a_kind_of(a), "must be kind of")`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to(be_a_kind_of(a), "must be kind of") - RUBY - end - - it 'registers an offense when using `assert_kind_of` with ' \ - 'multi-line arguments' do - expect_offense(<<~RUBY) - assert_kind_of(a, - ^^^^^^^^^^^^^^^^^ Use `expect(b).to(be_a_kind_of(a), "must be kind of")`. - b, - "must be kind of") - RUBY - - expect_correction(<<~RUBY) - expect(b).to(be_a_kind_of(a), "must be kind of") - RUBY - end - - it 'registers an offense when using `assert_not_kind_of`' do - expect_offense(<<~RUBY) - assert_not_kind_of a, b - ^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).not_to be_a_kind_of(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).not_to be_a_kind_of(a) - RUBY - end - - it 'registers an offense when using `refute_kind_of`' do - expect_offense(<<~RUBY) - refute_kind_of a, b - ^^^^^^^^^^^^^^^^^^^ Use `expect(b).not_to be_a_kind_of(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).not_to be_a_kind_of(a) - RUBY - end - - it 'does not register an offense when ' \ - 'using `expect(b).to be_a_kind_of(a)`' do - expect_no_offenses(<<~RUBY) - expect(b).to be_a_kind_of(a) - RUBY - end - - it 'does not register an offense when ' \ - 'using `expect(b).not_to be_a_kind_of(a)`' do - expect_no_offenses(<<~RUBY) - expect(b).not_to be_a_kind_of(a) - RUBY - end - - it 'does not register an offense when ' \ - 'using `expect(b).to be_kind_of(a)`' do - expect_no_offenses(<<~RUBY) - expect(b).to be_kind_of(a) - RUBY - end - - it 'does not register an offense when ' \ - 'using `expect(b).not_to be_kind_of(a)`' do - expect_no_offenses(<<~RUBY) - expect(b).not_to be_kind_of(a) - RUBY - end - end - - context 'with instance_of assertions' do - it 'registers an offense when using `assert_instance_of`' do - expect_offense(<<~RUBY) - assert_instance_of(a, b) - ^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_an_instance_of(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to be_an_instance_of(a) - RUBY - end - - it 'registers an offense when using `assert_instance_of` with ' \ - 'no parentheses' do - expect_offense(<<~RUBY) - assert_instance_of a, b - ^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_an_instance_of(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to be_an_instance_of(a) - RUBY - end - - it 'registers an offense when using `assert_instance_of` with' \ - 'failure message' do - expect_offense(<<~RUBY) - assert_instance_of a, b, "must be instance of" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to(be_an_instance_of(a), "must be instance of")`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to(be_an_instance_of(a), "must be instance of") - RUBY - end - - it 'registers an offense when using `assert_instance_of` with ' \ - 'multi-line arguments' do - expect_offense(<<~RUBY) - assert_instance_of(a, - ^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to(be_an_instance_of(a), "must be instance of")`. - b, - "must be instance of") - RUBY - - expect_correction(<<~RUBY) - expect(b).to(be_an_instance_of(a), "must be instance of") - RUBY - end - - it 'registers an offense when using `assert_not_instance_of`' do - expect_offense(<<~RUBY) - assert_not_instance_of a, b - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).not_to be_an_instance_of(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).not_to be_an_instance_of(a) - RUBY - end - - it 'registers an offense when using `refute_instance_of`' do - expect_offense(<<~RUBY) - refute_instance_of a, b - ^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).not_to be_an_instance_of(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).not_to be_an_instance_of(a) - RUBY - end - - it 'does not register an offense when ' \ - 'using `expect(b).to be_an_instance_of(a)`' do - expect_no_offenses(<<~RUBY) - expect(b).to be_an_instance_of(a) - RUBY - end - - it 'does not register an offense when ' \ - 'using `expect(b).not_to be_an_instance_of(a)`' do - expect_no_offenses(<<~RUBY) - expect(b).not_to be_an_instance_of(a) - RUBY - end - - it 'does not register an offense when ' \ - 'using `expect(b).to be_instance_of(a)`' do - expect_no_offenses(<<~RUBY) - expect(b).to be_instance_of(a) - RUBY - end - - it 'does not register an offense when ' \ - 'using `expect(b).not_to be_instance_of(a)`' do - expect_no_offenses(<<~RUBY) - expect(b).not_to be_instance_of(a) - RUBY - end - end - - context 'with includes assertions' do - it 'registers an offense when using `assert_includes`' do - expect_offense(<<~RUBY) - assert_includes(a, b) - ^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to include(b)`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to include(b) - RUBY - end - - it 'registers an offense when using `assert_includes` with ' \ - 'no parentheses' do - expect_offense(<<~RUBY) - assert_includes a, b - ^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to include(b)`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to include(b) - RUBY - end - - it 'registers an offense when using `assert_includes` with ' \ - 'failure message' do - expect_offense(<<~RUBY) - assert_includes a, b, "must be include" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to(include(b), "must be include")`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to(include(b), "must be include") - RUBY - end - - it 'registers an offense when using `assert_includes` with ' \ - 'multi-line arguments' do - expect_offense(<<~RUBY) - assert_includes(a, - ^^^^^^^^^^^^^^^^^^ Use `expect(a).to(include(b), "must be include")`. - b, - "must be include") - RUBY - - expect_correction(<<~RUBY) - expect(a).to(include(b), "must be include") - RUBY - end - - it 'registers an offense when using `assert_not_includes`' do - expect_offense(<<~RUBY) - assert_not_includes a, b - ^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).not_to include(b)`. - RUBY - - expect_correction(<<~RUBY) - expect(a).not_to include(b) - RUBY - end - - it 'registers an offense when using `refute_includes`' do - expect_offense(<<~RUBY) - refute_includes a, b - ^^^^^^^^^^^^^^^^^^^^ Use `expect(a).not_to include(b)`. - RUBY - - expect_correction(<<~RUBY) - expect(a).not_to include(b) - RUBY - end - - it 'does not register an offense when using `expect(a).to include(b)`' do - expect_no_offenses(<<~RUBY) - expect(a).to include(b) - RUBY - end - - it 'does not register an offense when ' \ - 'using `expect(a).not_to include(b)`' do - expect_no_offenses(<<~RUBY) - expect(a).not_to include(b) - RUBY - end - end - - context 'with in_delta assertions' do - it 'registers an offense when using `assert_in_delta`' do - expect_offense(<<~RUBY) - assert_in_delta(a, b) - ^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_within(0.001).of(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to be_within(0.001).of(a) - RUBY - end - - it 'registers an offense when using `assert_in_delta` with ' \ - 'no parentheses' do - expect_offense(<<~RUBY) - assert_in_delta a, b - ^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_within(0.001).of(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to be_within(0.001).of(a) - RUBY - end - - it 'registers an offense when using `assert_in_delta` with ' \ - 'a custom delta' do - expect_offense(<<~RUBY) - assert_in_delta a, b, 1 - ^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_within(1).of(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to be_within(1).of(a) - RUBY - end - - it 'registers an offense when using `assert_in_delta` with ' \ - 'a custom delta from a variable' do - expect_offense(<<~RUBY) - delta = 1 - - assert_in_delta a, b, delta - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_within(delta).of(a)`. - RUBY - - expect_correction(<<~RUBY) - delta = 1 - - expect(b).to be_within(delta).of(a) - RUBY - end - - it 'registers an offense when using `assert_in_delta` with ' \ - 'a custom delta and a failure message' do - expect_offense(<<~RUBY) - assert_in_delta a, b, 1, "must be within delta" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to(be_within(1).of(a), "must be within delta")`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to(be_within(1).of(a), "must be within delta") - RUBY - end - - it 'registers an offense when using `assert_in_delta` with ' \ - 'multi-line arguments' do - expect_offense(<<~RUBY) - assert_in_delta(a, - ^^^^^^^^^^^^^^^^^^ Use `expect(b).to be_within(1).of(a)`. - b, - 1) - RUBY - - expect_correction(<<~RUBY) - expect(b).to be_within(1).of(a) - RUBY - end - - it 'registers an offense when using `assert_not_in_delta`' do - expect_offense(<<~RUBY) - assert_not_in_delta a, b - ^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).not_to be_within(0.001).of(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).not_to be_within(0.001).of(a) - RUBY - end - - it 'registers an offense when using `refute_in_delta`' do - expect_offense(<<~RUBY) - refute_in_delta a, b - ^^^^^^^^^^^^^^^^^^^^ Use `expect(b).not_to be_within(0.001).of(a)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).not_to be_within(0.001).of(a) - RUBY - end - - it 'does not register an offense when ' \ - 'using `expect(b).to be_within(1).of(a)`' do - expect_no_offenses(<<~RUBY) - expect(b).to be_within(1).of(a) - RUBY - end - - it 'does not register an offense when ' \ - 'using `expect(b).not_to be_within(1).of(a)`' do - expect_no_offenses(<<~RUBY) - expect(b).not_to be_within(1).of(a) - RUBY - end - end - - context 'with match assertions' do - it 'registers an offense when using `assert_match`' do - expect_offense(<<~RUBY) - assert_match(/xyz/, b) - ^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to match(/xyz/)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to match(/xyz/) - RUBY - end - - it 'registers an offense when using `assert_match` with no parentheses' do - expect_offense(<<~RUBY) - assert_match /xyz/, b - ^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to match(/xyz/)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to match(/xyz/) - RUBY - end - - it 'registers an offense when using `assert_match` with failure message' do - expect_offense(<<~RUBY) - assert_match /xyz/, b, "must match" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).to(match(/xyz/), "must match")`. - RUBY - - expect_correction(<<~RUBY) - expect(b).to(match(/xyz/), "must match") - RUBY - end - - it 'registers an offense when using `assert_match` with ' \ - 'multi-line arguments' do - expect_offense(<<~RUBY) - assert_match(/xyz/, - ^^^^^^^^^^^^^^^^^^^ Use `expect(b).to(match(/xyz/), "must match")`. - b, - "must match") - RUBY - - expect_correction(<<~RUBY) - expect(b).to(match(/xyz/), "must match") - RUBY - end - - it 'registers an offense when using `refute_match`' do - expect_offense(<<~RUBY) - refute_match /xyz/, b - ^^^^^^^^^^^^^^^^^^^^^ Use `expect(b).not_to match(/xyz/)`. - RUBY - - expect_correction(<<~RUBY) - expect(b).not_to match(/xyz/) - RUBY - end - - it 'does not register an offense when using `expect(b).to match(/xyz/)`' do - expect_no_offenses(<<~RUBY) - expect(b).to match(/xyz/) - RUBY - end - - it 'does not register an offense when ' \ - 'using `expect(b).not_to match(/xyz/)`' do - expect_no_offenses(<<~RUBY) - expect(b).not_to match(/xyz/) - RUBY - end - end - - context 'with nil assertions' do - it 'registers an offense when using `assert_nil`' do - expect_offense(<<~RUBY) - assert_nil(a) - ^^^^^^^^^^^^^ Use `expect(a).to eq(nil)`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to eq(nil) - RUBY - end - - it 'registers an offense when using `assert_nil` with no parentheses' do - expect_offense(<<~RUBY) - assert_nil a - ^^^^^^^^^^^^ Use `expect(a).to eq(nil)`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to eq(nil) - RUBY - end - - it 'registers an offense when using `assert_nil` with failure message' do - expect_offense(<<~RUBY) - assert_nil a, "must be nil" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to(eq(nil), "must be nil")`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to(eq(nil), "must be nil") - RUBY - end - - it 'registers an offense when using `assert_nil` with ' \ - 'multi-line arguments' do - expect_offense(<<~RUBY) - assert_nil(a, - ^^^^^^^^^^^^^ Use `expect(a).to(eq(nil), "must be nil")`. - "must be nil") - RUBY - - expect_correction(<<~RUBY) - expect(a).to(eq(nil), "must be nil") - RUBY - end - - it 'registers an offense when using `assert_not_nil`' do - expect_offense(<<~RUBY) - assert_not_nil a - ^^^^^^^^^^^^^^^^ Use `expect(a).not_to eq(nil)`. - RUBY - - expect_correction(<<~RUBY) - expect(a).not_to eq(nil) - RUBY - end - - it 'registers an offense when using `refute_nil`' do - expect_offense(<<~RUBY) - refute_nil a - ^^^^^^^^^^^^ Use `expect(a).not_to eq(nil)`. - RUBY - - expect_correction(<<~RUBY) - expect(a).not_to eq(nil) - RUBY - end - - it 'does not register an offense when using `expect(a).to eq(nil)`' do - expect_no_offenses(<<~RUBY) - expect(a).to eq(nil) - RUBY - end - - it 'does not register an offense when using `expect(a).not_to eq(nil)`' do - expect_no_offenses(<<~RUBY) - expect(a).not_to eq(nil) - RUBY - end - end - - context 'with empty assertions' do - it 'registers an offense when using `assert_empty`' do - expect_offense(<<~RUBY) - assert_empty(a) - ^^^^^^^^^^^^^^^ Use `expect(a).to be_empty`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to be_empty - RUBY - end - - it 'registers an offense when using `assert_empty` with no parentheses' do - expect_offense(<<~RUBY) - assert_empty a - ^^^^^^^^^^^^^^ Use `expect(a).to be_empty`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to be_empty - RUBY - end - - it 'registers an offense when using `assert_empty` with failure message' do - expect_offense(<<~RUBY) - assert_empty a, "must be empty" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to(be_empty, "must be empty")`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to(be_empty, "must be empty") - RUBY - end - - it 'registers an offense when using `assert_empty` with ' \ - 'multi-line arguments' do - expect_offense(<<~RUBY) - assert_empty(a, - ^^^^^^^^^^^^^^^ Use `expect(a).to(be_empty, "must be empty")`. - "must be empty") - RUBY - - expect_correction(<<~RUBY) - expect(a).to(be_empty, "must be empty") - RUBY - end - - it 'registers an offense when using `assert_not_empty`' do - expect_offense(<<~RUBY) - assert_not_empty a - ^^^^^^^^^^^^^^^^^^ Use `expect(a).not_to be_empty`. - RUBY - - expect_correction(<<~RUBY) - expect(a).not_to be_empty - RUBY - end - - it 'registers an offense when using `refute_empty`' do - expect_offense(<<~RUBY) - refute_empty a - ^^^^^^^^^^^^^^ Use `expect(a).not_to be_empty`. - RUBY - - expect_correction(<<~RUBY) - expect(a).not_to be_empty - RUBY - end - - it 'does not register an offense when using `expect(a).to be_empty`' do - expect_no_offenses(<<~RUBY) - expect(a).to be_empty - RUBY - end - - it 'does not register an offense when using `expect(a).not_to be_empty`' do - expect_no_offenses(<<~RUBY) - expect(a).not_to be_empty - RUBY - end - end - - context 'with boolean assertions' do - it 'registers an offense when using `assert_true`' do - expect_offense(<<~RUBY) - assert_true(a) - ^^^^^^^^^^^^^^ Use `expect(a).to be(true)`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to be(true) - RUBY - end - - it 'registers an offense when using `assert_true` with no parentheses' do - expect_offense(<<~RUBY) - assert_true a - ^^^^^^^^^^^^^ Use `expect(a).to be(true)`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to be(true) - RUBY - end - - it 'registers an offense when using `assert_true` with failure message' do - expect_offense(<<~RUBY) - assert_true a, "must be true" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to(be(true), "must be true")`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to(be(true), "must be true") - RUBY - end - - it 'registers an offense when using `assert_true` with ' \ - 'multi-line arguments' do - expect_offense(<<~RUBY) - assert_true(a, - ^^^^^^^^^^^^^^ Use `expect(a).to(be(true), "must be true")`. - "must be true") - RUBY - - expect_correction(<<~RUBY) - expect(a).to(be(true), "must be true") - RUBY - end - - it 'registers an offense when using `assert_false`' do - expect_offense(<<~RUBY) - assert_false(a) - ^^^^^^^^^^^^^^^ Use `expect(a).to be(false)`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to be(false) - RUBY - end - - it 'registers an offense when using `assert_false` with no parentheses' do - expect_offense(<<~RUBY) - assert_false a - ^^^^^^^^^^^^^^ Use `expect(a).to be(false)`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to be(false) - RUBY - end - - it 'registers an offense when using `assert_false` with failure message' do - expect_offense(<<~RUBY) - assert_false a, "must be false" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to(be(false), "must be false")`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to(be(false), "must be false") - RUBY - end - - it 'registers an offense when using `assert_false` with ' \ - 'multi-line arguments' do - expect_offense(<<~RUBY) - assert_false(a, - ^^^^^^^^^^^^^^^ Use `expect(a).to(be(false), "must be false")`. - "must be false") - RUBY - - expect_correction(<<~RUBY) - expect(a).to(be(false), "must be false") - RUBY - end - end - - context 'with predicate assertions' do - it 'registers an offense when using `assert_predicate` with ' \ - 'an actual predicate' do - expect_offense(<<~RUBY) - assert_predicate(a, :valid?) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to be_valid`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to be_valid - RUBY - end - - it 'registers an offense when using `assert_predicate` with ' \ - 'an actual predicate and no parentheses' do - expect_offense(<<~RUBY) - assert_predicate a, :valid? - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to be_valid`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to be_valid - RUBY - end - - it 'registers an offense when using `assert_predicate` with ' \ - 'an actual predicate and a failure message' do - expect_offense(<<~RUBY) - assert_predicate a, :valid?, "must be valid" - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to(be_valid, "must be valid")`. - RUBY - - expect_correction(<<~RUBY) - expect(a).to(be_valid, "must be valid") - RUBY - end - - it 'registers an offense when using `assert_predicate` with ' \ - 'an actual predicate and multi-line arguments' do - expect_offense(<<~RUBY) - assert_predicate(a, - ^^^^^^^^^^^^^^^^^^^ Use `expect(a).to(be_valid, "must be valid")`. - :valid?, - "must be valid") - RUBY - - expect_correction(<<~RUBY) - expect(a).to(be_valid, "must be valid") - RUBY - end - - it 'registers an offense when using `assert_not_predicate` with ' \ - 'an actual predicate' do - expect_offense(<<~RUBY) - assert_not_predicate a, :valid? - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).not_to be_valid`. - RUBY - - expect_correction(<<~RUBY) - expect(a).not_to be_valid - RUBY - end - - it 'registers an offense when using `refute_predicate` with ' \ - 'an actual predicate' do - expect_offense(<<~RUBY) - refute_predicate a, :valid? - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).not_to be_valid`. - RUBY - - expect_correction(<<~RUBY) - expect(a).not_to be_valid - RUBY - end - - it 'does not register an offense when using `expect(a).to be_predicate`' do - expect_no_offenses(<<~RUBY) - expect(a).to be_predicate - RUBY - end - - it 'does not register an offense when using ' \ - '`expect(a).not_to be_predicate`' do - expect_no_offenses(<<~RUBY) - expect(a).not_to be_predicate - RUBY - end - - it 'does not register an offense when using `assert_predicate` with ' \ - 'not a predicate' do - expect_no_offenses(<<~RUBY) - assert_predicate foo, :do_something - RUBY - end - - it 'does not register an offense when using `assert_not_predicate` with ' \ - 'not a predicate' do - expect_no_offenses(<<~RUBY) - assert_not_predicate foo, :do_something - RUBY - end - - it 'does not register an offense when using `refute_predicate` with ' \ - 'not a predicate' do - expect_no_offenses(<<~RUBY) - refute_predicate foo, :do_something - RUBY - end - - it 'does not register an offense when the predicate is not a symbol' do - expect_no_offenses(<<~RUBY) - assert_predicate a, 1 - RUBY - end - - it 'does not register an offense when the predicate is missing' do - expect_no_offenses(<<~RUBY) - assert_predicate a, "whoops, we forgot about the actual predicate!" - RUBY - end - - it 'does not register an offense when the predicate is a variable' do - expect_no_offenses(<<~RUBY) - foo = :foo? - - assert_predicate a, foo - RUBY - end - end -end diff --git a/spec/rubocop/cop/rspec/rails/negation_be_valid_spec.rb b/spec/rubocop/cop/rspec/rails/negation_be_valid_spec.rb deleted file mode 100644 index 0c6fec2c8..000000000 --- a/spec/rubocop/cop/rspec/rails/negation_be_valid_spec.rb +++ /dev/null @@ -1,73 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe RuboCop::Cop::RSpec::Rails::NegationBeValid do - let(:cop_config) { { 'EnforcedStyle' => enforced_style } } - - context 'with EnforcedStyle `not_to`' do - let(:enforced_style) { 'not_to' } - - it 'registers an offense when using ' \ - '`expect(...).to be_invalid`' do - expect_offense(<<~RUBY) - expect(foo).to be_invalid - ^^^^^^^^^^^^^ Use `expect(...).not_to be_valid`. - RUBY - end - - it 'does not register an offense when using ' \ - '`expect(...).not_to be_valid`' do - expect_no_offenses(<<~RUBY) - expect(foo).not_to be_valid - RUBY - end - - it 'does not register an offense when using ' \ - '`expect(...).to be_valid`' do - expect_no_offenses(<<~RUBY) - expect(foo).to be_valid - RUBY - end - - it 'does not register an offense when using ' \ - '`expect(...).to be_invalid` and method chain' do - expect_no_offenses(<<~RUBY) - expect(foo).to be_invalid.and be_odd - expect(foo).to be_invalid.or be_even - RUBY - end - end - - context 'with EnforcedStyle `be_invalid`' do - let(:enforced_style) { 'be_invalid' } - - it 'registers an offense when using ' \ - '`expect(...).not_to be_valid`' do - expect_offense(<<~RUBY) - expect(foo).not_to be_valid - ^^^^^^^^^^^^^^^ Use `expect(...).to be_invalid`. - RUBY - end - - it 'does not register an offense when using ' \ - '`expect(...).to be_invalid`' do - expect_no_offenses(<<~RUBY) - expect(foo).to be_invalid - RUBY - end - - it 'does not register an offense when using ' \ - '`expect(...).to be_valid`' do - expect_no_offenses(<<~RUBY) - expect(foo).to be_valid - RUBY - end - - it 'does not register an offense when using ' \ - '`expect(...).not_to be_valid` and method chain' do - expect_no_offenses(<<~RUBY) - expect(foo).not_to be_valid.and be_odd - expect(foo).not_to be_valid.or be_even - RUBY - end - end -end diff --git a/spec/rubocop/cop/rspec/rails/travel_around_spec.rb b/spec/rubocop/cop/rspec/rails/travel_around_spec.rb deleted file mode 100644 index ae1c2944a..000000000 --- a/spec/rubocop/cop/rspec/rails/travel_around_spec.rb +++ /dev/null @@ -1,157 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe RuboCop::Cop::RSpec::Rails::TravelAround do - context 'with `freeze_time` in `before`' do - it 'registers no offense' do - expect_no_offenses(<<~RUBY) - before { freeze_time } - RUBY - end - end - - context 'with `freeze_time` in `around(:all)`' do - it 'registers no offense' do - expect_no_offenses(<<~RUBY) - around(:all) do |example| - freeze_time do - example.run - end - end - RUBY - end - end - - context 'with `freeze_time` in `around(:suite)`' do - it 'registers no offense' do - expect_no_offenses(<<~RUBY) - around(:suite) do |example| - freeze_time do - example.run - end - end - RUBY - end - end - - context 'with another step in `freeze_time`' do - it 'registers no offense' do - expect_no_offenses(<<~RUBY) - around do |example| - freeze_time do - do_some_preparation - example.run - end - end - RUBY - end - end - - context 'with `freeze_time` in `around`' do - it 'registers offense' do - expect_offense(<<~RUBY) - around do |example| - freeze_time do - ^^^^^^^^^^^^^^ Prefer to travel in `before` rather than `around`. - example.run - end - end - RUBY - - expect_correction(<<~RUBY) - before { freeze_time } - - around do |example| - example.run - end - RUBY - end - end - - context 'with `freeze_time` in `around(:each)`' do - it 'registers offense' do - expect_offense(<<~RUBY) - around(:each) do |example| - freeze_time do - ^^^^^^^^^^^^^^ Prefer to travel in `before` rather than `around`. - example.run - end - end - RUBY - - expect_correction(<<~RUBY) - before { freeze_time } - - around(:each) do |example| - example.run - end - RUBY - end - end - - context 'with `freeze_time` and another node in `around`' do - it 'registers offense' do - expect_offense(<<~RUBY) - around do |example| - foo - - freeze_time do - ^^^^^^^^^^^^^^ Prefer to travel in `before` rather than `around`. - example.run - end - end - RUBY - - expect_correction(<<~RUBY) - before { freeze_time } - - around do |example| - foo - - example.run - end - RUBY - end - end - - context 'with `travel` in `around`' do - it 'registers offense' do - expect_offense(<<~RUBY) - around do |example| - travel(duration) do - ^^^^^^^^^^^^^^^^^^^ Prefer to travel in `before` rather than `around`. - example.run - end - end - RUBY - - expect_correction(<<~RUBY) - before { travel(duration) } - - around do |example| - example.run - end - RUBY - end - end - - context 'with `travel_to` in `around`' do - it 'registers offense' do - expect_offense(<<~RUBY) - around do |example| - travel_to(time) do - ^^^^^^^^^^^^^^^^^^ Prefer to travel in `before` rather than `around`. - example.run - end - end - RUBY - - expect_correction(<<~RUBY) - before { travel_to(time) } - - around do |example| - example.run - end - RUBY - end - end -end diff --git a/tasks/cops_documentation.rake b/tasks/cops_documentation.rake index 2010920ac..474896e26 100644 --- a/tasks/cops_documentation.rake +++ b/tasks/cops_documentation.rake @@ -65,6 +65,31 @@ task generate_cops_documentation: :yard_for_generate_documentation do end global.enlist(cop) end + %w[ + RuboCop::Cop::RSpec::Rails::AvoidSetupHook + RuboCop::Cop::RSpec::Rails::HaveHttpStatus + RuboCop::Cop::RSpec::Rails::HttpStatus + RuboCop::Cop::RSpec::Rails::InferredSpecType + RuboCop::Cop::RSpec::Rails::MinitestAssertions + RuboCop::Cop::RSpec::Rails::NegationBeValid + RuboCop::Cop::RSpec::Rails::TravelAround + ].each do |extracted_cop| + cop = Class.const_get(extracted_cop) + class << cop + def badge + RuboCop::Cop::Badge.for(name) + end + + def name + super.sub('::RSpecRails::', '::RSpec::Rails::') + end + + def department + :'RSpec/Rails' + end + end + global.enlist(cop) + end generator = CopsDocumentationGenerator.new( departments: %w[RSpec/Capybara RSpec/FactoryBot RSpec/Rails RSpec]