brew vendor-gems: commit updates.
This commit is contained in:
parent
e8e220128d
commit
31af2df104
@ -89,7 +89,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.35.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.14.3/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rails-2.16.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-2.12.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-2.13.1/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.6.11/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-3.0.0/lib"
|
||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-html-0.12.3/lib"
|
||||
|
@ -1,77 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
module Capybara
|
||||
# Checks for there is a more specific matcher offered by Capybara.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# expect(page).to have_selector('button')
|
||||
# expect(page).to have_no_selector('button.cls')
|
||||
# expect(page).to have_css('button')
|
||||
# expect(page).to have_no_css('a.cls', exact_text: 'foo')
|
||||
# expect(page).to have_css('table.cls')
|
||||
# expect(page).to have_css('select')
|
||||
#
|
||||
# # good
|
||||
# expect(page).to have_button
|
||||
# expect(page).to have_no_button(class: 'cls')
|
||||
# expect(page).to have_button
|
||||
# expect(page).to have_no_link('foo', class: 'cls')
|
||||
# expect(page).to have_table(class: 'cls')
|
||||
# expect(page).to have_select
|
||||
#
|
||||
class SpecificMatcher < Base
|
||||
MSG = 'Prefer `%<good_matcher>s` over `%<bad_matcher>s`.'
|
||||
RESTRICT_ON_SEND = %i[have_selector have_no_selector have_css
|
||||
have_no_css].freeze
|
||||
SPECIFIC_MATCHER = {
|
||||
'button' => 'button',
|
||||
'a' => 'link',
|
||||
'table' => 'table',
|
||||
'select' => 'select'
|
||||
}.freeze
|
||||
|
||||
# @!method first_argument(node)
|
||||
def_node_matcher :first_argument, <<-PATTERN
|
||||
(send nil? _ (str $_) ... )
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
return unless (arg = first_argument(node))
|
||||
return unless (matcher = specific_matcher(arg))
|
||||
return if acceptable_pattern?(arg)
|
||||
|
||||
add_offense(node, message: message(node, matcher))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def specific_matcher(arg)
|
||||
splitted_arg = arg[/^\w+/, 0]
|
||||
SPECIFIC_MATCHER[splitted_arg]
|
||||
end
|
||||
|
||||
def acceptable_pattern?(arg)
|
||||
arg.match?(/\[.+=\w+\]/) || arg.match?(/[ >,+]/)
|
||||
end
|
||||
|
||||
def message(node, matcher)
|
||||
format(MSG,
|
||||
good_matcher: good_matcher(node, matcher),
|
||||
bad_matcher: node.method_name)
|
||||
end
|
||||
|
||||
def good_matcher(node, matcher)
|
||||
node.method_name
|
||||
.to_s
|
||||
.gsub(/selector|css/, matcher.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,77 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Checks that `context` docstring starts with an allowed prefix.
|
||||
#
|
||||
# The default list of prefixes is minimal. Users are encouraged to tailor
|
||||
# the configuration to meet project needs. Other acceptable prefixes may
|
||||
# include `if`, `unless`, `for`, `before`, `after`, or `during`.
|
||||
# They may consist of multiple words if desired.
|
||||
#
|
||||
# @see https://rspec.rubystyle.guide/#context-descriptions
|
||||
# @see http://www.betterspecs.org/#contexts
|
||||
#
|
||||
# @example `Prefixes` configuration
|
||||
#
|
||||
# # .rubocop.yml
|
||||
# # RSpec/ContextWording:
|
||||
# # Prefixes:
|
||||
# # - when
|
||||
# # - with
|
||||
# # - without
|
||||
# # - if
|
||||
# # - unless
|
||||
# # - for
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# context 'the display name not present' do
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# context 'when the display name is not present' do
|
||||
# # ...
|
||||
# end
|
||||
class ContextWording < Base
|
||||
MSG = 'Start context description with %<prefixes>s.'
|
||||
|
||||
# @!method context_wording(node)
|
||||
def_node_matcher :context_wording, <<-PATTERN
|
||||
(block (send #rspec? { :context :shared_context } $(str #bad_prefix?) ...) ...)
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
context_wording(node) do |context|
|
||||
add_offense(context,
|
||||
message: format(MSG, prefixes: joined_prefixes))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def bad_prefix?(description)
|
||||
!prefix_regex.match?(description)
|
||||
end
|
||||
|
||||
def joined_prefixes
|
||||
quoted = prefixes.map { |prefix| "'#{prefix}'" }
|
||||
return quoted.first if quoted.size == 1
|
||||
|
||||
quoted << "or #{quoted.pop}"
|
||||
quoted.join(', ')
|
||||
end
|
||||
|
||||
def prefixes
|
||||
cop_config['Prefixes'] || []
|
||||
end
|
||||
|
||||
def prefix_regex
|
||||
/^#{Regexp.union(prefixes)}\b/
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -2,6 +2,7 @@
|
||||
RSpec:
|
||||
Enabled: true
|
||||
StyleGuideBaseURL: https://rspec.rubystyle.guide
|
||||
DocumentationBaseURL: https://docs.rubocop.org/rubocop-rspec
|
||||
Include: &1
|
||||
- "**/*_spec.rb"
|
||||
- "**/spec/**/*"
|
||||
@ -61,9 +62,14 @@ RSpec:
|
||||
Pending:
|
||||
- pending
|
||||
Expectations:
|
||||
- are_expected
|
||||
- expect
|
||||
- is_expected
|
||||
- expect_any_instance_of
|
||||
- is_expected
|
||||
- should
|
||||
- should_not
|
||||
- should_not_receive
|
||||
- should_receive
|
||||
Helpers:
|
||||
- let
|
||||
- let!
|
||||
@ -187,8 +193,21 @@ RSpec/BeforeAfterAll:
|
||||
RSpec/ChangeByZero:
|
||||
Description: Prefer negated matchers over `to change.by(0)`.
|
||||
Enabled: pending
|
||||
VersionAdded: 2.11.0
|
||||
VersionAdded: '2.11'
|
||||
VersionChanged: '2.13'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ChangeByZero
|
||||
NegatedMatcher: ~
|
||||
|
||||
RSpec/ClassCheck:
|
||||
Description: Enforces consistent use of `be_a` or `be_kind_of`.
|
||||
StyleGuide: "#is-a-vs-kind-of"
|
||||
Enabled: pending
|
||||
VersionAdded: '2.13'
|
||||
EnforcedStyle: be_a
|
||||
SupportedStyles:
|
||||
- be_a
|
||||
- be_kind_of
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ClassCheck
|
||||
|
||||
RSpec/ContextMethod:
|
||||
Description: "`context` should not be used for specifying methods."
|
||||
@ -204,8 +223,9 @@ RSpec/ContextWording:
|
||||
- when
|
||||
- with
|
||||
- without
|
||||
AllowedPatterns: []
|
||||
VersionAdded: '1.20'
|
||||
VersionChanged: 1.20.1
|
||||
VersionChanged: '2.13'
|
||||
StyleGuide: https://rspec.rubystyle.guide/#context-descriptions
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording
|
||||
|
||||
@ -279,8 +299,9 @@ RSpec/Dialect:
|
||||
RSpec/EmptyExampleGroup:
|
||||
Description: Checks if an example group does not include any tests.
|
||||
Enabled: true
|
||||
SafeAutoCorrect: false
|
||||
VersionAdded: '1.7'
|
||||
VersionChanged: '2.0'
|
||||
VersionChanged: '2.13'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyExampleGroup
|
||||
|
||||
RSpec/EmptyHook:
|
||||
@ -315,8 +336,10 @@ RSpec/EmptyLineAfterHook:
|
||||
Description: Checks if there is an empty line after hook blocks.
|
||||
Enabled: true
|
||||
VersionAdded: '1.27'
|
||||
VersionChanged: '2.13'
|
||||
StyleGuide: https://rspec.rubystyle.guide/#empty-line-after-let
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterHook
|
||||
AllowConsecutiveOneLiners: true
|
||||
|
||||
RSpec/EmptyLineAfterSubject:
|
||||
Description: Checks if there is an empty line after subject block.
|
||||
@ -607,10 +630,18 @@ RSpec/NestedGroups:
|
||||
Description: Checks for nested example groups.
|
||||
Enabled: true
|
||||
Max: 3
|
||||
AllowedGroups: []
|
||||
VersionAdded: '1.7'
|
||||
VersionChanged: '1.10'
|
||||
VersionChanged: '2.13'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NestedGroups
|
||||
|
||||
RSpec/NoExpectationExample:
|
||||
Description: Checks if an example contains any expectation.
|
||||
Enabled: pending
|
||||
Safe: false
|
||||
VersionAdded: '2.13'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NoExpectationExample
|
||||
|
||||
RSpec/NotToNot:
|
||||
Description: Checks for consistent method usage for negating expectations.
|
||||
Enabled: true
|
||||
@ -775,9 +806,10 @@ RSpec/VariableName:
|
||||
SupportedStyles:
|
||||
- snake_case
|
||||
- camelCase
|
||||
AllowedPatterns: []
|
||||
IgnoredPatterns: []
|
||||
VersionAdded: '1.40'
|
||||
VersionChanged: '1.43'
|
||||
VersionChanged: '2.13'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableName
|
||||
|
||||
RSpec/VerifiedDoubleReference:
|
||||
@ -834,6 +866,12 @@ RSpec/Capybara/FeatureMethods:
|
||||
VersionChanged: '2.0'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/FeatureMethods
|
||||
|
||||
RSpec/Capybara/SpecificFinders:
|
||||
Description: Checks if there is a more specific finder offered by Capybara.
|
||||
Enabled: pending
|
||||
VersionAdded: '2.13'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/SpecificFinders
|
||||
|
||||
RSpec/Capybara/SpecificMatcher:
|
||||
Description: Checks for there is a more specific matcher offered by Capybara.
|
||||
Enabled: pending
|
14
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rspec-2.13.1/config/obsoletion.yml
vendored
Normal file
14
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rspec-2.13.1/config/obsoletion.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
#
|
||||
# Configuration of obsolete/deprecated cops used by `ConfigObsoletion`.
|
||||
#
|
||||
# See: https://docs.rubocop.org/rubocop/extensions.html#config-obsoletions
|
||||
#
|
||||
|
||||
# Cop parameters that have been changed
|
||||
# Can be treated as a warning instead of a failure with `severity: warning`
|
||||
changed_parameters:
|
||||
- cops:
|
||||
- RSpec/VariableName
|
||||
parameters: IgnoredPatterns
|
||||
alternative: AllowedPatterns
|
||||
severity: warning
|
@ -5,6 +5,7 @@ require 'yaml'
|
||||
|
||||
require 'rubocop'
|
||||
|
||||
require_relative 'rubocop/rspec'
|
||||
require_relative 'rubocop/rspec/version'
|
||||
require_relative 'rubocop/rspec/inject'
|
||||
require_relative 'rubocop/rspec/node'
|
||||
@ -20,6 +21,8 @@ require_relative 'rubocop/cop/rspec/mixin/final_end_location'
|
||||
require_relative 'rubocop/cop/rspec/mixin/comments_help'
|
||||
require_relative 'rubocop/cop/rspec/mixin/empty_line_separation'
|
||||
require_relative 'rubocop/cop/rspec/mixin/inside_example_group'
|
||||
require_relative 'rubocop/cop/rspec/mixin/namespace'
|
||||
require_relative 'rubocop/cop/rspec/mixin/css_selector'
|
||||
|
||||
require_relative 'rubocop/rspec/concept'
|
||||
require_relative 'rubocop/rspec/example_group'
|
@ -6,16 +6,15 @@ module RuboCop
|
||||
# Checks that left braces for adjacent single line lets are aligned.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# let(:foobar) { blahblah }
|
||||
# let(:baz) { bar }
|
||||
# let(:a) { b }
|
||||
#
|
||||
# # bad
|
||||
# let(:foobar) { blahblah }
|
||||
# let(:baz) { bar }
|
||||
# let(:a) { b }
|
||||
#
|
||||
# # good
|
||||
# let(:foobar) { blahblah }
|
||||
# let(:baz) { bar }
|
||||
# let(:a) { b }
|
||||
# # good
|
||||
# let(:foobar) { blahblah }
|
||||
# let(:baz) { bar }
|
||||
# let(:a) { b }
|
||||
#
|
||||
class AlignLeftLetBrace < Base
|
||||
extend AutoCorrector
|
@ -6,16 +6,15 @@ module RuboCop
|
||||
# Checks that right braces for adjacent single line lets are aligned.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# let(:foobar) { blahblah }
|
||||
# let(:baz) { bar }
|
||||
# let(:a) { b }
|
||||
#
|
||||
# # bad
|
||||
# let(:foobar) { blahblah }
|
||||
# let(:baz) { bar }
|
||||
# let(:a) { b }
|
||||
#
|
||||
# # good
|
||||
# let(:foobar) { blahblah }
|
||||
# let(:baz) { bar }
|
||||
# let(:a) { b }
|
||||
# # good
|
||||
# let(:foobar) { blahblah }
|
||||
# let(:baz) { bar }
|
||||
# let(:a) { b }
|
||||
#
|
||||
class AlignRightLetBrace < Base
|
||||
extend AutoCorrector
|
@ -22,6 +22,7 @@ module RuboCop
|
||||
# allow(my_instance).to receive(:foo)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class AnyInstance < Base
|
||||
MSG = 'Avoid stubbing using `%<method>s`.'
|
||||
RESTRICT_ON_SEND = %i[
|
@ -25,23 +25,29 @@ module RuboCop
|
||||
# some_method
|
||||
# test.run
|
||||
# end
|
||||
#
|
||||
class AroundBlock < Base
|
||||
MSG_NO_ARG = 'Test object should be passed to around block.'
|
||||
MSG_UNUSED_ARG = 'You should call `%<arg>s.call` ' \
|
||||
'or `%<arg>s.run`.'
|
||||
|
||||
# @!method hook(node)
|
||||
def_node_matcher :hook, <<-PATTERN
|
||||
# @!method hook_block(node)
|
||||
def_node_matcher :hook_block, <<-PATTERN
|
||||
(block (send nil? :around sym ?) (args $...) ...)
|
||||
PATTERN
|
||||
|
||||
# @!method hook_numblock(node)
|
||||
def_node_matcher :hook_numblock, <<-PATTERN
|
||||
(numblock (send nil? :around sym ?) ...)
|
||||
PATTERN
|
||||
|
||||
# @!method find_arg_usage(node)
|
||||
def_node_search :find_arg_usage, <<-PATTERN
|
||||
{(send $... {:call :run}) (send _ _ $...) (yield $...) (block-pass $...)}
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
hook(node) do |(example_proxy)|
|
||||
hook_block(node) do |(example_proxy)|
|
||||
if example_proxy.nil?
|
||||
add_no_arg_offense(node)
|
||||
else
|
||||
@ -50,6 +56,12 @@ module RuboCop
|
||||
end
|
||||
end
|
||||
|
||||
def on_numblock(node)
|
||||
hook_numblock(node) do
|
||||
check_for_numblock(node)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def add_no_arg_offense(node)
|
||||
@ -68,6 +80,17 @@ module RuboCop
|
||||
message: format(MSG_UNUSED_ARG, arg: name)
|
||||
)
|
||||
end
|
||||
|
||||
def check_for_numblock(block)
|
||||
find_arg_usage(block) do |usage|
|
||||
return if usage.include?(s(:lvar, :_1))
|
||||
end
|
||||
|
||||
add_offense(
|
||||
block.children.last,
|
||||
message: format(MSG_UNUSED_ARG, arg: :_1)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -10,7 +10,6 @@ module RuboCop
|
||||
# cases it's better to specify what exactly is the expected value.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# expect(foo).to be
|
||||
#
|
@ -10,7 +10,6 @@ module RuboCop
|
||||
# the `be` matcher is preferable as it is a more strict test.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# expect(foo).to eq(true)
|
||||
# expect(foo).to eq(false)
|
@ -11,7 +11,6 @@ module RuboCop
|
||||
# preferable as it is a more strict test.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# expect(foo).to eql(1)
|
||||
# expect(foo).to eql(1.0)
|
@ -23,6 +23,7 @@ module RuboCop
|
||||
# before(:each) { Widget.create }
|
||||
# after(:each) { Widget.delete_all }
|
||||
# end
|
||||
#
|
||||
class BeforeAfterAll < Base
|
||||
MSG = 'Beware of using `%<hook>s` as it may cause state to leak ' \
|
||||
'between tests. If you are using `rspec-rails`, and ' \
|
@ -14,14 +14,20 @@ module RuboCop
|
||||
# which ensures that preceding actions (like `click_link`) have
|
||||
# completed.
|
||||
#
|
||||
# This cop does not support autocorrection in some cases.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# expect(current_path).to eq('/callback')
|
||||
# expect(page.current_path).to match(/widgets/)
|
||||
#
|
||||
# # good
|
||||
# expect(page).to have_current_path("/callback")
|
||||
# expect(page).to have_current_path(/widgets/)
|
||||
# expect(page).to have_current_path('/callback')
|
||||
#
|
||||
# # bad (does not support autocorrection)
|
||||
# expect(page.current_path).to match(variable)
|
||||
#
|
||||
# # good
|
||||
# expect(page).to have_current_path('/callback')
|
||||
#
|
||||
class CurrentPathExpectation < Base
|
||||
extend AutoCorrector
|
@ -40,6 +40,7 @@ module RuboCop
|
||||
# # ...
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class FeatureMethods < Base
|
||||
extend AutoCorrector
|
||||
include InsideExampleGroup
|
||||
@ -68,7 +69,7 @@ module RuboCop
|
||||
...)
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless inside_example_group?(node)
|
||||
|
||||
feature_method(node) do |send_node, match|
|
@ -0,0 +1,86 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
module Capybara
|
||||
# Checks if there is a more specific finder offered by Capybara.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# find('#some-id')
|
||||
# find('[visible][id=some-id]')
|
||||
#
|
||||
# # good
|
||||
# find_by_id('some-id')
|
||||
# find_by_id('some-id', visible: true)
|
||||
#
|
||||
class SpecificFinders < Base
|
||||
extend AutoCorrector
|
||||
|
||||
include RangeHelp
|
||||
|
||||
MSG = 'Prefer `find_by` over `find`.'
|
||||
RESTRICT_ON_SEND = %i[find].freeze
|
||||
|
||||
# @!method find_argument(node)
|
||||
def_node_matcher :find_argument, <<~PATTERN
|
||||
(send _ :find (str $_) ...)
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
find_argument(node) do |arg|
|
||||
next if CssSelector.multiple_selectors?(arg)
|
||||
|
||||
on_attr(node, arg) if attribute?(arg)
|
||||
on_id(node, arg) if CssSelector.id?(arg)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def on_attr(node, arg)
|
||||
return unless (id = CssSelector.attributes(arg)['id'])
|
||||
|
||||
register_offense(node, replaced_arguments(arg, id))
|
||||
end
|
||||
|
||||
def on_id(node, arg)
|
||||
register_offense(node, "'#{arg.to_s.delete('#')}'")
|
||||
end
|
||||
|
||||
def attribute?(arg)
|
||||
CssSelector.attribute?(arg) &&
|
||||
CssSelector.common_attributes?(arg)
|
||||
end
|
||||
|
||||
def register_offense(node, arg_replacement)
|
||||
add_offense(offense_range(node)) do |corrector|
|
||||
corrector.replace(node.loc.selector, 'find_by_id')
|
||||
corrector.replace(node.first_argument.loc.expression,
|
||||
arg_replacement)
|
||||
end
|
||||
end
|
||||
|
||||
def replaced_arguments(arg, id)
|
||||
options = to_options(CssSelector.attributes(arg))
|
||||
options.empty? ? id : "#{id}, #{options}"
|
||||
end
|
||||
|
||||
def to_options(attrs)
|
||||
attrs.each.map do |key, value|
|
||||
next if key == 'id'
|
||||
|
||||
"#{key}: #{value}"
|
||||
end.compact.join(', ')
|
||||
end
|
||||
|
||||
def offense_range(node)
|
||||
range_between(node.loc.selector.begin_pos,
|
||||
node.loc.end.end_pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,158 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
module Capybara
|
||||
# Checks for there is a more specific matcher offered by Capybara.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# expect(page).to have_selector('button')
|
||||
# expect(page).to have_no_selector('button.cls')
|
||||
# expect(page).to have_css('button')
|
||||
# expect(page).to have_no_css('a.cls', href: 'http://example.com')
|
||||
# expect(page).to have_css('table.cls')
|
||||
# expect(page).to have_css('select')
|
||||
# expect(page).to have_css('input', exact_text: 'foo')
|
||||
#
|
||||
# # good
|
||||
# expect(page).to have_button
|
||||
# expect(page).to have_no_button(class: 'cls')
|
||||
# expect(page).to have_button
|
||||
# expect(page).to have_no_link('foo', class: 'cls', href: 'http://example.com')
|
||||
# expect(page).to have_table(class: 'cls')
|
||||
# expect(page).to have_select
|
||||
# expect(page).to have_field('foo')
|
||||
#
|
||||
class SpecificMatcher < Base # rubocop:disable Metrics/ClassLength
|
||||
MSG = 'Prefer `%<good_matcher>s` over `%<bad_matcher>s`.'
|
||||
RESTRICT_ON_SEND = %i[have_selector have_no_selector have_css
|
||||
have_no_css].freeze
|
||||
SPECIFIC_MATCHER = {
|
||||
'button' => 'button',
|
||||
'a' => 'link',
|
||||
'table' => 'table',
|
||||
'select' => 'select',
|
||||
'input' => 'field'
|
||||
}.freeze
|
||||
SPECIFIC_MATCHER_OPTIONS = {
|
||||
'button' => (
|
||||
CssSelector::COMMON_OPTIONS + %w[disabled name value title type]
|
||||
).freeze,
|
||||
'link' => (
|
||||
CssSelector::COMMON_OPTIONS + %w[href alt title download]
|
||||
).freeze,
|
||||
'table' => (
|
||||
CssSelector::COMMON_OPTIONS + %w[
|
||||
caption with_cols cols with_rows rows
|
||||
]
|
||||
).freeze,
|
||||
'select' => (
|
||||
CssSelector::COMMON_OPTIONS + %w[
|
||||
disabled name placeholder options enabled_options
|
||||
disabled_options selected with_selected multiple with_options
|
||||
]
|
||||
).freeze,
|
||||
'field' => (
|
||||
CssSelector::COMMON_OPTIONS + %w[
|
||||
checked unchecked disabled valid name placeholder
|
||||
validation_message readonly with type multiple
|
||||
]
|
||||
).freeze
|
||||
}.freeze
|
||||
SPECIFIC_MATCHER_PSEUDO_CLASSES = %w[
|
||||
not() disabled enabled checked unchecked
|
||||
].freeze
|
||||
|
||||
# @!method first_argument(node)
|
||||
def_node_matcher :first_argument, <<-PATTERN
|
||||
(send nil? _ (str $_) ... )
|
||||
PATTERN
|
||||
|
||||
# @!method option?(node)
|
||||
def_node_search :option?, <<-PATTERN
|
||||
(pair (sym %) _)
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
first_argument(node) do |arg|
|
||||
next unless (matcher = specific_matcher(arg))
|
||||
next if CssSelector.multiple_selectors?(arg)
|
||||
next unless specific_matcher_option?(node, arg, matcher)
|
||||
next unless specific_matcher_pseudo_classes?(arg)
|
||||
|
||||
add_offense(node, message: message(node, matcher))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def specific_matcher(arg)
|
||||
splitted_arg = arg[/^\w+/, 0]
|
||||
SPECIFIC_MATCHER[splitted_arg]
|
||||
end
|
||||
|
||||
def specific_matcher_option?(node, arg, matcher)
|
||||
attrs = CssSelector.attributes(arg).keys
|
||||
return true if attrs.empty?
|
||||
return false unless replaceable_matcher?(node, matcher, attrs)
|
||||
|
||||
attrs.all? do |attr|
|
||||
SPECIFIC_MATCHER_OPTIONS.fetch(matcher, []).include?(attr)
|
||||
end
|
||||
end
|
||||
|
||||
def specific_matcher_pseudo_classes?(arg)
|
||||
CssSelector.pseudo_classes(arg).all? do |pseudo_class|
|
||||
replaceable_pseudo_class?(pseudo_class, arg)
|
||||
end
|
||||
end
|
||||
|
||||
def replaceable_pseudo_class?(pseudo_class, arg)
|
||||
unless SPECIFIC_MATCHER_PSEUDO_CLASSES.include?(pseudo_class)
|
||||
return false
|
||||
end
|
||||
|
||||
case pseudo_class
|
||||
when 'not()' then replaceable_pseudo_class_not?(arg)
|
||||
else true
|
||||
end
|
||||
end
|
||||
|
||||
def replaceable_pseudo_class_not?(arg)
|
||||
arg.scan(/not\(.*?\)/).all? do |not_arg|
|
||||
CssSelector.attributes(not_arg).values.all? do |v|
|
||||
v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def replaceable_matcher?(node, matcher, attrs)
|
||||
case matcher
|
||||
when 'link' then replaceable_to_have_link?(node, attrs)
|
||||
else true
|
||||
end
|
||||
end
|
||||
|
||||
def replaceable_to_have_link?(node, attrs)
|
||||
option?(node, :href) || attrs.include?('href')
|
||||
end
|
||||
|
||||
def message(node, matcher)
|
||||
format(MSG,
|
||||
good_matcher: good_matcher(node, matcher),
|
||||
bad_matcher: node.method_name)
|
||||
end
|
||||
|
||||
def good_matcher(node, matcher)
|
||||
node.method_name
|
||||
.to_s
|
||||
.gsub(/selector|css/, matcher.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -16,7 +16,6 @@ module RuboCop
|
||||
# https://www.rubydoc.info/gems/capybara/Capybara%2FNode%2FFinders:all[the documentation].
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# expect(page).to have_selector('.foo', visible: false)
|
||||
# expect(page).to have_css('.foo', visible: true)
|
@ -5,12 +5,20 @@ module RuboCop
|
||||
module RSpec
|
||||
# Prefer negated matchers over `to change.by(0)`.
|
||||
#
|
||||
# @example
|
||||
# In the case of composite expectations, cop suggest using the
|
||||
# negation matchers of `RSpec::Matchers#change`.
|
||||
#
|
||||
# By default the cop does not support autocorrect of
|
||||
# compound expectations, but if you set the
|
||||
# negated matcher for `change`, e.g. `not_change` with
|
||||
# the `NegatedMatcher` option, the cop will perform the autocorrection.
|
||||
#
|
||||
# @example NegatedMatcher: ~ (default)
|
||||
# # bad
|
||||
# expect { run }.to change(Foo, :bar).by(0)
|
||||
# expect { run }.to change { Foo.bar }.by(0)
|
||||
#
|
||||
# # bad - compound expectations
|
||||
# # bad - compound expectations (does not support autocorrection)
|
||||
# expect { run }
|
||||
# .to change(Foo, :bar).by(0)
|
||||
# .and change(Foo, :baz).by(0)
|
||||
@ -31,10 +39,28 @@ module RuboCop
|
||||
# .to not_change { Foo.bar }
|
||||
# .and not_change { Foo.baz }
|
||||
#
|
||||
# @example NegatedMatcher: not_change
|
||||
# # bad (support autocorrection to good case)
|
||||
# expect { run }
|
||||
# .to change(Foo, :bar).by(0)
|
||||
# .and change(Foo, :baz).by(0)
|
||||
# expect { run }
|
||||
# .to change { Foo.bar }.by(0)
|
||||
# .and change { Foo.baz }.by(0)
|
||||
#
|
||||
# # good
|
||||
# define_negated_matcher :not_change, :change
|
||||
# expect { run }
|
||||
# .to not_change(Foo, :bar)
|
||||
# .and not_change(Foo, :baz)
|
||||
# expect { run }
|
||||
# .to not_change { Foo.bar }
|
||||
# .and not_change { Foo.baz }
|
||||
#
|
||||
class ChangeByZero < Base
|
||||
extend AutoCorrector
|
||||
MSG = 'Prefer `not_to change` over `to change.by(0)`.'
|
||||
MSG_COMPOUND = 'Prefer negated matchers with compound expectations ' \
|
||||
MSG_COMPOUND = 'Prefer %<preferred>s with compound expectations ' \
|
||||
'over `change.by(0)`.'
|
||||
RESTRICT_ON_SEND = %i[change].freeze
|
||||
|
||||
@ -55,6 +81,11 @@ module RuboCop
|
||||
(int 0))
|
||||
PATTERN
|
||||
|
||||
# @!method change_nodes(node)
|
||||
def_node_search :change_nodes, <<-PATTERN
|
||||
$(send nil? :change ...)
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
expect_change_with_arguments(node.parent) do
|
||||
check_offense(node.parent)
|
||||
@ -70,7 +101,9 @@ module RuboCop
|
||||
def check_offense(node)
|
||||
expression = node.loc.expression
|
||||
if compound_expectations?(node)
|
||||
add_offense(expression, message: MSG_COMPOUND)
|
||||
add_offense(expression, message: message_compound) do |corrector|
|
||||
autocorrect_compound(corrector, node)
|
||||
end
|
||||
else
|
||||
add_offense(expression) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
@ -79,7 +112,7 @@ module RuboCop
|
||||
end
|
||||
|
||||
def compound_expectations?(node)
|
||||
%i[and or].include?(node.parent.method_name)
|
||||
%i[and or & |].include?(node.parent.method_name)
|
||||
end
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
@ -87,6 +120,28 @@ module RuboCop
|
||||
range = node.loc.dot.with(end_pos: node.loc.expression.end_pos)
|
||||
corrector.remove(range)
|
||||
end
|
||||
|
||||
def autocorrect_compound(corrector, node)
|
||||
return unless negated_matcher
|
||||
|
||||
change_nodes(node) do |change_node|
|
||||
corrector.replace(change_node.loc.selector, negated_matcher)
|
||||
range = node.loc.dot.with(end_pos: node.loc.expression.end_pos)
|
||||
corrector.remove(range)
|
||||
end
|
||||
end
|
||||
|
||||
def negated_matcher
|
||||
cop_config['NegatedMatcher']
|
||||
end
|
||||
|
||||
def message_compound
|
||||
format(MSG_COMPOUND, preferred: preferred_method)
|
||||
end
|
||||
|
||||
def preferred_method
|
||||
negated_matcher ? "`#{negated_matcher}`" : 'negated matchers'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,101 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Enforces consistent use of `be_a` or `be_kind_of`.
|
||||
#
|
||||
# @example EnforcedStyle: be_a (default)
|
||||
# # bad
|
||||
# expect(object).to be_kind_of(String)
|
||||
# expect(object).to be_a_kind_of(String)
|
||||
#
|
||||
# # good
|
||||
# expect(object).to be_a(String)
|
||||
# expect(object).to be_an(String)
|
||||
#
|
||||
# @example EnforcedStyle: be_kind_of
|
||||
# # bad
|
||||
# expect(object).to be_a(String)
|
||||
# expect(object).to be_an(String)
|
||||
#
|
||||
# # good
|
||||
# expect(object).to be_kind_of(String)
|
||||
# expect(object).to be_a_kind_of(String)
|
||||
#
|
||||
class ClassCheck < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
MSG = 'Prefer `%<preferred>s` over `%<current>s`.'
|
||||
|
||||
METHOD_NAMES_FOR_BE_A = ::Set[
|
||||
:be_a,
|
||||
:be_an
|
||||
].freeze
|
||||
|
||||
METHOD_NAMES_FOR_KIND_OF = ::Set[
|
||||
:be_a_kind_of,
|
||||
:be_kind_of
|
||||
].freeze
|
||||
|
||||
PREFERRED_METHOD_NAME_BY_STYLE = {
|
||||
be_a: :be_a,
|
||||
be_kind_of: :be_kind_of
|
||||
}.freeze
|
||||
|
||||
RESTRICT_ON_SEND = %i[
|
||||
be_a
|
||||
be_a_kind_of
|
||||
be_an
|
||||
be_kind_of
|
||||
].freeze
|
||||
|
||||
def on_send(node)
|
||||
return unless offending?(node)
|
||||
|
||||
add_offense(
|
||||
node.loc.selector,
|
||||
message: format_message(node)
|
||||
) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
corrector.replace(node.loc.selector, preferred_method_name)
|
||||
end
|
||||
|
||||
def format_message(node)
|
||||
format(
|
||||
MSG,
|
||||
current: node.method_name,
|
||||
preferred: preferred_method_name
|
||||
)
|
||||
end
|
||||
|
||||
def offending?(node)
|
||||
!node.receiver && !preferred_method_name?(node.method_name)
|
||||
end
|
||||
|
||||
def preferred_method_name?(method_name)
|
||||
preferred_method_names.include?(method_name)
|
||||
end
|
||||
|
||||
def preferred_method_name
|
||||
PREFERRED_METHOD_NAME_BY_STYLE[style]
|
||||
end
|
||||
|
||||
def preferred_method_names
|
||||
if style == :be_a
|
||||
METHOD_NAMES_FOR_BE_A
|
||||
else
|
||||
METHOD_NAMES_FOR_KIND_OF
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -23,6 +23,7 @@ module RuboCop
|
||||
# describe '.foo_bar' do
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
class ContextMethod < Base
|
||||
extend AutoCorrector
|
||||
|
||||
@ -33,7 +34,7 @@ module RuboCop
|
||||
(block (send #rspec? :context $(str #method_name?) ...) ...)
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
context_method(node) do |context|
|
||||
add_offense(context) do |corrector|
|
||||
corrector.replace(node.send_node.loc.selector, 'describe')
|
@ -0,0 +1,108 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Checks that `context` docstring starts with an allowed prefix.
|
||||
#
|
||||
# The default list of prefixes is minimal. Users are encouraged to tailor
|
||||
# the configuration to meet project needs. Other acceptable prefixes may
|
||||
# include `if`, `unless`, `for`, `before`, `after`, or `during`.
|
||||
# They may consist of multiple words if desired.
|
||||
#
|
||||
# @see https://rspec.rubystyle.guide/#context-descriptions
|
||||
# @see http://www.betterspecs.org/#contexts
|
||||
#
|
||||
# @example `Prefixes` configuration
|
||||
# # .rubocop.yml
|
||||
# # RSpec/ContextWording:
|
||||
# # Prefixes:
|
||||
# # - when
|
||||
# # - with
|
||||
# # - without
|
||||
# # - if
|
||||
# # - unless
|
||||
# # - for
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# context 'the display name not present' do
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# context 'when the display name is not present' do
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
# This cop can be customized allowed context description pattern
|
||||
# with `AllowedPatterns`. By default, there are no checking by pattern.
|
||||
#
|
||||
# @example `AllowedPatterns` configuration
|
||||
#
|
||||
# # .rubocop.yml
|
||||
# # RSpec/ContextWording:
|
||||
# # AllowedPatterns:
|
||||
# # - /とき$/
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# context '条件を満たす' do
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# context '条件を満たすとき' do
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
class ContextWording < Base
|
||||
include AllowedPattern
|
||||
|
||||
MSG = 'Context description should match %<patterns>s.'
|
||||
|
||||
# @!method context_wording(node)
|
||||
def_node_matcher :context_wording, <<-PATTERN
|
||||
(block (send #rspec? { :context :shared_context } $(str $_) ...) ...)
|
||||
PATTERN
|
||||
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
context_wording(node) do |context, description|
|
||||
if bad_pattern?(description)
|
||||
message = format(MSG, patterns: expect_patterns)
|
||||
add_offense(context, message: message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def allowed_patterns
|
||||
super + prefix_regexes
|
||||
end
|
||||
|
||||
def prefix_regexes
|
||||
@prefix_regexes ||= prefixes.map { |pre| /^#{Regexp.escape(pre)}\b/ }
|
||||
end
|
||||
|
||||
def bad_pattern?(description)
|
||||
return false if allowed_patterns.empty?
|
||||
|
||||
!matches_allowed_pattern?(description)
|
||||
end
|
||||
|
||||
def expect_patterns
|
||||
inspected = allowed_patterns.map(&:inspect)
|
||||
return inspected.first if inspected.size == 1
|
||||
|
||||
inspected << "or #{inspected.pop}"
|
||||
inspected.join(', ')
|
||||
end
|
||||
|
||||
def prefixes
|
||||
Array(cop_config.fetch('Prefixes', []))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -10,7 +10,6 @@ module RuboCop
|
||||
# Ignores Rails and Aruba `type` metadata by default.
|
||||
#
|
||||
# @example `IgnoredMetadata` configuration
|
||||
#
|
||||
# # .rubocop.yml
|
||||
# # RSpec/DescribeClass:
|
||||
# # IgnoredMetadata:
|
||||
@ -34,6 +33,7 @@ module RuboCop
|
||||
#
|
||||
# describe "A feature example", type: :feature do
|
||||
# end
|
||||
#
|
||||
class DescribeClass < Base
|
||||
include TopLevelGroup
|
||||
|
@ -16,6 +16,7 @@ module RuboCop
|
||||
#
|
||||
# describe MyClass, '.my_class_method' do
|
||||
# end
|
||||
#
|
||||
class DescribeMethod < Base
|
||||
include TopLevelGroup
|
||||
|
@ -57,6 +57,7 @@ module RuboCop
|
||||
class DescribedClass < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
include Namespace
|
||||
|
||||
DESCRIBED_CLASS = 'described_class'
|
||||
MSG = 'Use `%<replacement>s` instead of `%<src>s`.'
|
||||
@ -81,7 +82,7 @@ module RuboCop
|
||||
def_node_search :contains_described_class?,
|
||||
'(send nil? :described_class)'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
# In case the explicit style is used, we need to remember what's
|
||||
# being described.
|
||||
@described_class, body = described_constant(node)
|
||||
@ -160,7 +161,8 @@ module RuboCop
|
||||
end
|
||||
|
||||
def full_const_name(node)
|
||||
collapse_namespace(namespace(node), const_name(node))
|
||||
symbolized_namespace = namespace(node).map(&:to_sym)
|
||||
collapse_namespace(symbolized_namespace, const_name(node))
|
||||
end
|
||||
|
||||
# @param namespace [Array<Symbol>]
|
||||
@ -200,18 +202,6 @@ module RuboCop
|
||||
[nil, name]
|
||||
end
|
||||
end
|
||||
|
||||
# @param node [RuboCop::AST::Node]
|
||||
# @return [Array<Symbol>]
|
||||
# @example
|
||||
# namespace(node) # => [:A, :B, :C]
|
||||
def namespace(node)
|
||||
node
|
||||
.each_ancestor(:class, :module)
|
||||
.reverse_each
|
||||
.flat_map { |ancestor| ancestor.defined_module_name.split('::') }
|
||||
.map(&:to_sym)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -41,6 +41,7 @@ module RuboCop
|
||||
# describe 'display name presence' do
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
class Dialect < Base
|
||||
extend AutoCorrector
|
||||
include MethodPreference
|
@ -6,7 +6,6 @@ module RuboCop
|
||||
# Checks if an example group does not include any tests.
|
||||
#
|
||||
# @example usage
|
||||
#
|
||||
# # bad
|
||||
# describe Bacon do
|
||||
# let(:bacon) { Bacon.new(chunkiness) }
|
||||
@ -35,7 +34,12 @@ module RuboCop
|
||||
# describe Bacon do
|
||||
# pending 'will add tests later'
|
||||
# end
|
||||
#
|
||||
class EmptyExampleGroup < Base
|
||||
extend AutoCorrector
|
||||
|
||||
include RangeHelp
|
||||
|
||||
MSG = 'Empty example group detected.'
|
||||
|
||||
# @!method example_group_body(node)
|
||||
@ -119,7 +123,7 @@ module RuboCop
|
||||
# describe { it { i_run_as_well } }
|
||||
#
|
||||
# @example source that does not match
|
||||
# before { it { whatever here wont run anyway } }
|
||||
# before { it { whatever here won't run anyway } }
|
||||
#
|
||||
# @param node [RuboCop::AST::Node]
|
||||
# @return [Array<RuboCop::AST::Node>] matching nodes
|
||||
@ -130,12 +134,16 @@ module RuboCop
|
||||
}
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return if node.each_ancestor(:def, :defs).any?
|
||||
return if node.each_ancestor(:block).any? { |block| example?(block) }
|
||||
|
||||
example_group_body(node) do |body|
|
||||
add_offense(node.send_node) if offensive?(body)
|
||||
next unless offensive?(body)
|
||||
|
||||
add_offense(node.send_node) do |corrector|
|
||||
corrector.remove(removed_range(node))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -163,6 +171,13 @@ module RuboCop
|
||||
def examples_in_branches?(condition_node)
|
||||
condition_node.branches.any? { |branch| examples?(branch) }
|
||||
end
|
||||
|
||||
def removed_range(node)
|
||||
range_by_whole_lines(
|
||||
node.location.expression,
|
||||
include_final_newline: true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -22,6 +22,7 @@ module RuboCop
|
||||
# create_feed
|
||||
# end
|
||||
# after(:all) { cleanup_feed }
|
||||
#
|
||||
class EmptyHook < Base
|
||||
extend AutoCorrector
|
||||
include RuboCop::Cop::RangeHelp
|
||||
@ -33,7 +34,7 @@ module RuboCop
|
||||
(block $#{send_pattern('#Hooks.all')} _ nil?)
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
empty_hook?(node) do |hook|
|
||||
add_offense(hook) do |corrector|
|
||||
corrector.remove(
|
@ -30,7 +30,6 @@ module RuboCop
|
||||
# end
|
||||
#
|
||||
# @example with AllowConsecutiveOneLiners configuration
|
||||
#
|
||||
# # rubocop.yml
|
||||
# # RSpec/EmptyLineAfterExample:
|
||||
# # AllowConsecutiveOneLiners: false
|
||||
@ -47,7 +46,7 @@ module RuboCop
|
||||
|
||||
MSG = 'Add an empty line after `%<example>s`.'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example?(node)
|
||||
return if allowed_one_liner?(node)
|
||||
|
||||
@ -65,19 +64,15 @@ module RuboCop
|
||||
end
|
||||
|
||||
def consecutive_one_liner?(node)
|
||||
node.line_count == 1 && next_one_line_example?(node)
|
||||
node.single_line? && next_one_line_example?(node)
|
||||
end
|
||||
|
||||
def next_one_line_example?(node)
|
||||
next_sibling = next_sibling(node)
|
||||
next_sibling = node.right_sibling
|
||||
return unless next_sibling
|
||||
return unless example?(next_sibling)
|
||||
|
||||
next_sibling.line_count == 1
|
||||
end
|
||||
|
||||
def next_sibling(node)
|
||||
node.parent.children[node.sibling_index + 1]
|
||||
next_sibling.single_line?
|
||||
end
|
||||
end
|
||||
end
|
@ -29,7 +29,7 @@ module RuboCop
|
||||
|
||||
MSG = 'Add an empty line after `%<example_group>s`.'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example_group?(node)
|
||||
|
||||
missing_separating_line_offense(node) do |method|
|
@ -16,13 +16,14 @@ module RuboCop
|
||||
# let(:something) { other }
|
||||
#
|
||||
# it { does_something }
|
||||
#
|
||||
class EmptyLineAfterFinalLet < Base
|
||||
extend AutoCorrector
|
||||
include EmptyLineSeparation
|
||||
|
||||
MSG = 'Add an empty line after the last `%<let>s`.'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example_group_with_body?(node)
|
||||
|
||||
final_let = node.body.child_nodes.reverse.find { |child| let?(child) }
|
@ -5,6 +5,9 @@ module RuboCop
|
||||
module RSpec
|
||||
# Checks if there is an empty line after hook blocks.
|
||||
#
|
||||
# `AllowConsecutiveOneLiners` configures whether adjacent
|
||||
# one-line definitions are considered an offense.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# before { do_something }
|
||||
@ -19,11 +22,23 @@ module RuboCop
|
||||
# it { does_something }
|
||||
#
|
||||
# # good
|
||||
# before { do_something }
|
||||
# after { do_something }
|
||||
#
|
||||
# it { does_something }
|
||||
#
|
||||
# # good
|
||||
# # fair - it's ok to have non-separated one-liners hooks
|
||||
# around { |test| test.run }
|
||||
# after { do_something }
|
||||
#
|
||||
# it { does_something }
|
||||
#
|
||||
# @example with AllowConsecutiveOneLiners configuration
|
||||
# # rubocop.yml
|
||||
# # RSpec/EmptyLineAfterHook:
|
||||
# # AllowConsecutiveOneLiners: false
|
||||
#
|
||||
# # bad
|
||||
# around { |test| test.run }
|
||||
# after { do_something }
|
||||
#
|
||||
# it { does_something }
|
||||
@ -31,21 +46,36 @@ module RuboCop
|
||||
# # good
|
||||
# around { |test| test.run }
|
||||
#
|
||||
# after { do_something }
|
||||
#
|
||||
# it { does_something }
|
||||
#
|
||||
class EmptyLineAfterHook < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
include EmptyLineSeparation
|
||||
|
||||
MSG = 'Add an empty line after `%<hook>s`.'
|
||||
|
||||
def on_block(node)
|
||||
return unless hook?(node)
|
||||
return if cop_config['AllowConsecutiveOneLiners'] &&
|
||||
chained_single_line_hooks?(node)
|
||||
|
||||
missing_separating_line_offense(node) do |method|
|
||||
format(MSG, hook: method)
|
||||
end
|
||||
end
|
||||
|
||||
alias on_numblock on_block
|
||||
|
||||
private
|
||||
|
||||
def chained_single_line_hooks?(node)
|
||||
next_node = node.right_sibling
|
||||
|
||||
hook?(next_node) && node.single_line? && next_node.single_line?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -14,6 +14,7 @@ module RuboCop
|
||||
# subject(:obj) { described_class }
|
||||
#
|
||||
# let(:foo) { bar }
|
||||
#
|
||||
class EmptyLineAfterSubject < Base
|
||||
extend AutoCorrector
|
||||
include EmptyLineSeparation
|
||||
@ -21,7 +22,7 @@ module RuboCop
|
||||
|
||||
MSG = 'Add an empty line after `%<subject>s`.'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless subject?(node)
|
||||
return unless inside_example_group?(node)
|
||||
|
@ -47,12 +47,13 @@ module RuboCop
|
||||
# content.
|
||||
# HEREDOC
|
||||
# end # 5 points
|
||||
#
|
||||
class ExampleLength < Base
|
||||
include CodeLength
|
||||
|
||||
LABEL = 'Example'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example?(node)
|
||||
|
||||
check_code_length(node)
|
@ -47,6 +47,7 @@ module RuboCop
|
||||
# result = service.call
|
||||
# expect(result).to be(true)
|
||||
# end
|
||||
#
|
||||
class ExampleWithoutDescription < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
@ -57,7 +58,7 @@ module RuboCop
|
||||
# @!method example_description(node)
|
||||
def_node_matcher :example_description, '(send nil? _ $(str $_))'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example?(node)
|
||||
|
||||
check_example_without_description(node.send_node)
|
@ -29,6 +29,7 @@ module RuboCop
|
||||
# # good
|
||||
# it 'does things' do
|
||||
# end
|
||||
#
|
||||
class ExampleWording < Base
|
||||
extend AutoCorrector
|
||||
|
||||
@ -46,7 +47,7 @@ module RuboCop
|
||||
} ...) ...)
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
it_description(node) do |description_node, message|
|
||||
if message.match?(SHOULD_PREFIX)
|
||||
add_wording_offense(description_node, MSG_SHOULD)
|
@ -22,6 +22,7 @@ module RuboCop
|
||||
# # good
|
||||
# context 'when a condition is met' do
|
||||
# end
|
||||
#
|
||||
class ExcessiveDocstringSpacing < Base
|
||||
extend AutoCorrector
|
||||
|
@ -18,6 +18,9 @@ module RuboCop
|
||||
# expect(pattern).to eq(/foo/)
|
||||
# expect(name).to eq("John")
|
||||
#
|
||||
# # bad (not supported autocorrection)
|
||||
# expect(false).to eq(true)
|
||||
#
|
||||
class ExpectActual < Base
|
||||
extend AutoCorrector
|
||||
|
@ -69,7 +69,7 @@ module RuboCop
|
||||
end
|
||||
end
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless style == :method_call
|
||||
|
||||
expect_change_with_block(node) do |receiver, message|
|
@ -20,13 +20,14 @@ module RuboCop
|
||||
# it do
|
||||
# expect(something).to eq 'foo'
|
||||
# end
|
||||
#
|
||||
class ExpectInHook < Base
|
||||
MSG = 'Do not use `%<expect>s` in `%<hook>s` hook'
|
||||
|
||||
# @!method expectation(node)
|
||||
def_node_search :expectation, send_pattern('#Expectations.all')
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless hook?(node)
|
||||
return if node.body.nil?
|
||||
|
||||
@ -36,6 +37,8 @@ module RuboCop
|
||||
end
|
||||
end
|
||||
|
||||
alias on_numblock on_block
|
||||
|
||||
private
|
||||
|
||||
def message(expect, hook)
|
@ -14,6 +14,7 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# expect { my_app.print_report }.to output('Hello World').to_stdout
|
||||
#
|
||||
class ExpectOutput < Base
|
||||
MSG = 'Use `expect { ... }.to output(...).to_%<name>s` ' \
|
||||
'instead of mutating $%<name>s.'
|
@ -24,6 +24,7 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# count { 1 }
|
||||
#
|
||||
class AttributeDefinedStatically < Base
|
||||
extend AutoCorrector
|
||||
|
||||
@ -39,7 +40,7 @@ module RuboCop
|
||||
(block (send _ #attribute_defining_method? ...) _ { (begin $...) $(send ...) } )
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
attributes = factory_attributes(node) || []
|
||||
attributes = [attributes] unless attributes.is_a?(Array) # rubocop:disable Style/ArrayCoercion, Lint/RedundantCopDisableDirective
|
||||
|
@ -30,6 +30,7 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# 3.times { create :user }
|
||||
#
|
||||
class CreateList < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
@ -39,20 +40,23 @@ module RuboCop
|
||||
MSG_N_TIMES = 'Prefer %<number>s.times.'
|
||||
RESTRICT_ON_SEND = %i[create_list].freeze
|
||||
|
||||
# @!method n_times_block?(node)
|
||||
def_node_matcher :n_times_block?, <<-PATTERN
|
||||
# @!method array_new_or_n_times_block?(node)
|
||||
def_node_matcher :array_new_or_n_times_block?, <<-PATTERN
|
||||
(block
|
||||
(send (int _) :times)
|
||||
{
|
||||
(send (const {nil? | cbase} :Array) :new (int _)) |
|
||||
(send (int _) :times)
|
||||
}
|
||||
...
|
||||
)
|
||||
PATTERN
|
||||
|
||||
# @!method n_times_block_with_arg_and_used?(node)
|
||||
def_node_matcher :n_times_block_with_arg_and_used?, <<-PATTERN
|
||||
# @!method block_with_arg_and_used?(node)
|
||||
def_node_matcher :block_with_arg_and_used?, <<-PATTERN
|
||||
(block
|
||||
(send (int _) :times)
|
||||
_
|
||||
(args (arg _value))
|
||||
`_value
|
||||
`_value
|
||||
)
|
||||
PATTERN
|
||||
|
||||
@ -71,11 +75,11 @@ module RuboCop
|
||||
(send {nil? #factory_bot?} :create_list (sym _) (int $_) ...)
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:todo InternalAffairs/NumblockHandler
|
||||
return unless style == :create_list
|
||||
|
||||
return unless n_times_block?(node)
|
||||
return if n_times_block_with_arg_and_used?(node)
|
||||
return unless array_new_or_n_times_block?(node)
|
||||
return if block_with_arg_and_used?(node)
|
||||
return unless node.body
|
||||
return if arguments_include_method_call?(node.body)
|
||||
return unless contains_only_factory?(node.body)
|
||||
@ -183,7 +187,7 @@ module RuboCop
|
||||
|
||||
def call_with_block_replacement(node)
|
||||
block = node.body
|
||||
arguments = build_arguments(block, node.receiver.source)
|
||||
arguments = build_arguments(block, count_from(node))
|
||||
replacement = format_receiver(block.receiver)
|
||||
replacement += format_method_call(block, 'create_list', arguments)
|
||||
replacement += format_block(block)
|
||||
@ -203,7 +207,7 @@ module RuboCop
|
||||
block = node.body
|
||||
factory, *options = *block.arguments
|
||||
|
||||
arguments = "#{factory.source}, #{node.receiver.source}"
|
||||
arguments = "#{factory.source}, #{count_from(node)}"
|
||||
options = build_options_string(options)
|
||||
arguments += ", #{options}" unless options.empty?
|
||||
|
||||
@ -212,6 +216,16 @@ module RuboCop
|
||||
replacement
|
||||
end
|
||||
|
||||
def count_from(node)
|
||||
count_node =
|
||||
if node.receiver.int_type?
|
||||
node.receiver
|
||||
else
|
||||
node.send_node.first_argument
|
||||
end
|
||||
count_node.source
|
||||
end
|
||||
|
||||
def format_block(node)
|
||||
if node.body.begin_type?
|
||||
format_multiline_block(node)
|
@ -19,6 +19,7 @@ module RuboCop
|
||||
# # good
|
||||
# factory :foo, class: 'Foo' do
|
||||
# end
|
||||
#
|
||||
class FactoryClassName < Base
|
||||
extend AutoCorrector
|
||||
|
@ -58,6 +58,7 @@ module RuboCop
|
||||
#
|
||||
class FilePath < Base
|
||||
include TopLevelGroup
|
||||
include Namespace
|
||||
|
||||
MSG = 'Spec path should end with `%<suffix>s`.'
|
||||
|
||||
@ -101,7 +102,7 @@ module RuboCop
|
||||
|
||||
def pattern_for(example_group, method_name)
|
||||
if spec_suffix_only? || !example_group.const_type?
|
||||
return pattern_for_spec_suffix_only?
|
||||
return pattern_for_spec_suffix_only
|
||||
end
|
||||
|
||||
[
|
||||
@ -111,7 +112,7 @@ module RuboCop
|
||||
].join
|
||||
end
|
||||
|
||||
def pattern_for_spec_suffix_only?
|
||||
def pattern_for_spec_suffix_only
|
||||
'.*_spec\.rb'
|
||||
end
|
||||
|
||||
@ -123,8 +124,10 @@ module RuboCop
|
||||
end
|
||||
|
||||
def expected_path(constant)
|
||||
constants = namespace(constant) + constant.const_name.split('::')
|
||||
|
||||
File.join(
|
||||
constant.const_name.split('::').map do |name|
|
||||
constants.map do |name|
|
||||
custom_transform.fetch(name) { camel_to_snake_case(name) }
|
||||
end
|
||||
)
|
@ -5,6 +5,8 @@ module RuboCop
|
||||
module RSpec
|
||||
# Checks if examples are focused.
|
||||
#
|
||||
# This cop does not support autocorrection in some cases.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# describe MyClass, focus: true do
|
||||
@ -19,6 +21,22 @@ module RuboCop
|
||||
# # good
|
||||
# describe MyClass do
|
||||
# end
|
||||
#
|
||||
# # bad
|
||||
# fdescribe 'test' do; end
|
||||
#
|
||||
# # good
|
||||
# describe 'test' do; end
|
||||
#
|
||||
# # bad
|
||||
# fdescribe 'test' do; end
|
||||
#
|
||||
# # good
|
||||
# describe 'test' do; end
|
||||
#
|
||||
# # bad (does not support autocorrection)
|
||||
# focus 'test' do; end
|
||||
#
|
||||
class Focus < Base
|
||||
extend AutoCorrector
|
||||
include RangeHelp
|
@ -57,6 +57,7 @@ module RuboCop
|
||||
# before(:example) do
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
class HookArgument < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
@ -66,11 +67,13 @@ module RuboCop
|
||||
|
||||
# @!method scoped_hook(node)
|
||||
def_node_matcher :scoped_hook, <<-PATTERN
|
||||
(block $(send _ #Hooks.all (sym ${:each :example})) ...)
|
||||
({block numblock} $(send _ #Hooks.all (sym ${:each :example})) ...)
|
||||
PATTERN
|
||||
|
||||
# @!method unscoped_hook(node)
|
||||
def_node_matcher :unscoped_hook, '(block $(send _ #Hooks.all) ...)'
|
||||
def_node_matcher :unscoped_hook, <<-PATTERN
|
||||
({block numblock} $(send _ #Hooks.all) ...)
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
hook(node) do |method_send, scope_name|
|
||||
@ -86,6 +89,8 @@ module RuboCop
|
||||
end
|
||||
end
|
||||
|
||||
alias on_numblock on_block
|
||||
|
||||
private
|
||||
|
||||
def check_implicit(method_send)
|
@ -6,8 +6,7 @@ module RuboCop
|
||||
# Checks for before/around/after hooks that come after an example.
|
||||
#
|
||||
# @example
|
||||
# # Bad
|
||||
#
|
||||
# # bad
|
||||
# it 'checks what foo does' do
|
||||
# expect(foo).to be
|
||||
# end
|
||||
@ -15,7 +14,7 @@ module RuboCop
|
||||
# before { prepare }
|
||||
# after { clean_up }
|
||||
#
|
||||
# # Good
|
||||
# # good
|
||||
# before { prepare }
|
||||
# after { clean_up }
|
||||
#
|
||||
@ -32,6 +31,7 @@ module RuboCop
|
||||
def_node_matcher :example_or_group?, <<-PATTERN
|
||||
{
|
||||
#{block_pattern('{#ExampleGroups.all #Examples.all}')}
|
||||
#{numblock_pattern('{#ExampleGroups.all #Examples.all}')}
|
||||
#{send_pattern('#Includes.examples')}
|
||||
}
|
||||
PATTERN
|
||||
@ -42,6 +42,8 @@ module RuboCop
|
||||
check_hooks(node.body) if multiline_block?(node.body)
|
||||
end
|
||||
|
||||
alias on_numblock on_block
|
||||
|
||||
private
|
||||
|
||||
def multiline_block?(block)
|
||||
@ -52,13 +54,12 @@ module RuboCop
|
||||
first_example = find_first_example(node)
|
||||
return unless first_example
|
||||
|
||||
node.each_child_node do |child|
|
||||
next if child.sibling_index < first_example.sibling_index
|
||||
next unless hook?(child)
|
||||
first_example.right_siblings.each do |sibling|
|
||||
next unless hook?(sibling)
|
||||
|
||||
msg = format(MSG, hook: child.method_name)
|
||||
add_offense(child, message: msg) do |corrector|
|
||||
autocorrect(corrector, child, first_example)
|
||||
msg = format(MSG, hook: sibling.method_name)
|
||||
add_offense(sibling, message: msg) do |corrector|
|
||||
autocorrect(corrector, sibling, first_example)
|
||||
end
|
||||
end
|
||||
end
|
@ -6,7 +6,6 @@ module RuboCop
|
||||
# Checks for equality assertions with identical expressions on both sides.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# expect(foo.bar).to eq(foo.bar)
|
||||
# expect(foo.bar).to eql(foo.bar)
|
@ -16,6 +16,7 @@ module RuboCop
|
||||
# it 'changes something to a new value' do
|
||||
# expect { do_something }.to change(something).to(new_value)
|
||||
# end
|
||||
#
|
||||
class ImplicitBlockExpectation < Base
|
||||
MSG = 'Avoid implicit block expectations.'
|
||||
RESTRICT_ON_SEND = %i[is_expected should should_not].freeze
|
@ -9,7 +9,6 @@ module RuboCop
|
||||
# and supports the `--auto-gen-config` flag.
|
||||
#
|
||||
# @example `EnforcedStyle: is_expected` (default)
|
||||
#
|
||||
# # bad
|
||||
# it { should be_truthy }
|
||||
#
|
||||
@ -17,7 +16,6 @@ module RuboCop
|
||||
# it { is_expected.to be_truthy }
|
||||
#
|
||||
# @example `EnforcedStyle: should`
|
||||
#
|
||||
# # bad
|
||||
# it { is_expected.to be_truthy }
|
||||
#
|
@ -42,7 +42,7 @@ module RuboCop
|
||||
...)
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example?(node)
|
||||
|
||||
null_double(node) do |var, receiver|
|
@ -24,7 +24,6 @@ module RuboCop
|
||||
# end
|
||||
#
|
||||
# @example with AssignmentOnly configuration
|
||||
#
|
||||
# # rubocop.yml
|
||||
# # RSpec/InstanceVariable:
|
||||
# # AssignmentOnly: false
|
@ -18,6 +18,7 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# it_should_behave_like 'a foo'
|
||||
#
|
||||
class ItBehavesLike < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
@ -15,6 +15,7 @@ module RuboCop
|
||||
# it 'validates users' do
|
||||
# expect([user1, user2, user3]).to all(be_valid)
|
||||
# end
|
||||
#
|
||||
class IteratedExpectation < Base
|
||||
MSG = 'Prefer using the `all` matcher instead ' \
|
||||
'of iterating over an array.'
|
||||
@ -28,6 +29,13 @@ module RuboCop
|
||||
)
|
||||
PATTERN
|
||||
|
||||
# @!method each_numblock?(node)
|
||||
def_node_matcher :each_numblock?, <<-PATTERN
|
||||
(numblock
|
||||
(send ... :each) _ $(...)
|
||||
)
|
||||
PATTERN
|
||||
|
||||
# @!method expectation?(node)
|
||||
def_node_matcher :expectation?, <<-PATTERN
|
||||
(send (send nil? :expect (lvar %)) :to ...)
|
||||
@ -41,6 +49,14 @@ module RuboCop
|
||||
end
|
||||
end
|
||||
|
||||
def on_numblock(node)
|
||||
each_numblock?(node) do |body|
|
||||
if single_expectation?(body, :_1) || only_expectations?(body, :_1)
|
||||
add_offense(node.send_node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def single_expectation?(body, arg)
|
@ -7,29 +7,29 @@ module RuboCop
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# let(:params) { blah }
|
||||
# subject { described_class.new(params) }
|
||||
# let(:params) { blah }
|
||||
# subject { described_class.new(params) }
|
||||
#
|
||||
# before { do_something }
|
||||
# subject { described_class.new(params) }
|
||||
# before { do_something }
|
||||
# subject { described_class.new(params) }
|
||||
#
|
||||
# it { expect_something }
|
||||
# subject { described_class.new(params) }
|
||||
# it { expect_something_else }
|
||||
# it { expect_something }
|
||||
# subject { described_class.new(params) }
|
||||
# it { expect_something_else }
|
||||
#
|
||||
#
|
||||
# # good
|
||||
# subject { described_class.new(params) }
|
||||
# let(:params) { blah }
|
||||
# subject { described_class.new(params) }
|
||||
# let(:params) { blah }
|
||||
#
|
||||
# # good
|
||||
# subject { described_class.new(params) }
|
||||
# before { do_something }
|
||||
# subject { described_class.new(params) }
|
||||
# before { do_something }
|
||||
#
|
||||
# # good
|
||||
# subject { described_class.new(params) }
|
||||
# it { expect_something }
|
||||
# it { expect_something_else }
|
||||
# subject { described_class.new(params) }
|
||||
# it { expect_something }
|
||||
# it { expect_something_else }
|
||||
#
|
||||
class LeadingSubject < Base
|
||||
extend AutoCorrector
|
||||
@ -37,7 +37,7 @@ module RuboCop
|
||||
|
||||
MSG = 'Declare `subject` above any other `%<offending>s` declarations.'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless subject?(node)
|
||||
return unless inside_example_group?(node)
|
||||
|
@ -6,7 +6,7 @@ module RuboCop
|
||||
# Checks for `let` definitions that come after an example.
|
||||
#
|
||||
# @example
|
||||
# # Bad
|
||||
# # bad
|
||||
# let(:foo) { bar }
|
||||
#
|
||||
# it 'checks what foo does' do
|
||||
@ -19,7 +19,7 @@ module RuboCop
|
||||
# expect(some).to be
|
||||
# end
|
||||
#
|
||||
# # Good
|
||||
# # good
|
||||
# let(:foo) { bar }
|
||||
# let(:some) { other }
|
||||
#
|
||||
@ -43,7 +43,7 @@ module RuboCop
|
||||
}
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example_group_with_body?(node)
|
||||
|
||||
check_let_declarations(node.body) if multiline_block?(node.body)
|
||||
@ -59,12 +59,11 @@ module RuboCop
|
||||
first_example = find_first_example(node)
|
||||
return unless first_example
|
||||
|
||||
node.each_child_node do |child|
|
||||
next if child.sibling_index < first_example.sibling_index
|
||||
next unless let?(child)
|
||||
first_example.right_siblings.each do |sibling|
|
||||
next unless let?(sibling)
|
||||
|
||||
add_offense(child) do |corrector|
|
||||
autocorrect(corrector, child, first_example)
|
||||
add_offense(sibling) do |corrector|
|
||||
autocorrect(corrector, sibling, first_example)
|
||||
end
|
||||
end
|
||||
end
|
@ -6,20 +6,20 @@ module RuboCop
|
||||
# Checks unreferenced `let!` calls being used for test setup.
|
||||
#
|
||||
# @example
|
||||
# # Bad
|
||||
# # bad
|
||||
# let!(:my_widget) { create(:widget) }
|
||||
#
|
||||
# it 'counts widgets' do
|
||||
# expect(Widget.count).to eq(1)
|
||||
# end
|
||||
#
|
||||
# # Good
|
||||
# # good
|
||||
# it 'counts widgets' do
|
||||
# create(:widget)
|
||||
# expect(Widget.count).to eq(1)
|
||||
# end
|
||||
#
|
||||
# # Good
|
||||
# # good
|
||||
# before { create(:widget) }
|
||||
#
|
||||
# it 'counts widgets' do
|
||||
@ -49,7 +49,7 @@ module RuboCop
|
||||
# @!method method_called?(node)
|
||||
def_node_search :method_called?, '(send nil? %)'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example_or_shared_group_or_including?(node)
|
||||
|
||||
unused_let_bang(node) do |let|
|
@ -9,7 +9,7 @@ module RuboCop
|
||||
# # bad
|
||||
# allow(foo).to receive_message_chain(:bar, :baz).and_return(42)
|
||||
#
|
||||
# # better
|
||||
# # good
|
||||
# thing = Thing.new(baz: 42)
|
||||
# allow(foo).to receive(:bar).and_return(thing)
|
||||
#
|
@ -19,10 +19,11 @@ module RuboCop
|
||||
#
|
||||
# describe "A feature example" do
|
||||
# end
|
||||
#
|
||||
class MissingExampleGroupArgument < Base
|
||||
MSG = 'The first argument to `%<method>s` should not be empty.'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example_group?(node)
|
||||
return if node.send_node.arguments?
|
||||
|
@ -0,0 +1,99 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Helps parsing css selector.
|
||||
module CssSelector
|
||||
COMMON_OPTIONS = %w[
|
||||
above below left_of right_of near count minimum maximum between text
|
||||
id class style visible obscured exact exact_text normalize_ws match
|
||||
wait filter_set focused
|
||||
].freeze
|
||||
|
||||
module_function
|
||||
|
||||
# @param selector [String]
|
||||
# @return [Boolean]
|
||||
# @example
|
||||
# id?('#some-id') # => true
|
||||
# id?('.some-class') # => false
|
||||
def id?(selector)
|
||||
selector.start_with?('#')
|
||||
end
|
||||
|
||||
# @param selector [String]
|
||||
# @return [Boolean]
|
||||
# @example
|
||||
# attribute?('[attribute]') # => true
|
||||
# attribute?('attribute') # => false
|
||||
def attribute?(selector)
|
||||
selector.start_with?('[')
|
||||
end
|
||||
|
||||
# @param selector [String]
|
||||
# @return [Array<String>]
|
||||
# @example
|
||||
# attributes('a[foo-bar_baz]') # => {"foo-bar_baz=>true}
|
||||
# attributes('button[foo][bar]') # => {"foo"=>true, "bar"=>true}
|
||||
# attributes('table[foo=bar]') # => {"foo"=>"'bar'"}
|
||||
def attributes(selector)
|
||||
selector.scan(/\[(.*?)\]/).flatten.to_h do |attr|
|
||||
key, value = attr.split('=')
|
||||
[key, normalize_value(value)]
|
||||
end
|
||||
end
|
||||
|
||||
# @param selector [String]
|
||||
# @return [Boolean]
|
||||
# @example
|
||||
# common_attributes?('a[focused]') # => true
|
||||
# common_attributes?('button[focused][visible]') # => true
|
||||
# common_attributes?('table[id=some-id]') # => true
|
||||
# common_attributes?('h1[invalid]') # => false
|
||||
def common_attributes?(selector)
|
||||
attributes(selector).keys.difference(COMMON_OPTIONS).none?
|
||||
end
|
||||
|
||||
# @param selector [String]
|
||||
# @return [Array<String>]
|
||||
# @example
|
||||
# pseudo_classes('button:not([disabled])') # => ['not()']
|
||||
# pseudo_classes('a:enabled:not([valid])') # => ['enabled', 'not()']
|
||||
def pseudo_classes(selector)
|
||||
# Attributes must be excluded or else the colon in the `href`s URL
|
||||
# will also be picked up as pseudo classes.
|
||||
# "a:not([href='http://example.com']):enabled" => "a:not():enabled"
|
||||
ignored_attribute = selector.gsub(/\[.*?\]/, '')
|
||||
# "a:not():enabled" => ["not()", "enabled"]
|
||||
ignored_attribute.scan(/:([^:]*)/).flatten
|
||||
end
|
||||
|
||||
# @param selector [String]
|
||||
# @return [Boolean]
|
||||
# @example
|
||||
# multiple_selectors?('a.cls b#id') # => true
|
||||
# multiple_selectors?('a.cls') # => false
|
||||
def multiple_selectors?(selector)
|
||||
selector.match?(/[ >,+]/)
|
||||
end
|
||||
|
||||
# @param value [String]
|
||||
# @return [Boolean, String]
|
||||
# @example
|
||||
# normalize_value('true') # => true
|
||||
# normalize_value('false') # => false
|
||||
# normalize_value(nil) # => false
|
||||
# normalize_value("foo") # => "'foo'"
|
||||
def normalize_value(value)
|
||||
case value
|
||||
when 'true' then true
|
||||
when 'false' then false
|
||||
when nil then true
|
||||
else "'#{value}'"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,23 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Helps to find namespace of the node.
|
||||
module Namespace
|
||||
private
|
||||
|
||||
# @param node [RuboCop::AST::Node]
|
||||
# @return [Array<String>]
|
||||
# @example
|
||||
# namespace(node) # => ['A', 'B', 'C']
|
||||
def namespace(node)
|
||||
node
|
||||
.each_ancestor(:class, :module)
|
||||
.reverse_each
|
||||
.flat_map { |ancestor| ancestor.defined_module_name.split('::') }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -22,6 +22,7 @@ module RuboCop
|
||||
# describe '.do_something_else' do
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class MultipleDescribes < Base
|
||||
include TopLevelGroup
|
||||
|
@ -11,7 +11,6 @@ module RuboCop
|
||||
# and works with `--auto-gen-config`.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# describe UserCreator do
|
||||
# it 'builds a user' do
|
||||
@ -32,7 +31,6 @@ module RuboCop
|
||||
# end
|
||||
#
|
||||
# @example `aggregate_failures: true` (default)
|
||||
#
|
||||
# # good - the cop ignores when RSpec aggregates failures
|
||||
# describe UserCreator do
|
||||
# it 'builds a user', :aggregate_failures do
|
||||
@ -42,7 +40,6 @@ module RuboCop
|
||||
# end
|
||||
#
|
||||
# @example `aggregate_failures: false`
|
||||
#
|
||||
# # Detected as an offense
|
||||
# describe UserCreator do
|
||||
# it 'builds a user', aggregate_failures: false do
|
||||
@ -52,7 +49,6 @@ module RuboCop
|
||||
# end
|
||||
#
|
||||
# @example configuration
|
||||
#
|
||||
# # .rubocop.yml
|
||||
# # RSpec/MultipleExpectations:
|
||||
# # Max: 2
|
||||
@ -88,7 +84,7 @@ module RuboCop
|
||||
(block (send nil? :aggregate_failures ...) ...)
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example?(node)
|
||||
|
||||
return if example_with_aggregate_failures?(node)
|
@ -56,7 +56,6 @@ module RuboCop
|
||||
# end
|
||||
#
|
||||
# @example when disabling AllowSubject configuration
|
||||
#
|
||||
# # rubocop.yml
|
||||
# # RSpec/MultipleMemoizedHelpers:
|
||||
# # AllowSubject: false
|
||||
@ -72,7 +71,6 @@ module RuboCop
|
||||
# end
|
||||
#
|
||||
# @example with Max configuration
|
||||
#
|
||||
# # rubocop.yml
|
||||
# # RSpec/MultipleMemoizedHelpers:
|
||||
# # Max: 1
|
||||
@ -89,7 +87,7 @@ module RuboCop
|
||||
|
||||
MSG = 'Example group has too many memoized helpers [%<count>d/%<max>d]'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless spec_group?(node)
|
||||
|
||||
count = all_helpers(node).uniq.count
|
@ -6,7 +6,6 @@ module RuboCop
|
||||
# Checks if an example group defines `subject` multiple times.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# describe Foo do
|
||||
# subject(:user) { User.new }
|
||||
@ -19,6 +18,21 @@ module RuboCop
|
||||
# subject(:post) { Post.new }
|
||||
# end
|
||||
#
|
||||
# # bad (does not support autocorrection)
|
||||
# describe Foo do
|
||||
# subject!(:user) { User.new }
|
||||
# subject!(:post) { Post.new }
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# describe Foo do
|
||||
# before do
|
||||
# User.new
|
||||
# Post.new
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# This cop does not support autocorrection in some cases.
|
||||
# The autocorrect behavior for this cop depends on the type of
|
||||
# duplication:
|
||||
#
|
||||
@ -33,13 +47,14 @@ module RuboCop
|
||||
# - If subjects are defined with `subject!` then we don't autocorrect.
|
||||
# This is enough of an edge case that people can just move this to
|
||||
# a `before` hook on their own
|
||||
#
|
||||
class MultipleSubjects < Base
|
||||
extend AutoCorrector
|
||||
include RangeHelp
|
||||
|
||||
MSG = 'Do not set more than one subject per example group'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example_group?(node)
|
||||
|
||||
subjects = RuboCop::RSpec::ExampleGroup.new(node).subjects
|
@ -41,6 +41,7 @@ module RuboCop
|
||||
#
|
||||
# it { is_expected.to be_valid }
|
||||
# end
|
||||
#
|
||||
class NamedSubject < Base
|
||||
MSG = 'Name your test subject if you need to reference it explicitly.'
|
||||
|
||||
@ -55,7 +56,7 @@ module RuboCop
|
||||
# @!method subject_usage(node)
|
||||
def_node_search :subject_usage, '$(send nil? :subject)'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
if !example_or_hook_block?(node) || ignored_shared_example?(node)
|
||||
return
|
||||
end
|
@ -36,7 +36,7 @@ module RuboCop
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # better
|
||||
# # good
|
||||
# context 'using some feature as an admin' do
|
||||
# let(:some) { :various }
|
||||
# let(:feature) { :setup }
|
||||
@ -53,34 +53,40 @@ module RuboCop
|
||||
# it 'yada yada'
|
||||
# end
|
||||
#
|
||||
# @example configuration
|
||||
#
|
||||
# # .rubocop.yml
|
||||
# # RSpec/NestedGroups:
|
||||
# # Max: 2
|
||||
#
|
||||
# context 'when using some feature' do
|
||||
# let(:some) { :various }
|
||||
# let(:feature) { :setup }
|
||||
#
|
||||
# context 'when user is signed in' do
|
||||
# let(:user) do
|
||||
# UserCreate.call(user_attributes)
|
||||
# @example `Max: 3` (default)
|
||||
# # bad
|
||||
# describe Foo do
|
||||
# context 'foo' do
|
||||
# context 'bar' do
|
||||
# context 'baz' do # flagged by rubocop
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# let(:user_attributes) do
|
||||
# {
|
||||
# name: 'John',
|
||||
# age: 22,
|
||||
# role: role
|
||||
# }
|
||||
# @example `Max: 2`
|
||||
# # bad
|
||||
# describe Foo do
|
||||
# context 'foo' do
|
||||
# context 'bar' do # flagged by rubocop
|
||||
# context 'baz' do # flagged by rubocop
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# context 'when user is an admin' do # flagged by rubocop
|
||||
# let(:role) { 'admin' }
|
||||
# @example `AllowedGroups: [] (default)`
|
||||
# describe Foo do # <-- nested groups 1
|
||||
# context 'foo' do # <-- nested groups 2
|
||||
# context 'bar' do # <-- nested groups 3
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# it 'blah blah'
|
||||
# it 'yada yada'
|
||||
# @example `AllowedGroups: [path]`
|
||||
# describe Foo do # <-- nested groups 1
|
||||
# path '/foo' do # <-- nested groups 1 (not counted)
|
||||
# context 'bar' do # <-- nested groups 2
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
@ -113,13 +119,23 @@ module RuboCop
|
||||
example_group = example_group?(node)
|
||||
yield node, nesting if example_group && nesting > max_nesting
|
||||
|
||||
next_nesting = example_group ? nesting + 1 : nesting
|
||||
next_nesting = if count_up_nesting?(node, example_group)
|
||||
nesting + 1
|
||||
else
|
||||
nesting
|
||||
end
|
||||
|
||||
node.each_child_node(:block, :begin) do |child|
|
||||
find_nested_example_groups(child, nesting: next_nesting, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def count_up_nesting?(node, example_group)
|
||||
example_group &&
|
||||
(node.block_type? &&
|
||||
!allowed_groups.include?(node.method_name))
|
||||
end
|
||||
|
||||
def message(nesting)
|
||||
format(MSG, total: nesting, max: max_nesting)
|
||||
end
|
||||
@ -136,6 +152,10 @@ module RuboCop
|
||||
cop_config.fetch('Max', 3)
|
||||
end
|
||||
end
|
||||
|
||||
def allowed_groups
|
||||
@allowed_groups ||= cop_config.fetch('AllowedGroups', [])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,64 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Checks if an example contains any expectation.
|
||||
#
|
||||
# All RSpec's example and expectation methods are covered by default.
|
||||
# If you are using your own custom methods,
|
||||
# add the following configuration:
|
||||
#
|
||||
# RSpec:
|
||||
# Language:
|
||||
# Examples:
|
||||
# Regular:
|
||||
# - custom_it
|
||||
# Expectations:
|
||||
# - custom_expect
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# it do
|
||||
# a?
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# it do
|
||||
# expect(a?).to be(true)
|
||||
# end
|
||||
#
|
||||
class NoExpectationExample < Base
|
||||
MSG = 'No expectation found in this example.'
|
||||
|
||||
# @!method regular_or_focused_example?(node)
|
||||
# @param [RuboCop::AST::Node] node
|
||||
# @return [Boolean]
|
||||
def_node_matcher :regular_or_focused_example?, <<~PATTERN
|
||||
{
|
||||
#{block_pattern('{#Examples.regular | #Examples.focused}')}
|
||||
#{numblock_pattern('{#Examples.regular | #Examples.focused}')}
|
||||
}
|
||||
PATTERN
|
||||
|
||||
# @!method including_any_expectation?(node)
|
||||
# @param [RuboCop::AST::Node] node
|
||||
# @return [Boolean]
|
||||
def_node_search(
|
||||
:including_any_expectation?,
|
||||
send_pattern('#Expectations.all')
|
||||
)
|
||||
|
||||
# @param [RuboCop::AST::BlockNode] node
|
||||
def on_block(node)
|
||||
return unless regular_or_focused_example?(node)
|
||||
return if including_any_expectation?(node)
|
||||
|
||||
add_offense(node)
|
||||
end
|
||||
|
||||
alias on_numblock on_block
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -6,7 +6,6 @@ module RuboCop
|
||||
# Checks for consistent method usage for negating expectations.
|
||||
#
|
||||
# @example `EnforcedStyle: not_to` (default)
|
||||
#
|
||||
# # bad
|
||||
# it '...' do
|
||||
# expect(false).to_not be_true
|
||||
@ -18,7 +17,6 @@ module RuboCop
|
||||
# end
|
||||
#
|
||||
# @example `EnforcedStyle: to_not`
|
||||
#
|
||||
# # bad
|
||||
# it '...' do
|
||||
# expect(false).not_to be_true
|
||||
@ -28,6 +26,7 @@ module RuboCop
|
||||
# it '...' do
|
||||
# expect(false).to_not be_true
|
||||
# end
|
||||
#
|
||||
class NotToNot < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
@ -21,6 +21,7 @@ module RuboCop
|
||||
# let(:foo) { bar }
|
||||
# let(:baz) { baz }
|
||||
# let!(:other) { other }
|
||||
#
|
||||
class OverwritingSetup < Base
|
||||
MSG = '`%<name>s` is already defined.'
|
||||
|
||||
@ -30,7 +31,7 @@ module RuboCop
|
||||
# @!method first_argument_name(node)
|
||||
def_node_matcher :first_argument_name, '(send _ _ ({str sym} $_))'
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example_group_with_body?(node)
|
||||
|
||||
find_duplicates(node.body) do |duplicate, name|
|
@ -31,6 +31,7 @@ module RuboCop
|
||||
# # good
|
||||
# describe MyClass do
|
||||
# end
|
||||
#
|
||||
class Pending < Base
|
||||
MSG = 'Pending spec found.'
|
||||
|
@ -276,6 +276,7 @@ module RuboCop
|
||||
#
|
||||
# # good - the above code is rewritten to it by this cop
|
||||
# expect(foo.something?).to be_truthy
|
||||
#
|
||||
class PredicateMatcher < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
@ -291,7 +292,7 @@ module RuboCop
|
||||
end
|
||||
end
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
check_explicit(node) if style == :explicit
|
||||
end
|
||||
|
@ -7,7 +7,6 @@ module RuboCop
|
||||
# Checks that tests use RSpec `before` hook over Rails `setup` method.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# setup do
|
||||
# allow(foo).to receive(:bar)
|
||||
@ -30,7 +29,7 @@ module RuboCop
|
||||
(args) _)
|
||||
PATTERN
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
setup_call(node) do |setup|
|
||||
add_offense(node) do |corrector|
|
||||
corrector.replace setup, 'before'
|
@ -6,22 +6,21 @@ module RuboCop
|
||||
# Check for `once` and `twice` receive counts matchers usage.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# expect(foo).to receive(:bar).exactly(1).times
|
||||
# expect(foo).to receive(:bar).exactly(2).times
|
||||
# expect(foo).to receive(:bar).at_least(1).times
|
||||
# expect(foo).to receive(:bar).at_least(2).times
|
||||
# expect(foo).to receive(:bar).at_most(1).times
|
||||
# expect(foo).to receive(:bar).at_most(2).times
|
||||
#
|
||||
# # bad
|
||||
# expect(foo).to receive(:bar).exactly(1).times
|
||||
# expect(foo).to receive(:bar).exactly(2).times
|
||||
# expect(foo).to receive(:bar).at_least(1).times
|
||||
# expect(foo).to receive(:bar).at_least(2).times
|
||||
# expect(foo).to receive(:bar).at_most(1).times
|
||||
# expect(foo).to receive(:bar).at_most(2).times
|
||||
#
|
||||
# # good
|
||||
# expect(foo).to receive(:bar).once
|
||||
# expect(foo).to receive(:bar).twice
|
||||
# expect(foo).to receive(:bar).at_least(:once)
|
||||
# expect(foo).to receive(:bar).at_least(:twice)
|
||||
# expect(foo).to receive(:bar).at_most(:once)
|
||||
# expect(foo).to receive(:bar).at_most(:twice).times
|
||||
# # good
|
||||
# expect(foo).to receive(:bar).once
|
||||
# expect(foo).to receive(:bar).twice
|
||||
# expect(foo).to receive(:bar).at_least(:once)
|
||||
# expect(foo).to receive(:bar).at_least(:twice)
|
||||
# expect(foo).to receive(:bar).at_most(:once)
|
||||
# expect(foo).to receive(:bar).at_most(:twice).times
|
||||
#
|
||||
class ReceiveCounts < Base
|
||||
extend AutoCorrector
|
@ -6,12 +6,11 @@ module RuboCop
|
||||
# Prefer `not_to receive(...)` over `receive(...).never`.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# expect(foo).to receive(:bar).never
|
||||
#
|
||||
# # bad
|
||||
# expect(foo).to receive(:bar).never
|
||||
#
|
||||
# # good
|
||||
# expect(foo).not_to receive(:bar)
|
||||
# # good
|
||||
# expect(foo).not_to receive(:bar)
|
||||
#
|
||||
class ReceiveNever < Base
|
||||
extend AutoCorrector
|
@ -6,44 +6,43 @@ module RuboCop
|
||||
# Check for repeated description strings in example groups.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# RSpec.describe User do
|
||||
# it 'is valid' do
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
# it 'is valid' do
|
||||
# # ...
|
||||
# end
|
||||
# # bad
|
||||
# RSpec.describe User do
|
||||
# it 'is valid' do
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# RSpec.describe User do
|
||||
# it 'is valid when first and last name are present' do
|
||||
# # ...
|
||||
# end
|
||||
# it 'is valid' do
|
||||
# # ...
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# it 'is valid when last name only is present' do
|
||||
# # ...
|
||||
# end
|
||||
# # good
|
||||
# RSpec.describe User do
|
||||
# it 'is valid when first and last name are present' do
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# RSpec.describe User do
|
||||
# it 'is valid' do
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
# it 'is valid', :flag do
|
||||
# # ...
|
||||
# end
|
||||
# it 'is valid when last name only is present' do
|
||||
# # ...
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# RSpec.describe User do
|
||||
# it 'is valid' do
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
# it 'is valid', :flag do
|
||||
# # ...
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class RepeatedDescription < Base
|
||||
MSG = "Don't repeat descriptions within an example group."
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example_group?(node)
|
||||
|
||||
repeated_descriptions(node).each do |repeated_description|
|
@ -18,7 +18,7 @@ module RuboCop
|
||||
class RepeatedExample < Base
|
||||
MSG = "Don't repeat examples within an example group."
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example_group?(node)
|
||||
|
||||
repeated_examples(node).each do |repeated_example|
|
@ -6,42 +6,41 @@ module RuboCop
|
||||
# Check for repeated describe and context block body.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# describe 'cool feature x' do
|
||||
# it { cool_predicate }
|
||||
# end
|
||||
#
|
||||
# # bad
|
||||
# describe 'cool feature x' do
|
||||
# it { cool_predicate }
|
||||
# end
|
||||
# describe 'cool feature y' do
|
||||
# it { cool_predicate }
|
||||
# end
|
||||
#
|
||||
# describe 'cool feature y' do
|
||||
# it { cool_predicate }
|
||||
# end
|
||||
# # good
|
||||
# describe 'cool feature' do
|
||||
# it { cool_predicate }
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# describe 'cool feature' do
|
||||
# it { cool_predicate }
|
||||
# end
|
||||
# describe 'another cool feature' do
|
||||
# it { another_predicate }
|
||||
# end
|
||||
#
|
||||
# describe 'another cool feature' do
|
||||
# it { another_predicate }
|
||||
# end
|
||||
# # good
|
||||
# context 'when case x', :tag do
|
||||
# it { cool_predicate }
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# context 'when case x', :tag do
|
||||
# it { cool_predicate }
|
||||
# end
|
||||
# context 'when case y' do
|
||||
# it { cool_predicate }
|
||||
# end
|
||||
#
|
||||
# context 'when case y' do
|
||||
# it { cool_predicate }
|
||||
# end
|
||||
# # good
|
||||
# context Array do
|
||||
# it { is_expected.to respond_to :each }
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# context Array do
|
||||
# it { is_expected.to respond_to :each }
|
||||
# end
|
||||
#
|
||||
# context Hash do
|
||||
# it { is_expected.to respond_to :each }
|
||||
# end
|
||||
# context Hash do
|
||||
# it { is_expected.to respond_to :each }
|
||||
# end
|
||||
#
|
||||
class RepeatedExampleGroupBody < Base
|
||||
MSG = 'Repeated %<group>s block body on line(s) %<loc>s'
|
@ -6,42 +6,41 @@ module RuboCop
|
||||
# Check for repeated example group descriptions.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# describe 'cool feature' do
|
||||
# # example group
|
||||
# end
|
||||
#
|
||||
# # bad
|
||||
# describe 'cool feature' do
|
||||
# # example group
|
||||
# end
|
||||
# describe 'cool feature' do
|
||||
# # example group
|
||||
# end
|
||||
#
|
||||
# describe 'cool feature' do
|
||||
# # example group
|
||||
# end
|
||||
# # bad
|
||||
# context 'when case x' do
|
||||
# # example group
|
||||
# end
|
||||
#
|
||||
# # bad
|
||||
# context 'when case x' do
|
||||
# # example group
|
||||
# end
|
||||
# describe 'when case x' do
|
||||
# # example group
|
||||
# end
|
||||
#
|
||||
# describe 'when case x' do
|
||||
# # example group
|
||||
# end
|
||||
# # good
|
||||
# describe 'cool feature' do
|
||||
# # example group
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# describe 'cool feature' do
|
||||
# # example group
|
||||
# end
|
||||
# describe 'another cool feature' do
|
||||
# # example group
|
||||
# end
|
||||
#
|
||||
# describe 'another cool feature' do
|
||||
# # example group
|
||||
# end
|
||||
# # good
|
||||
# context 'when case x' do
|
||||
# # example group
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# context 'when case x' do
|
||||
# # example group
|
||||
# end
|
||||
#
|
||||
# context 'when another case' do
|
||||
# # example group
|
||||
# end
|
||||
# context 'when another case' do
|
||||
# # example group
|
||||
# end
|
||||
#
|
||||
class RepeatedExampleGroupDescription < Base
|
||||
MSG = 'Repeated %<group>s block description on line(s) %<loc>s'
|
@ -6,45 +6,44 @@ module RuboCop
|
||||
# Check for repeated include of shared examples.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# describe 'foo' do
|
||||
# include_examples 'cool stuff'
|
||||
# include_examples 'cool stuff'
|
||||
# end
|
||||
#
|
||||
# # bad
|
||||
# describe 'foo' do
|
||||
# include_examples 'cool stuff'
|
||||
# include_examples 'cool stuff'
|
||||
# end
|
||||
# # bad
|
||||
# describe 'foo' do
|
||||
# it_behaves_like 'a cool', 'thing'
|
||||
# it_behaves_like 'a cool', 'thing'
|
||||
# end
|
||||
#
|
||||
# # bad
|
||||
# describe 'foo' do
|
||||
# it_behaves_like 'a cool', 'thing'
|
||||
# it_behaves_like 'a cool', 'thing'
|
||||
# end
|
||||
# # bad
|
||||
# context 'foo' do
|
||||
# it_should_behave_like 'a duck'
|
||||
# it_should_behave_like 'a duck'
|
||||
# end
|
||||
#
|
||||
# # bad
|
||||
# context 'foo' do
|
||||
# it_should_behave_like 'a duck'
|
||||
# it_should_behave_like 'a duck'
|
||||
# end
|
||||
# # good
|
||||
# describe 'foo' do
|
||||
# include_examples 'cool stuff'
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# describe 'foo' do
|
||||
# include_examples 'cool stuff'
|
||||
# end
|
||||
# describe 'bar' do
|
||||
# include_examples 'cool stuff'
|
||||
# end
|
||||
#
|
||||
# describe 'bar' do
|
||||
# include_examples 'cool stuff'
|
||||
# end
|
||||
# # good
|
||||
# describe 'foo' do
|
||||
# it_behaves_like 'a cool', 'thing'
|
||||
# it_behaves_like 'a cool', 'person'
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# describe 'foo' do
|
||||
# it_behaves_like 'a cool', 'thing'
|
||||
# it_behaves_like 'a cool', 'person'
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# context 'foo' do
|
||||
# it_should_behave_like 'a duck'
|
||||
# it_should_behave_like 'a goose'
|
||||
# end
|
||||
# # good
|
||||
# context 'foo' do
|
||||
# it_should_behave_like 'a duck'
|
||||
# it_should_behave_like 'a goose'
|
||||
# end
|
||||
#
|
||||
class RepeatedIncludeExample < Base
|
||||
MSG = 'Repeated include of shared_examples %<name>s ' \
|
@ -59,7 +59,7 @@ module RuboCop
|
||||
check_and_return_call(node)
|
||||
end
|
||||
|
||||
def on_block(node)
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless style == :and_return
|
||||
return unless stub_with_block?(node)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user