Merge pull request #14101 from Homebrew/dependabot/bundler/Library/Homebrew/rubocop-rspec-2.15.0
build(deps): bump rubocop-rspec from 2.13.2 to 2.15.0 in /Library/Homebrew
This commit is contained in:
commit
57df913974
@ -151,7 +151,7 @@ GEM
|
||||
activesupport (>= 4.2.0)
|
||||
rack (>= 1.1)
|
||||
rubocop (>= 1.33.0, < 2.0)
|
||||
rubocop-rspec (2.13.2)
|
||||
rubocop-rspec (2.15.0)
|
||||
rubocop (~> 1.33)
|
||||
rubocop-sorbet (0.6.11)
|
||||
rubocop (>= 0.90.0)
|
||||
|
||||
@ -172,6 +172,47 @@ end
|
||||
RuboCop::Cop::RSpec::Capybara::FeatureMethods::MAP = T.let(T.unsafe(nil), Hash)
|
||||
RuboCop::Cop::RSpec::Capybara::FeatureMethods::MSG = T.let(T.unsafe(nil), String)
|
||||
|
||||
class RuboCop::Cop::RSpec::Capybara::NegationMatcher < ::RuboCop::Cop::RSpec::Base
|
||||
include ::RuboCop::Cop::ConfigurableEnforcedStyle
|
||||
extend ::RuboCop::Cop::AutoCorrector
|
||||
|
||||
def have_no?(param0 = T.unsafe(nil)); end
|
||||
def not_to?(param0 = T.unsafe(nil)); end
|
||||
def on_send(node); end
|
||||
|
||||
private
|
||||
|
||||
def message(matcher); end
|
||||
def offense?(node); end
|
||||
def offense_range(node); end
|
||||
def replaced_matcher(matcher); end
|
||||
def replaced_runner; end
|
||||
end
|
||||
|
||||
RuboCop::Cop::RSpec::Capybara::NegationMatcher::CAPYBARA_MATCHERS = T.let(T.unsafe(nil), Array)
|
||||
RuboCop::Cop::RSpec::Capybara::NegationMatcher::MSG = T.let(T.unsafe(nil), String)
|
||||
RuboCop::Cop::RSpec::Capybara::NegationMatcher::NEGATIVE_MATCHERS = T.let(T.unsafe(nil), Set)
|
||||
RuboCop::Cop::RSpec::Capybara::NegationMatcher::POSITIVE_MATCHERS = T.let(T.unsafe(nil), Set)
|
||||
RuboCop::Cop::RSpec::Capybara::NegationMatcher::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Set)
|
||||
|
||||
class RuboCop::Cop::RSpec::Capybara::SpecificActions < ::RuboCop::Cop::RSpec::Base
|
||||
def click_on_selector(param0 = T.unsafe(nil)); end
|
||||
def on_send(node); end
|
||||
|
||||
private
|
||||
|
||||
def good_action(action); end
|
||||
def last_selector(arg); end
|
||||
def message(action, selector); end
|
||||
def offense_range(node, receiver); end
|
||||
def specific_action(selector); end
|
||||
def supported_selector?(selector); end
|
||||
end
|
||||
|
||||
RuboCop::Cop::RSpec::Capybara::SpecificActions::MSG = T.let(T.unsafe(nil), String)
|
||||
RuboCop::Cop::RSpec::Capybara::SpecificActions::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array)
|
||||
RuboCop::Cop::RSpec::Capybara::SpecificActions::SPECIFIC_ACTION = T.let(T.unsafe(nil), Hash)
|
||||
|
||||
class RuboCop::Cop::RSpec::Capybara::SpecificFinders < ::RuboCop::Cop::RSpec::Base
|
||||
include ::RuboCop::Cop::RangeHelp
|
||||
extend ::RuboCop::Cop::AutoCorrector
|
||||
@ -195,28 +236,21 @@ RuboCop::Cop::RSpec::Capybara::SpecificFinders::MSG = T.let(T.unsafe(nil), Strin
|
||||
RuboCop::Cop::RSpec::Capybara::SpecificFinders::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array)
|
||||
|
||||
class RuboCop::Cop::RSpec::Capybara::SpecificMatcher < ::RuboCop::Cop::RSpec::Base
|
||||
include ::RuboCop::Cop::RSpec::CapybaraHelp
|
||||
|
||||
def first_argument(param0 = T.unsafe(nil)); end
|
||||
def on_send(node); end
|
||||
def option?(param0, param1); end
|
||||
|
||||
private
|
||||
|
||||
def good_matcher(node, matcher); end
|
||||
def message(node, matcher); end
|
||||
def replaceable_matcher?(node, matcher, attrs); end
|
||||
def replaceable_pseudo_class?(pseudo_class, arg); end
|
||||
def replaceable_pseudo_class_not?(arg); end
|
||||
def replaceable_to_have_link?(node, attrs); end
|
||||
def specific_matcher(arg); end
|
||||
def specific_matcher_option?(node, arg, matcher); end
|
||||
def specific_matcher_pseudo_classes?(arg); end
|
||||
end
|
||||
|
||||
RuboCop::Cop::RSpec::Capybara::SpecificMatcher::MSG = T.let(T.unsafe(nil), String)
|
||||
RuboCop::Cop::RSpec::Capybara::SpecificMatcher::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array)
|
||||
RuboCop::Cop::RSpec::Capybara::SpecificMatcher::SPECIFIC_MATCHER = T.let(T.unsafe(nil), Hash)
|
||||
RuboCop::Cop::RSpec::Capybara::SpecificMatcher::SPECIFIC_MATCHER_OPTIONS = T.let(T.unsafe(nil), Hash)
|
||||
RuboCop::Cop::RSpec::Capybara::SpecificMatcher::SPECIFIC_MATCHER_PSEUDO_CLASSES = T.let(T.unsafe(nil), Array)
|
||||
|
||||
class RuboCop::Cop::RSpec::Capybara::VisibilityMatcher < ::RuboCop::Cop::RSpec::Base
|
||||
def on_send(node); end
|
||||
@ -233,6 +267,28 @@ RuboCop::Cop::RSpec::Capybara::VisibilityMatcher::MSG_FALSE = T.let(T.unsafe(nil
|
||||
RuboCop::Cop::RSpec::Capybara::VisibilityMatcher::MSG_TRUE = T.let(T.unsafe(nil), String)
|
||||
RuboCop::Cop::RSpec::Capybara::VisibilityMatcher::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array)
|
||||
|
||||
module RuboCop::Cop::RSpec::CapybaraHelp
|
||||
private
|
||||
|
||||
def include_option?(node, option); end
|
||||
def replaceable_element?(node, element, attrs); end
|
||||
def replaceable_pseudo_class?(pseudo_class, locator); end
|
||||
def replaceable_pseudo_class_not?(locator); end
|
||||
def replaceable_to_link?(node, attrs); end
|
||||
def specific_option?(node, locator, element); end
|
||||
def specific_pseudo_classes?(locator); end
|
||||
|
||||
class << self
|
||||
def include_option?(node, option); end
|
||||
def replaceable_element?(node, element, attrs); end
|
||||
def replaceable_pseudo_class?(pseudo_class, locator); end
|
||||
def replaceable_pseudo_class_not?(locator); end
|
||||
def replaceable_to_link?(node, attrs); end
|
||||
def specific_option?(node, locator, element); end
|
||||
def specific_pseudo_classes?(locator); end
|
||||
end
|
||||
end
|
||||
|
||||
class RuboCop::Cop::RSpec::ChangeByZero < ::RuboCop::Cop::RSpec::Base
|
||||
extend ::RuboCop::Cop::AutoCorrector
|
||||
|
||||
@ -328,6 +384,8 @@ module RuboCop::Cop::RSpec::CssSelector
|
||||
def multiple_selectors?(selector); end
|
||||
def normalize_value(value); end
|
||||
def pseudo_classes(selector); end
|
||||
def specific_options?(element, attribute); end
|
||||
def specific_pesudo_classes?(pseudo_class); end
|
||||
|
||||
class << self
|
||||
def attribute?(selector); end
|
||||
@ -337,10 +395,14 @@ module RuboCop::Cop::RSpec::CssSelector
|
||||
def multiple_selectors?(selector); end
|
||||
def normalize_value(value); end
|
||||
def pseudo_classes(selector); end
|
||||
def specific_options?(element, attribute); end
|
||||
def specific_pesudo_classes?(pseudo_class); end
|
||||
end
|
||||
end
|
||||
|
||||
RuboCop::Cop::RSpec::CssSelector::COMMON_OPTIONS = T.let(T.unsafe(nil), Array)
|
||||
RuboCop::Cop::RSpec::CssSelector::SPECIFIC_OPTIONS = T.let(T.unsafe(nil), Hash)
|
||||
RuboCop::Cop::RSpec::CssSelector::SPECIFIC_PSEUDO_CLASSES = T.let(T.unsafe(nil), Array)
|
||||
|
||||
class RuboCop::Cop::RSpec::DescribeClass < ::RuboCop::Cop::RSpec::Base
|
||||
include ::RuboCop::Cop::RSpec::TopLevelGroup
|
||||
@ -568,11 +630,15 @@ class RuboCop::Cop::RSpec::ExampleWording < ::RuboCop::Cop::RSpec::Base
|
||||
def custom_transform; end
|
||||
def docstring(node); end
|
||||
def ignored_words; end
|
||||
def insufficient_docstring?(description_node); end
|
||||
def insufficient_examples; end
|
||||
def preprocess(message); end
|
||||
def replacement_text(node); end
|
||||
def text(node); end
|
||||
end
|
||||
|
||||
RuboCop::Cop::RSpec::ExampleWording::IT_PREFIX = T.let(T.unsafe(nil), Regexp)
|
||||
RuboCop::Cop::RSpec::ExampleWording::MSG_INSUFFICIENT_DESCRIPTION = T.let(T.unsafe(nil), String)
|
||||
RuboCop::Cop::RSpec::ExampleWording::MSG_IT = T.let(T.unsafe(nil), String)
|
||||
RuboCop::Cop::RSpec::ExampleWording::MSG_SHOULD = T.let(T.unsafe(nil), String)
|
||||
RuboCop::Cop::RSpec::ExampleWording::SHOULD_PREFIX = T.let(T.unsafe(nil), Regexp)
|
||||
@ -696,6 +762,31 @@ end
|
||||
|
||||
RuboCop::Cop::RSpec::FactoryBot::AttributeDefinedStatically::MSG = T.let(T.unsafe(nil), String)
|
||||
|
||||
class RuboCop::Cop::RSpec::FactoryBot::ConsistentParenthesesStyle < ::RuboCop::Cop::RSpec::Base
|
||||
include ::RuboCop::Cop::ConfigurableEnforcedStyle
|
||||
include ::RuboCop::RSpec::FactoryBot::Language
|
||||
extend ::RuboCop::Cop::AutoCorrector
|
||||
|
||||
def ambiguous_without_parentheses?(node); end
|
||||
def factory_call(param0 = T.unsafe(nil)); end
|
||||
def on_send(node); end
|
||||
def process_with_parentheses(node); end
|
||||
def process_without_parentheses(node); end
|
||||
|
||||
private
|
||||
|
||||
def remove_parentheses(corrector, node); end
|
||||
|
||||
class << self
|
||||
def autocorrect_incompatible_with; end
|
||||
end
|
||||
end
|
||||
|
||||
RuboCop::Cop::RSpec::FactoryBot::ConsistentParenthesesStyle::FACTORY_CALLS = T.let(T.unsafe(nil), Set)
|
||||
RuboCop::Cop::RSpec::FactoryBot::ConsistentParenthesesStyle::MSG_OMIT_PARENS = T.let(T.unsafe(nil), String)
|
||||
RuboCop::Cop::RSpec::FactoryBot::ConsistentParenthesesStyle::MSG_REQUIRE_PARENS = T.let(T.unsafe(nil), String)
|
||||
RuboCop::Cop::RSpec::FactoryBot::ConsistentParenthesesStyle::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Set)
|
||||
|
||||
class RuboCop::Cop::RSpec::FactoryBot::CreateList < ::RuboCop::Cop::RSpec::Base
|
||||
include ::RuboCop::Cop::ConfigurableEnforcedStyle
|
||||
include ::RuboCop::RSpec::FactoryBot::Language
|
||||
@ -803,14 +894,16 @@ class RuboCop::Cop::RSpec::FilePath < ::RuboCop::Cop::RSpec::Base
|
||||
def camel_to_snake_case(string); end
|
||||
def custom_transform; end
|
||||
def ensure_correct_file_path(send_node, example_group, arguments); end
|
||||
def expanded_file_path; end
|
||||
def expected_path(constant); end
|
||||
def filename_ends_with?(pattern); end
|
||||
def ignore_methods?; end
|
||||
def name_pattern(method_name); end
|
||||
def pattern_for(example_group, method_name); end
|
||||
def pattern_for(example_group, arguments); end
|
||||
def pattern_for_spec_suffix_only; end
|
||||
def relevant_rubocop_rspec_file?(_file); end
|
||||
def routing_spec?(args); end
|
||||
def routing_spec_path?; end
|
||||
def spec_suffix_only?; end
|
||||
end
|
||||
|
||||
@ -922,17 +1015,26 @@ class RuboCop::Cop::RSpec::ImplicitSubject < ::RuboCop::Cop::RSpec::Base
|
||||
include ::RuboCop::Cop::ConfigurableEnforcedStyle
|
||||
extend ::RuboCop::Cop::AutoCorrector
|
||||
|
||||
def explicit_unnamed_subject?(param0 = T.unsafe(nil)); end
|
||||
def implicit_subject?(param0 = T.unsafe(nil)); end
|
||||
def on_send(node); end
|
||||
|
||||
private
|
||||
|
||||
def allowed_by_style?(example); end
|
||||
def autocorrect(corrector, node); end
|
||||
def valid_usage?(node); end
|
||||
def example_of(node); end
|
||||
def implicit_subject_in_non_its?(node); end
|
||||
def implicit_subject_in_non_its_and_non_single_line?(node); end
|
||||
def implicit_subject_in_non_its_and_non_single_statement?(node); end
|
||||
def invalid?(node); end
|
||||
def its?(node); end
|
||||
def message(_node); end
|
||||
def single_line?(node); end
|
||||
def single_statement?(node); end
|
||||
end
|
||||
|
||||
RuboCop::Cop::RSpec::ImplicitSubject::MSG = T.let(T.unsafe(nil), String)
|
||||
RuboCop::Cop::RSpec::ImplicitSubject::MSG_REQUIRE_EXPLICIT = T.let(T.unsafe(nil), String)
|
||||
RuboCop::Cop::RSpec::ImplicitSubject::MSG_REQUIRE_IMPLICIT = T.let(T.unsafe(nil), String)
|
||||
RuboCop::Cop::RSpec::ImplicitSubject::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array)
|
||||
|
||||
module RuboCop::Cop::RSpec::InflectedHelper
|
||||
@ -1061,12 +1163,14 @@ class RuboCop::Cop::RSpec::LetBeforeExamples < ::RuboCop::Cop::RSpec::Base
|
||||
extend ::RuboCop::Cop::AutoCorrector
|
||||
|
||||
def example_or_group?(param0 = T.unsafe(nil)); end
|
||||
def include_examples?(param0 = T.unsafe(nil)); end
|
||||
def on_block(node); end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node, first_example); end
|
||||
def check_let_declarations(node); end
|
||||
def example_group_with_include_examples?(body); end
|
||||
def find_first_example(node); end
|
||||
def multiline_block?(block); end
|
||||
end
|
||||
@ -1199,11 +1303,23 @@ end
|
||||
RuboCop::Cop::RSpec::MultipleSubjects::MSG = T.let(T.unsafe(nil), String)
|
||||
|
||||
class RuboCop::Cop::RSpec::NamedSubject < ::RuboCop::Cop::RSpec::Base
|
||||
include ::RuboCop::Cop::ConfigurableEnforcedStyle
|
||||
|
||||
def example_or_hook_block?(param0 = T.unsafe(nil)); end
|
||||
def ignored_shared_example?(node); end
|
||||
def on_block(node); end
|
||||
def shared_example?(param0 = T.unsafe(nil)); end
|
||||
def subject_usage(param0); end
|
||||
|
||||
private
|
||||
|
||||
def allow_explicit_subject?(node); end
|
||||
def always?; end
|
||||
def check_explicit_subject(node); end
|
||||
def find_subject(block_node); end
|
||||
def ignored_shared_example?(node); end
|
||||
def named_only?(node); end
|
||||
def nearest_subject(node); end
|
||||
def subject_definition_is_named?(node); end
|
||||
end
|
||||
|
||||
RuboCop::Cop::RSpec::NamedSubject::MSG = T.let(T.unsafe(nil), String)
|
||||
@ -1235,8 +1351,11 @@ RuboCop::Cop::RSpec::NestedGroups::DEPRECATION_WARNING = T.let(T.unsafe(nil), St
|
||||
RuboCop::Cop::RSpec::NestedGroups::MSG = T.let(T.unsafe(nil), String)
|
||||
|
||||
class RuboCop::Cop::RSpec::NoExpectationExample < ::RuboCop::Cop::RSpec::Base
|
||||
def including_any_expectation?(param0); end
|
||||
def including_any_skip_example?(param0); end
|
||||
include ::RuboCop::Cop::AllowedPattern
|
||||
include ::RuboCop::Cop::RSpec::SkipOrPending
|
||||
|
||||
def includes_expectation?(param0); end
|
||||
def includes_skip_example?(param0); end
|
||||
def on_block(node); end
|
||||
def on_numblock(node); end
|
||||
def regular_or_focused_example?(param0 = T.unsafe(nil)); end
|
||||
@ -1273,11 +1392,11 @@ end
|
||||
RuboCop::Cop::RSpec::OverwritingSetup::MSG = T.let(T.unsafe(nil), String)
|
||||
|
||||
class RuboCop::Cop::RSpec::Pending < ::RuboCop::Cop::RSpec::Base
|
||||
include ::RuboCop::Cop::RSpec::SkipOrPending
|
||||
|
||||
def on_send(node); end
|
||||
def pending_block?(param0 = T.unsafe(nil)); end
|
||||
def skip_or_pending?(param0 = T.unsafe(nil)); end
|
||||
def skippable?(param0 = T.unsafe(nil)); end
|
||||
def skipped_in_metadata?(param0 = T.unsafe(nil)); end
|
||||
|
||||
private
|
||||
|
||||
@ -1369,6 +1488,26 @@ end
|
||||
|
||||
RuboCop::Cop::RSpec::Rails::HttpStatus::SymbolicStyleChecker::MSG = T.let(T.unsafe(nil), String)
|
||||
|
||||
class RuboCop::Cop::RSpec::Rails::InferredSpecType < ::RuboCop::Cop::RSpec::Base
|
||||
extend ::RuboCop::Cop::AutoCorrector
|
||||
|
||||
def describe_with_type(param0 = T.unsafe(nil)); end
|
||||
def on_block(node); end
|
||||
def on_numblock(node); end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node); end
|
||||
def detect_removable_node(node); end
|
||||
def file_path; end
|
||||
def inferences; end
|
||||
def inferred_type?(node); end
|
||||
def inferred_type_from_file_path; end
|
||||
def remove_range(node); end
|
||||
end
|
||||
|
||||
RuboCop::Cop::RSpec::Rails::InferredSpecType::MSG = T.let(T.unsafe(nil), String)
|
||||
|
||||
class RuboCop::Cop::RSpec::ReceiveCounts < ::RuboCop::Cop::RSpec::Base
|
||||
extend ::RuboCop::Cop::AutoCorrector
|
||||
|
||||
@ -1407,7 +1546,9 @@ class RuboCop::Cop::RSpec::RepeatedDescription < ::RuboCop::Cop::RSpec::Base
|
||||
private
|
||||
|
||||
def example_signature(example); end
|
||||
def its_signature(example); end
|
||||
def repeated_descriptions(node); end
|
||||
def repeated_its(node); end
|
||||
end
|
||||
|
||||
RuboCop::Cop::RSpec::RepeatedDescription::MSG = T.let(T.unsafe(nil), String)
|
||||
@ -1606,6 +1747,35 @@ end
|
||||
RuboCop::Cop::RSpec::SingleArgumentMessageChain::MSG = T.let(T.unsafe(nil), String)
|
||||
RuboCop::Cop::RSpec::SingleArgumentMessageChain::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array)
|
||||
|
||||
module RuboCop::Cop::RSpec::SkipOrPending
|
||||
extend ::RuboCop::AST::NodePattern::Macros
|
||||
|
||||
def skip_or_pending?(param0 = T.unsafe(nil)); end
|
||||
def skipped_in_metadata?(param0 = T.unsafe(nil)); end
|
||||
end
|
||||
|
||||
class RuboCop::Cop::RSpec::SortMetadata < ::RuboCop::Cop::RSpec::Base
|
||||
include ::RuboCop::Cop::RangeHelp
|
||||
extend ::RuboCop::Cop::AutoCorrector
|
||||
|
||||
def metadata_in_block(param0, param1); end
|
||||
def on_block(node); end
|
||||
def on_numblock(node); end
|
||||
def rspec_configure(param0 = T.unsafe(nil)); end
|
||||
def rspec_metadata(param0 = T.unsafe(nil)); end
|
||||
|
||||
private
|
||||
|
||||
def crime_scene(symbols, pairs); end
|
||||
def investigate(symbols, pairs); end
|
||||
def replacement(symbols, pairs); end
|
||||
def sort_pairs(pairs); end
|
||||
def sort_symbols(symbols); end
|
||||
def sorted?(symbols, pairs); end
|
||||
end
|
||||
|
||||
RuboCop::Cop::RSpec::SortMetadata::MSG = T.let(T.unsafe(nil), String)
|
||||
|
||||
class RuboCop::Cop::RSpec::StubbedMock < ::RuboCop::Cop::RSpec::Base
|
||||
def configured_response?(param0 = T.unsafe(nil)); end
|
||||
def expectation(param0 = T.unsafe(nil)); end
|
||||
@ -1889,6 +2059,7 @@ module RuboCop::RSpec::FactoryBot::Language
|
||||
def factory_bot?(param0 = T.unsafe(nil)); end
|
||||
end
|
||||
|
||||
RuboCop::RSpec::FactoryBot::Language::METHODS = T.let(T.unsafe(nil), Set)
|
||||
RuboCop::RSpec::FactoryBot::RESERVED_METHODS = T.let(T.unsafe(nil), Array)
|
||||
RuboCop::RSpec::FactoryBot::UNPROXIED_METHODS = T.let(T.unsafe(nil), Array)
|
||||
|
||||
@ -1979,6 +2150,8 @@ module RuboCop::RSpec::Language::HookScopes
|
||||
end
|
||||
end
|
||||
|
||||
RuboCop::RSpec::Language::HookScopes::ALL = T.let(T.unsafe(nil), Array)
|
||||
|
||||
module RuboCop::RSpec::Language::Hooks
|
||||
class << self
|
||||
def all(element); end
|
||||
@ -2005,6 +2178,8 @@ module RuboCop::RSpec::Language::Runners
|
||||
end
|
||||
end
|
||||
|
||||
RuboCop::RSpec::Language::Runners::ALL = T.let(T.unsafe(nil), Array)
|
||||
|
||||
module RuboCop::RSpec::Language::SharedGroups
|
||||
class << self
|
||||
def all(element); end
|
||||
@ -6,7 +6,7 @@ require "cmd/shared_examples/args_parse"
|
||||
describe "brew bump" do
|
||||
it_behaves_like "parseable arguments"
|
||||
|
||||
describe "formula", :integration_test, :needs_network, :needs_homebrew_curl do
|
||||
describe "formula", :integration_test, :needs_homebrew_curl, :needs_network do
|
||||
it "returns data for single valid specified formula" do
|
||||
install_test_formula "testball"
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
require "utils/repology"
|
||||
|
||||
describe Repology do
|
||||
describe "single_package_query", :needs_network, :needs_homebrew_curl do
|
||||
describe "single_package_query", :needs_homebrew_curl, :needs_network do
|
||||
it "returns nil for non-existent package" do
|
||||
response = described_class.single_package_query("invalidName", repository: "homebrew")
|
||||
|
||||
@ -19,7 +19,7 @@ describe Repology do
|
||||
end
|
||||
end
|
||||
|
||||
describe "parse_api_response", :needs_network, :needs_homebrew_curl do
|
||||
describe "parse_api_response", :needs_homebrew_curl, :needs_network do
|
||||
it "returns a hash of data" do
|
||||
limit = 1
|
||||
start_with = "x"
|
||||
|
||||
@ -107,7 +107,7 @@ $:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-1.35.1/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-performance-1.15.0/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-rails-2.16.1/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-rspec-2.13.2/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-rspec-2.15.0/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-sorbet-0.6.11/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/ruby-macho-3.0.0/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/simplecov-html-0.12.3/lib")
|
||||
|
||||
@ -1,158 +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', 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
|
||||
@ -1,100 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Checks for usage of implicit subject (`is_expected` / `should`).
|
||||
#
|
||||
# This cop can be configured using the `EnforcedStyle` option
|
||||
#
|
||||
# @example `EnforcedStyle: single_line_only` (default)
|
||||
# # bad
|
||||
# it do
|
||||
# is_expected.to be_truthy
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# it { is_expected.to be_truthy }
|
||||
# it do
|
||||
# expect(subject).to be_truthy
|
||||
# end
|
||||
#
|
||||
# @example `EnforcedStyle: single_statement_only`
|
||||
# # bad
|
||||
# it do
|
||||
# foo = 1
|
||||
# is_expected.to be_truthy
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# it do
|
||||
# foo = 1
|
||||
# expect(subject).to be_truthy
|
||||
# end
|
||||
# it do
|
||||
# is_expected.to be_truthy
|
||||
# end
|
||||
#
|
||||
# @example `EnforcedStyle: disallow`
|
||||
# # bad
|
||||
# it { is_expected.to be_truthy }
|
||||
#
|
||||
# # good
|
||||
# it { expect(subject).to be_truthy }
|
||||
#
|
||||
class ImplicitSubject < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
MSG = "Don't use implicit subject."
|
||||
RESTRICT_ON_SEND = %i[is_expected should should_not].freeze
|
||||
|
||||
# @!method implicit_subject?(node)
|
||||
def_node_matcher :implicit_subject?, <<-PATTERN
|
||||
(send nil? {:should :should_not :is_expected} ...)
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
return unless implicit_subject?(node)
|
||||
return if valid_usage?(node)
|
||||
|
||||
add_offense(node) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
replacement = 'expect(subject)'
|
||||
case node.method_name
|
||||
when :should
|
||||
replacement += '.to'
|
||||
when :should_not
|
||||
replacement += '.not_to'
|
||||
end
|
||||
|
||||
corrector.replace(node.loc.selector, replacement)
|
||||
end
|
||||
|
||||
def valid_usage?(node)
|
||||
example = node.ancestors.find { |parent| example?(parent) }
|
||||
return false if example.nil?
|
||||
|
||||
example.method?(:its) || allowed_by_style?(example)
|
||||
end
|
||||
|
||||
def allowed_by_style?(example)
|
||||
case style
|
||||
when :single_line_only
|
||||
example.single_line?
|
||||
when :single_statement_only
|
||||
!example.body.begin_type?
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,76 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Checks for explicitly referenced test subjects.
|
||||
#
|
||||
# RSpec lets you declare an "implicit subject" using `subject { ... }`
|
||||
# which allows for tests like `it { is_expected.to be_valid }`.
|
||||
# If you need to reference your test subject you should explicitly
|
||||
# name it using `subject(:your_subject_name) { ... }`. Your test subjects
|
||||
# should be the most important object in your tests so they deserve
|
||||
# a descriptive name.
|
||||
#
|
||||
# This cop can be configured in your configuration using the
|
||||
# `IgnoreSharedExamples` which will not report offenses for implicit
|
||||
# subjects in shared example groups.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# RSpec.describe User do
|
||||
# subject { described_class.new }
|
||||
#
|
||||
# it 'is valid' do
|
||||
# expect(subject.valid?).to be(true)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# RSpec.describe Foo do
|
||||
# subject(:user) { described_class.new }
|
||||
#
|
||||
# it 'is valid' do
|
||||
# expect(user.valid?).to be(true)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # also good
|
||||
# RSpec.describe Foo do
|
||||
# subject(:user) { described_class.new }
|
||||
#
|
||||
# it { is_expected.to be_valid }
|
||||
# end
|
||||
#
|
||||
class NamedSubject < Base
|
||||
MSG = 'Name your test subject if you need to reference it explicitly.'
|
||||
|
||||
# @!method example_or_hook_block?(node)
|
||||
def_node_matcher :example_or_hook_block?,
|
||||
block_pattern('{#Examples.all #Hooks.all}')
|
||||
|
||||
# @!method shared_example?(node)
|
||||
def_node_matcher :shared_example?,
|
||||
block_pattern('#SharedGroups.examples')
|
||||
|
||||
# @!method subject_usage(node)
|
||||
def_node_search :subject_usage, '$(send nil? :subject)'
|
||||
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
if !example_or_hook_block?(node) || ignored_shared_example?(node)
|
||||
return
|
||||
end
|
||||
|
||||
subject_usage(node) do |subject_node|
|
||||
add_offense(subject_node.loc.selector)
|
||||
end
|
||||
end
|
||||
|
||||
def ignored_shared_example?(node)
|
||||
cop_config['IgnoreSharedExamples'] &&
|
||||
node.each_ancestor(:block).any?(&method(:shared_example?))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,17 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module RSpec
|
||||
module FactoryBot
|
||||
# Contains node matchers for common FactoryBot DSL.
|
||||
module Language
|
||||
extend RuboCop::NodePattern::Macros
|
||||
|
||||
# @!method factory_bot?(node)
|
||||
def_node_matcher :factory_bot?, <<~PATTERN
|
||||
(const {nil? cbase} {:FactoryGirl :FactoryBot})
|
||||
PATTERN
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -12,8 +12,6 @@ RSpec:
|
||||
- Expectations
|
||||
- Helpers
|
||||
- Hooks
|
||||
- HookScopes
|
||||
- Runners
|
||||
- Subjects
|
||||
ExampleGroups:
|
||||
inherit_mode:
|
||||
@ -81,12 +79,6 @@ RSpec:
|
||||
- prepend_after
|
||||
- after
|
||||
- append_after
|
||||
HookScopes:
|
||||
- each
|
||||
- example
|
||||
- context
|
||||
- all
|
||||
- suite
|
||||
Includes:
|
||||
inherit_mode:
|
||||
merge:
|
||||
@ -98,10 +90,6 @@ RSpec:
|
||||
- include_examples
|
||||
Context:
|
||||
- include_context
|
||||
Runners:
|
||||
- to
|
||||
- to_not
|
||||
- not_to
|
||||
SharedGroups:
|
||||
inherit_mode:
|
||||
merge:
|
||||
@ -194,7 +182,7 @@ RSpec/ChangeByZero:
|
||||
Description: Prefer negated matchers over `to change.by(0)`.
|
||||
Enabled: pending
|
||||
VersionAdded: '2.11'
|
||||
VersionChanged: '2.13'
|
||||
VersionChanged: '2.14'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ChangeByZero
|
||||
NegatedMatcher: ~
|
||||
|
||||
@ -383,8 +371,10 @@ RSpec/ExampleWording:
|
||||
have: has
|
||||
HAVE: HAS
|
||||
IgnoredWords: []
|
||||
DisallowedExamples:
|
||||
- works
|
||||
VersionAdded: '1.0'
|
||||
VersionChanged: '1.2'
|
||||
VersionChanged: '2.13'
|
||||
StyleGuide: https://rspec.rubystyle.guide/#should-in-example-docstrings
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWording
|
||||
|
||||
@ -492,8 +482,9 @@ RSpec/ImplicitSubject:
|
||||
- single_line_only
|
||||
- single_statement_only
|
||||
- disallow
|
||||
- require_implicit
|
||||
VersionAdded: '1.29'
|
||||
VersionChanged: '1.30'
|
||||
VersionChanged: '2.13'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitSubject
|
||||
|
||||
RSpec/InstanceSpy:
|
||||
@ -621,8 +612,13 @@ RSpec/MultipleSubjects:
|
||||
RSpec/NamedSubject:
|
||||
Description: Checks for explicitly referenced test subjects.
|
||||
Enabled: true
|
||||
EnforcedStyle: always
|
||||
SupportedStyles:
|
||||
- always
|
||||
- named_only
|
||||
IgnoreSharedExamples: true
|
||||
VersionAdded: 1.5.3
|
||||
VersionChanged: '2.15'
|
||||
StyleGuide: https://rspec.rubystyle.guide/#use-subject
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NamedSubject
|
||||
|
||||
@ -640,7 +636,11 @@ RSpec/NoExpectationExample:
|
||||
Enabled: pending
|
||||
Safe: false
|
||||
VersionAdded: '2.13'
|
||||
VersionChanged: '2.14'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NoExpectationExample
|
||||
AllowedPatterns:
|
||||
- "^expect_"
|
||||
- "^assert_"
|
||||
|
||||
RSpec/NotToNot:
|
||||
Description: Checks for consistent method usage for negating expectations.
|
||||
@ -763,6 +763,12 @@ RSpec/SingleArgumentMessageChain:
|
||||
VersionChanged: '1.10'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SingleArgumentMessageChain
|
||||
|
||||
RSpec/SortMetadata:
|
||||
Description: Sort RSpec metadata alphabetically.
|
||||
Enabled: pending
|
||||
VersionAdded: '2.14'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SortMetadata
|
||||
|
||||
RSpec/StubbedMock:
|
||||
Description: Checks that message expectations do not have a configured response.
|
||||
Enabled: true
|
||||
@ -807,7 +813,6 @@ RSpec/VariableName:
|
||||
- snake_case
|
||||
- camelCase
|
||||
AllowedPatterns: []
|
||||
IgnoredPatterns: []
|
||||
VersionAdded: '1.40'
|
||||
VersionChanged: '2.13'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableName
|
||||
@ -866,6 +871,22 @@ RSpec/Capybara/FeatureMethods:
|
||||
VersionChanged: '2.0'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/FeatureMethods
|
||||
|
||||
RSpec/Capybara/NegationMatcher:
|
||||
Description: Enforces use of `have_no_*` or `not_to` for negated expectations.
|
||||
Enabled: pending
|
||||
VersionAdded: '2.14'
|
||||
EnforcedStyle: not_to
|
||||
SupportedStyles:
|
||||
- have_no
|
||||
- not_to
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/NegationMatcher
|
||||
|
||||
RSpec/Capybara/SpecificActions:
|
||||
Description: Checks for there is a more specific actions offered by Capybara.
|
||||
Enabled: pending
|
||||
VersionAdded: '2.14'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/SpecificActions
|
||||
|
||||
RSpec/Capybara/SpecificFinders:
|
||||
Description: Checks if there is a more specific finder offered by Capybara.
|
||||
Enabled: pending
|
||||
@ -901,6 +922,16 @@ RSpec/FactoryBot/AttributeDefinedStatically:
|
||||
VersionChanged: '2.0'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/AttributeDefinedStatically
|
||||
|
||||
RSpec/FactoryBot/ConsistentParenthesesStyle:
|
||||
Description: Use a consistent style for parentheses in factory bot calls.
|
||||
Enabled: pending
|
||||
EnforcedStyle: require_parentheses
|
||||
SupportedStyles:
|
||||
- require_parentheses
|
||||
- omit_parentheses
|
||||
VersionAdded: '2.14'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/ConsistentParenthesesStyle
|
||||
|
||||
RSpec/FactoryBot/CreateList:
|
||||
Description: Checks for create_list usage.
|
||||
Enabled: true
|
||||
@ -954,6 +985,29 @@ RSpec/Rails/HaveHttpStatus:
|
||||
VersionAdded: '2.12'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HaveHttpStatus
|
||||
|
||||
RSpec/Rails/InferredSpecType:
|
||||
Description: Identifies redundant spec type.
|
||||
Enabled: pending
|
||||
Safe: false
|
||||
VersionAdded: '2.14'
|
||||
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/InferredSpecType
|
||||
Inferences:
|
||||
channels: channel
|
||||
controllers: controller
|
||||
features: feature
|
||||
generator: generator
|
||||
helpers: helper
|
||||
jobs: job
|
||||
mailboxes: mailbox
|
||||
mailers: mailer
|
||||
models: model
|
||||
requests: request
|
||||
integration: request
|
||||
api: request
|
||||
routing: routing
|
||||
system: system
|
||||
views: view
|
||||
|
||||
RSpec/Rails/HttpStatus:
|
||||
Description: Enforces use of symbolic or numeric value to describe HTTP status.
|
||||
Enabled: true
|
||||
@ -23,6 +23,8 @@ 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/cop/rspec/mixin/skip_or_pending'
|
||||
require_relative 'rubocop/cop/rspec/mixin/capybara_help'
|
||||
|
||||
require_relative 'rubocop/rspec/concept'
|
||||
require_relative 'rubocop/rspec/example_group'
|
||||
@ -0,0 +1,106 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
module Capybara
|
||||
# Enforces use of `have_no_*` or `not_to` for negated expectations.
|
||||
#
|
||||
# @example EnforcedStyle: not_to (default)
|
||||
# # bad
|
||||
# expect(page).to have_no_selector
|
||||
# expect(page).to have_no_css('a')
|
||||
#
|
||||
# # good
|
||||
# expect(page).not_to have_selector
|
||||
# expect(page).not_to have_css('a')
|
||||
#
|
||||
# @example EnforcedStyle: have_no
|
||||
# # bad
|
||||
# expect(page).not_to have_selector
|
||||
# expect(page).not_to have_css('a')
|
||||
#
|
||||
# # good
|
||||
# expect(page).to have_no_selector
|
||||
# expect(page).to have_no_css('a')
|
||||
#
|
||||
class NegationMatcher < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
MSG = 'Use `expect(...).%<runner>s %<matcher>s`.'
|
||||
CAPYBARA_MATCHERS = %w[
|
||||
selector css xpath text title current_path link button
|
||||
field checked_field unchecked_field select table
|
||||
sibling ancestor
|
||||
].freeze
|
||||
POSITIVE_MATCHERS =
|
||||
Set.new(CAPYBARA_MATCHERS) { |element| :"have_#{element}" }.freeze
|
||||
NEGATIVE_MATCHERS =
|
||||
Set.new(CAPYBARA_MATCHERS) { |element| :"have_no_#{element}" }
|
||||
.freeze
|
||||
RESTRICT_ON_SEND = (POSITIVE_MATCHERS + NEGATIVE_MATCHERS).freeze
|
||||
|
||||
# @!method not_to?(node)
|
||||
def_node_matcher :not_to?, <<~PATTERN
|
||||
(send ... :not_to
|
||||
(send nil? %POSITIVE_MATCHERS ...))
|
||||
PATTERN
|
||||
|
||||
# @!method have_no?(node)
|
||||
def_node_matcher :have_no?, <<~PATTERN
|
||||
(send ... :to
|
||||
(send nil? %NEGATIVE_MATCHERS ...))
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
return unless offense?(node.parent)
|
||||
|
||||
matcher = node.method_name.to_s
|
||||
add_offense(offense_range(node),
|
||||
message: message(matcher)) do |corrector|
|
||||
corrector.replace(node.parent.loc.selector, replaced_runner)
|
||||
corrector.replace(node.loc.selector,
|
||||
replaced_matcher(matcher))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def offense?(node)
|
||||
(style == :have_no && not_to?(node)) ||
|
||||
(style == :not_to && have_no?(node))
|
||||
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(matcher))
|
||||
end
|
||||
|
||||
def replaced_runner
|
||||
case style
|
||||
when :have_no
|
||||
'to'
|
||||
when :not_to
|
||||
'not_to'
|
||||
end
|
||||
end
|
||||
|
||||
def replaced_matcher(matcher)
|
||||
case style
|
||||
when :have_no
|
||||
matcher.sub('have_', 'have_no_')
|
||||
when :not_to
|
||||
matcher.sub('have_no_', 'have_')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,85 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
module Capybara
|
||||
# Checks for there is a more specific actions offered by Capybara.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# find('a').click
|
||||
# find('button.cls').click
|
||||
# find('a', exact_text: 'foo').click
|
||||
# find('div button').click
|
||||
#
|
||||
# # good
|
||||
# click_link
|
||||
# click_button(class: 'cls')
|
||||
# click_link(exact_text: 'foo')
|
||||
# find('div').click_button
|
||||
#
|
||||
class SpecificActions < Base
|
||||
MSG = "Prefer `%<good_action>s` over `find('%<selector>s').click`."
|
||||
RESTRICT_ON_SEND = %i[click].freeze
|
||||
SPECIFIC_ACTION = {
|
||||
'button' => 'button',
|
||||
'a' => 'link'
|
||||
}.freeze
|
||||
|
||||
# @!method click_on_selector(node)
|
||||
def_node_matcher :click_on_selector, <<-PATTERN
|
||||
(send _ :find (str $_) ...)
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
click_on_selector(node.receiver) do |arg|
|
||||
next unless supported_selector?(arg)
|
||||
# Always check the last selector in the case of multiple selectors
|
||||
# separated by whitespace.
|
||||
# because the `.click` is executed on the element to
|
||||
# which the last selector points.
|
||||
next unless (selector = last_selector(arg))
|
||||
next unless (action = specific_action(selector))
|
||||
next unless CapybaraHelp.specific_option?(node.receiver, arg,
|
||||
action)
|
||||
next unless CapybaraHelp.specific_pseudo_classes?(arg)
|
||||
|
||||
range = offense_range(node, node.receiver)
|
||||
add_offense(range, message: message(action, selector))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def specific_action(selector)
|
||||
SPECIFIC_ACTION[last_selector(selector)]
|
||||
end
|
||||
|
||||
def supported_selector?(selector)
|
||||
!selector.match?(/[>,+~]/)
|
||||
end
|
||||
|
||||
def last_selector(arg)
|
||||
arg.split.last[/^\w+/, 0]
|
||||
end
|
||||
|
||||
def offense_range(node, receiver)
|
||||
receiver.loc.selector.with(end_pos: node.loc.expression.end_pos)
|
||||
end
|
||||
|
||||
def message(action, selector)
|
||||
format(MSG,
|
||||
good_action: good_action(action),
|
||||
selector: selector)
|
||||
end
|
||||
|
||||
def good_action(action)
|
||||
"click_#{action}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,81 @@
|
||||
# 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
|
||||
include CapybaraHelp
|
||||
|
||||
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
|
||||
|
||||
# @!method first_argument(node)
|
||||
def_node_matcher :first_argument, <<-PATTERN
|
||||
(send nil? _ (str $_) ... )
|
||||
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_option?(node, arg, matcher)
|
||||
next unless specific_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 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
|
||||
@ -61,7 +61,7 @@ module RuboCop
|
||||
extend AutoCorrector
|
||||
MSG = 'Prefer `not_to change` over `to change.by(0)`.'
|
||||
MSG_COMPOUND = 'Prefer %<preferred>s with compound expectations ' \
|
||||
'over `change.by(0)`.'
|
||||
'over `change.by(0)`.'
|
||||
RESTRICT_ON_SEND = %i[change].freeze
|
||||
|
||||
# @!method expect_change_with_arguments(node)
|
||||
@ -43,7 +43,7 @@ module RuboCop
|
||||
# # .rubocop.yml
|
||||
# # RSpec/ContextWording:
|
||||
# # AllowedPatterns:
|
||||
# # - /とき$/
|
||||
# # - とき$
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
@ -92,7 +92,9 @@ module RuboCop
|
||||
end
|
||||
|
||||
def expect_patterns
|
||||
inspected = allowed_patterns.map(&:inspect)
|
||||
inspected = allowed_patterns.map do |pattern|
|
||||
pattern.inspect.gsub(/\A"|"\z/, '/')
|
||||
end
|
||||
return inspected.first if inspected.size == 1
|
||||
|
||||
inspected << "or #{inspected.pop}"
|
||||
@ -6,12 +6,17 @@ module RuboCop
|
||||
# Checks for common mistakes in example descriptions.
|
||||
#
|
||||
# This cop will correct docstrings that begin with 'should' and 'it'.
|
||||
# This cop will also look for insufficient examples and call them out.
|
||||
#
|
||||
# @see http://betterspecs.org/#should
|
||||
#
|
||||
# The autocorrect is experimental - use with care! It can be configured
|
||||
# with CustomTransform (e.g. have => has) and IgnoredWords (e.g. only).
|
||||
#
|
||||
# Use the DisallowedExamples setting to prevent unclear or insufficient
|
||||
# descriptions. Please note that this config will not be treated as
|
||||
# case sensitive.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# it 'should find nothing' do
|
||||
@ -30,11 +35,21 @@ module RuboCop
|
||||
# it 'does things' do
|
||||
# end
|
||||
#
|
||||
# @example `DisallowedExamples: ['works']` (default)
|
||||
# # bad
|
||||
# it 'works' do
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# it 'marks the task as done' do
|
||||
# end
|
||||
class ExampleWording < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG_SHOULD = 'Do not use should when describing your tests.'
|
||||
MSG_IT = "Do not repeat 'it' when describing your tests."
|
||||
MSG_INSUFFICIENT_DESCRIPTION = 'Your example description is ' \
|
||||
'insufficient.'
|
||||
|
||||
SHOULD_PREFIX = /\Ashould(?:n't)?\b/i.freeze
|
||||
IT_PREFIX = /\Ait /i.freeze
|
||||
@ -53,6 +68,9 @@ module RuboCop
|
||||
add_wording_offense(description_node, MSG_SHOULD)
|
||||
elsif message.match?(IT_PREFIX)
|
||||
add_wording_offense(description_node, MSG_IT)
|
||||
elsif insufficient_docstring?(description_node)
|
||||
add_offense(docstring(description_node),
|
||||
message: MSG_INSUFFICIENT_DESCRIPTION)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -113,6 +131,19 @@ module RuboCop
|
||||
def ignored_words
|
||||
cop_config.fetch('IgnoredWords', [])
|
||||
end
|
||||
|
||||
def insufficient_docstring?(description_node)
|
||||
insufficient_examples.include?(preprocess(text(description_node)))
|
||||
end
|
||||
|
||||
def insufficient_examples
|
||||
examples = cop_config.fetch('DisallowedExamples', [])
|
||||
examples.map! { |example| preprocess(example) }
|
||||
end
|
||||
|
||||
def preprocess(message)
|
||||
message.strip.squeeze(' ').downcase
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,115 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
module FactoryBot
|
||||
# Use a consistent style for parentheses in factory bot calls.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# create :user
|
||||
# build(:user)
|
||||
# create(:login)
|
||||
# create :login
|
||||
#
|
||||
# @example `EnforcedStyle: require_parentheses` (default)
|
||||
#
|
||||
# # good
|
||||
# create(:user)
|
||||
# create(:user)
|
||||
# create(:login)
|
||||
# build(:login)
|
||||
#
|
||||
# @example `EnforcedStyle: omit_parentheses`
|
||||
#
|
||||
# # good
|
||||
# create :user
|
||||
# build :user
|
||||
# create :login
|
||||
# create :login
|
||||
#
|
||||
# # also good
|
||||
# # when method name and first argument are not on same line
|
||||
# create(
|
||||
# :user
|
||||
# )
|
||||
# build(
|
||||
# :user,
|
||||
# name: 'foo'
|
||||
# )
|
||||
#
|
||||
class ConsistentParenthesesStyle < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
include RuboCop::RSpec::FactoryBot::Language
|
||||
include RuboCop::Cop::Util
|
||||
|
||||
def self.autocorrect_incompatible_with
|
||||
[Style::MethodCallWithArgsParentheses]
|
||||
end
|
||||
|
||||
MSG_REQUIRE_PARENS = 'Prefer method call with parentheses'
|
||||
MSG_OMIT_PARENS = 'Prefer method call without parentheses'
|
||||
|
||||
FACTORY_CALLS = RuboCop::RSpec::FactoryBot::Language::METHODS
|
||||
|
||||
RESTRICT_ON_SEND = FACTORY_CALLS
|
||||
|
||||
# @!method factory_call(node)
|
||||
def_node_matcher :factory_call, <<-PATTERN
|
||||
(send
|
||||
{#factory_bot? nil?} %FACTORY_CALLS
|
||||
{sym str send lvar} _*
|
||||
)
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
return if ambiguous_without_parentheses?(node)
|
||||
|
||||
factory_call(node) do
|
||||
if node.parenthesized?
|
||||
process_with_parentheses(node)
|
||||
else
|
||||
process_without_parentheses(node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def process_with_parentheses(node)
|
||||
return unless style == :omit_parentheses
|
||||
return unless same_line?(node, node.first_argument)
|
||||
|
||||
add_offense(node.loc.selector,
|
||||
message: MSG_OMIT_PARENS) do |corrector|
|
||||
remove_parentheses(corrector, node)
|
||||
end
|
||||
end
|
||||
|
||||
def process_without_parentheses(node)
|
||||
return unless style == :require_parentheses
|
||||
|
||||
add_offense(node.loc.selector,
|
||||
message: MSG_REQUIRE_PARENS) do |corrector|
|
||||
add_parentheses(node, corrector)
|
||||
end
|
||||
end
|
||||
|
||||
def ambiguous_without_parentheses?(node)
|
||||
node.parent&.send_type? ||
|
||||
node.parent&.pair_type? ||
|
||||
node.parent&.array_type?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def remove_parentheses(corrector, node)
|
||||
corrector.replace(node.location.begin, ' ')
|
||||
corrector.remove(node.location.end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -238,8 +238,8 @@ module RuboCop
|
||||
indent = ' ' * node.body.loc.column
|
||||
indent_end = ' ' * node.parent.loc.column
|
||||
" do #{node.arguments.source}\n" \
|
||||
"#{indent}#{node.body.source}\n" \
|
||||
"#{indent_end}end"
|
||||
"#{indent}#{node.body.source}\n" \
|
||||
"#{indent_end}end"
|
||||
end
|
||||
|
||||
def format_singleline_block(node)
|
||||
@ -54,25 +54,7 @@ module RuboCop
|
||||
|
||||
MSG = 'Use `%<method>s` from `FactoryBot::Syntax::Methods`.'
|
||||
|
||||
RESTRICT_ON_SEND = %i[
|
||||
attributes_for
|
||||
attributes_for_list
|
||||
attributes_for_pair
|
||||
build
|
||||
build_list
|
||||
build_pair
|
||||
build_stubbed
|
||||
build_stubbed_list
|
||||
build_stubbed_pair
|
||||
create
|
||||
create_list
|
||||
create_pair
|
||||
generate
|
||||
generate_list
|
||||
null
|
||||
null_list
|
||||
null_pair
|
||||
].to_set.freeze
|
||||
RESTRICT_ON_SEND = RuboCop::RSpec::FactoryBot::Language::METHODS
|
||||
|
||||
def on_send(node)
|
||||
return unless factory_bot?(node.receiver)
|
||||
@ -76,8 +76,6 @@ module RuboCop
|
||||
return unless top_level_groups.one?
|
||||
|
||||
example_group(node) do |send_node, example_group, arguments|
|
||||
next if routing_spec?(arguments)
|
||||
|
||||
ensure_correct_file_path(send_node, example_group, arguments)
|
||||
end
|
||||
end
|
||||
@ -85,7 +83,7 @@ module RuboCop
|
||||
private
|
||||
|
||||
def ensure_correct_file_path(send_node, example_group, arguments)
|
||||
pattern = pattern_for(example_group, arguments.first)
|
||||
pattern = pattern_for(example_group, arguments)
|
||||
return if filename_ends_with?(pattern)
|
||||
|
||||
# For the suffix shown in the offense message, modify the regular
|
||||
@ -97,11 +95,13 @@ module RuboCop
|
||||
end
|
||||
|
||||
def routing_spec?(args)
|
||||
args.any?(&method(:routing_metadata?))
|
||||
args.any?(&method(:routing_metadata?)) || routing_spec_path?
|
||||
end
|
||||
|
||||
def pattern_for(example_group, method_name)
|
||||
if spec_suffix_only? || !example_group.const_type?
|
||||
def pattern_for(example_group, arguments)
|
||||
method_name = arguments.first
|
||||
if spec_suffix_only? || !example_group.const_type? ||
|
||||
routing_spec?(arguments)
|
||||
return pattern_for_spec_suffix_only
|
||||
end
|
||||
|
||||
@ -149,8 +149,7 @@ module RuboCop
|
||||
end
|
||||
|
||||
def filename_ends_with?(pattern)
|
||||
filename = File.expand_path(processed_source.buffer.name)
|
||||
filename.match?("#{pattern}$")
|
||||
expanded_file_path.match?("#{pattern}$")
|
||||
end
|
||||
|
||||
def relevant_rubocop_rspec_file?(_file)
|
||||
@ -160,6 +159,14 @@ module RuboCop
|
||||
def spec_suffix_only?
|
||||
cop_config['SpecSuffixOnly']
|
||||
end
|
||||
|
||||
def routing_spec_path?
|
||||
expanded_file_path.include?('spec/routing/')
|
||||
end
|
||||
|
||||
def expanded_file_path
|
||||
File.expand_path(processed_source.buffer.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,167 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Checks for usage of implicit subject (`is_expected` / `should`).
|
||||
#
|
||||
# This cop can be configured using the `EnforcedStyle` option
|
||||
#
|
||||
# @example `EnforcedStyle: single_line_only` (default)
|
||||
# # bad
|
||||
# it do
|
||||
# is_expected.to be_truthy
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# it { is_expected.to be_truthy }
|
||||
# it do
|
||||
# expect(subject).to be_truthy
|
||||
# end
|
||||
#
|
||||
# @example `EnforcedStyle: single_statement_only`
|
||||
# # bad
|
||||
# it do
|
||||
# foo = 1
|
||||
# is_expected.to be_truthy
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# it do
|
||||
# foo = 1
|
||||
# expect(subject).to be_truthy
|
||||
# end
|
||||
# it do
|
||||
# is_expected.to be_truthy
|
||||
# end
|
||||
#
|
||||
# @example `EnforcedStyle: disallow`
|
||||
# # bad
|
||||
# it { is_expected.to be_truthy }
|
||||
#
|
||||
# # good
|
||||
# it { expect(subject).to be_truthy }
|
||||
#
|
||||
# @example `EnforcedStyle: require_implicit`
|
||||
# # bad
|
||||
# it { expect(subject).to be_truthy }
|
||||
#
|
||||
# # good
|
||||
# it { is_expected.to be_truthy }
|
||||
#
|
||||
# # bad
|
||||
# it do
|
||||
# expect(subject).to be_truthy
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# it do
|
||||
# is_expected.to be_truthy
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# it { expect(named_subject).to be_truthy }
|
||||
#
|
||||
class ImplicitSubject < Base
|
||||
extend AutoCorrector
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
MSG_REQUIRE_EXPLICIT = "Don't use implicit subject."
|
||||
|
||||
MSG_REQUIRE_IMPLICIT = "Don't use explicit subject."
|
||||
|
||||
RESTRICT_ON_SEND = %i[
|
||||
expect
|
||||
is_expected
|
||||
should
|
||||
should_not
|
||||
].freeze
|
||||
|
||||
# @!method explicit_unnamed_subject?(node)
|
||||
def_node_matcher :explicit_unnamed_subject?, <<-PATTERN
|
||||
(send nil? :expect (send nil? :subject))
|
||||
PATTERN
|
||||
|
||||
# @!method implicit_subject?(node)
|
||||
def_node_matcher :implicit_subject?, <<-PATTERN
|
||||
(send nil? {:should :should_not :is_expected} ...)
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
return unless invalid?(node)
|
||||
|
||||
add_offense(node) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(corrector, node)
|
||||
case node.method_name
|
||||
when :expect
|
||||
corrector.replace(node, 'is_expected')
|
||||
when :is_expected
|
||||
corrector.replace(node.location.selector, 'expect(subject)')
|
||||
when :should
|
||||
corrector.replace(node.location.selector, 'expect(subject).to')
|
||||
when :should_not
|
||||
corrector.replace(node.location.selector, 'expect(subject).not_to')
|
||||
end
|
||||
end
|
||||
|
||||
def message(_node)
|
||||
case style
|
||||
when :require_implicit
|
||||
MSG_REQUIRE_IMPLICIT
|
||||
else
|
||||
MSG_REQUIRE_EXPLICIT
|
||||
end
|
||||
end
|
||||
|
||||
def invalid?(node)
|
||||
case style
|
||||
when :require_implicit
|
||||
explicit_unnamed_subject?(node)
|
||||
when :disallow
|
||||
implicit_subject_in_non_its?(node)
|
||||
when :single_line_only
|
||||
implicit_subject_in_non_its_and_non_single_line?(node)
|
||||
when :single_statement_only
|
||||
implicit_subject_in_non_its_and_non_single_statement?(node)
|
||||
end
|
||||
end
|
||||
|
||||
def implicit_subject_in_non_its?(node)
|
||||
implicit_subject?(node) && !its?(node)
|
||||
end
|
||||
|
||||
def implicit_subject_in_non_its_and_non_single_line?(node)
|
||||
implicit_subject_in_non_its?(node) && !single_line?(node)
|
||||
end
|
||||
|
||||
def implicit_subject_in_non_its_and_non_single_statement?(node)
|
||||
implicit_subject_in_non_its?(node) && !single_statement?(node)
|
||||
end
|
||||
|
||||
def its?(node)
|
||||
example_of(node)&.method?(:its)
|
||||
end
|
||||
|
||||
def single_line?(node)
|
||||
example_of(node)&.single_line?
|
||||
end
|
||||
|
||||
def single_statement?(node)
|
||||
!example_of(node)&.body&.begin_type?
|
||||
end
|
||||
|
||||
def example_of(node)
|
||||
node.each_ancestor.find do |ancestor|
|
||||
example?(ancestor)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -43,6 +43,14 @@ module RuboCop
|
||||
}
|
||||
PATTERN
|
||||
|
||||
# @!method include_examples?(node)
|
||||
def_node_matcher :include_examples?, <<~PATTERN
|
||||
{
|
||||
#{block_pattern(':include_examples')}
|
||||
#{send_pattern(':include_examples')}
|
||||
}
|
||||
PATTERN
|
||||
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
return unless example_group_with_body?(node)
|
||||
|
||||
@ -51,6 +59,10 @@ module RuboCop
|
||||
|
||||
private
|
||||
|
||||
def example_group_with_include_examples?(body)
|
||||
body.children.any? { |sibling| include_examples?(sibling) }
|
||||
end
|
||||
|
||||
def multiline_block?(block)
|
||||
block.begin_type?
|
||||
end
|
||||
@ -59,11 +71,13 @@ module RuboCop
|
||||
first_example = find_first_example(node)
|
||||
return unless first_example
|
||||
|
||||
correct = !example_group_with_include_examples?(node)
|
||||
|
||||
first_example.right_siblings.each do |sibling|
|
||||
next unless let?(sibling)
|
||||
|
||||
add_offense(sibling) do |corrector|
|
||||
autocorrect(corrector, sibling, first_example)
|
||||
autocorrect(corrector, sibling, first_example) if correct
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,80 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Help methods for capybara.
|
||||
module CapybaraHelp
|
||||
module_function
|
||||
|
||||
# @param node [RuboCop::AST::SendNode]
|
||||
# @param locator [String]
|
||||
# @param element [String]
|
||||
# @return [Boolean]
|
||||
def specific_option?(node, locator, element)
|
||||
attrs = CssSelector.attributes(locator).keys
|
||||
return false unless replaceable_element?(node, element, attrs)
|
||||
|
||||
attrs.all? do |attr|
|
||||
CssSelector.specific_options?(element, attr)
|
||||
end
|
||||
end
|
||||
|
||||
# @param locator [String]
|
||||
# @return [Boolean]
|
||||
def specific_pseudo_classes?(locator)
|
||||
CssSelector.pseudo_classes(locator).all? do |pseudo_class|
|
||||
replaceable_pseudo_class?(pseudo_class, locator)
|
||||
end
|
||||
end
|
||||
|
||||
# @param pseudo_class [String]
|
||||
# @param locator [String]
|
||||
# @return [Boolean]
|
||||
def replaceable_pseudo_class?(pseudo_class, locator)
|
||||
return false unless CssSelector.specific_pesudo_classes?(pseudo_class)
|
||||
|
||||
case pseudo_class
|
||||
when 'not()' then replaceable_pseudo_class_not?(locator)
|
||||
else true
|
||||
end
|
||||
end
|
||||
|
||||
# @param locator [String]
|
||||
# @return [Boolean]
|
||||
def replaceable_pseudo_class_not?(locator)
|
||||
locator.scan(/not\(.*?\)/).all? do |negation|
|
||||
CssSelector.attributes(negation).values.all? do |v|
|
||||
v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @param node [RuboCop::AST::SendNode]
|
||||
# @param element [String]
|
||||
# @param attrs [Array<String>]
|
||||
# @return [Boolean]
|
||||
def replaceable_element?(node, element, attrs)
|
||||
case element
|
||||
when 'link' then replaceable_to_link?(node, attrs)
|
||||
else true
|
||||
end
|
||||
end
|
||||
|
||||
# @param node [RuboCop::AST::SendNode]
|
||||
# @param attrs [Array<String>]
|
||||
# @return [Boolean]
|
||||
def replaceable_to_link?(node, attrs)
|
||||
include_option?(node, :href) || attrs.include?('href')
|
||||
end
|
||||
|
||||
# @param node [RuboCop::AST::SendNode]
|
||||
# @param option [Symbol]
|
||||
# @return [Boolean]
|
||||
def include_option?(node, option)
|
||||
node.each_descendant(:sym).find { |opt| opt.value == option }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -10,9 +10,56 @@ module RuboCop
|
||||
id class style visible obscured exact exact_text normalize_ws match
|
||||
wait filter_set focused
|
||||
].freeze
|
||||
SPECIFIC_OPTIONS = {
|
||||
'button' => (
|
||||
COMMON_OPTIONS + %w[disabled name value title type]
|
||||
).freeze,
|
||||
'link' => (
|
||||
COMMON_OPTIONS + %w[href alt title download]
|
||||
).freeze,
|
||||
'table' => (
|
||||
COMMON_OPTIONS + %w[
|
||||
caption with_cols cols with_rows rows
|
||||
]
|
||||
).freeze,
|
||||
'select' => (
|
||||
COMMON_OPTIONS + %w[
|
||||
disabled name placeholder options enabled_options
|
||||
disabled_options selected with_selected multiple with_options
|
||||
]
|
||||
).freeze,
|
||||
'field' => (
|
||||
COMMON_OPTIONS + %w[
|
||||
checked unchecked disabled valid name placeholder
|
||||
validation_message readonly with type multiple
|
||||
]
|
||||
).freeze
|
||||
}.freeze
|
||||
SPECIFIC_PSEUDO_CLASSES = %w[
|
||||
not() disabled enabled checked unchecked
|
||||
].freeze
|
||||
|
||||
module_function
|
||||
|
||||
# @param element [String]
|
||||
# @param attribute [String]
|
||||
# @return [Boolean]
|
||||
# @example
|
||||
# specific_pesudo_classes?('button', 'name') # => true
|
||||
# specific_pesudo_classes?('link', 'invalid') # => false
|
||||
def specific_options?(element, attribute)
|
||||
SPECIFIC_OPTIONS.fetch(element, []).include?(attribute)
|
||||
end
|
||||
|
||||
# @param pseudo_class [String]
|
||||
# @return [Boolean]
|
||||
# @example
|
||||
# specific_pesudo_classes?('disabled') # => true
|
||||
# specific_pesudo_classes?('first-of-type') # => false
|
||||
def specific_pesudo_classes?(pseudo_class)
|
||||
SPECIFIC_PSEUDO_CLASSES.include?(pseudo_class)
|
||||
end
|
||||
|
||||
# @param selector [String]
|
||||
# @return [Boolean]
|
||||
# @example
|
||||
@ -75,7 +122,7 @@ module RuboCop
|
||||
# multiple_selectors?('a.cls b#id') # => true
|
||||
# multiple_selectors?('a.cls') # => false
|
||||
def multiple_selectors?(selector)
|
||||
selector.match?(/[ >,+]/)
|
||||
selector.match?(/[ >,+~]/)
|
||||
end
|
||||
|
||||
# @param value [String]
|
||||
@ -0,0 +1,23 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Helps check offenses with variable definitions
|
||||
module SkipOrPending
|
||||
extend RuboCop::NodePattern::Macros
|
||||
|
||||
# @!method skipped_in_metadata?(node)
|
||||
def_node_matcher :skipped_in_metadata?, <<-PATTERN
|
||||
{
|
||||
(send _ _ <#skip_or_pending? ...>)
|
||||
(send _ _ ... (hash <(pair #skip_or_pending? { true str }) ...>))
|
||||
}
|
||||
PATTERN
|
||||
|
||||
# @!method skip_or_pending?(node)
|
||||
def_node_matcher :skip_or_pending?, '{(sym :skip) (sym :pending)}'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,151 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# Checks for explicitly referenced test subjects.
|
||||
#
|
||||
# RSpec lets you declare an "implicit subject" using `subject { ... }`
|
||||
# which allows for tests like `it { is_expected.to be_valid }`.
|
||||
# If you need to reference your test subject you should explicitly
|
||||
# name it using `subject(:your_subject_name) { ... }`. Your test subjects
|
||||
# should be the most important object in your tests so they deserve
|
||||
# a descriptive name.
|
||||
#
|
||||
# This cop can be configured in your configuration using `EnforcedStyle`,
|
||||
# and `IgnoreSharedExamples` which will not report offenses for implicit
|
||||
# subjects in shared example groups.
|
||||
#
|
||||
# @example `EnforcedStyle: always` (default)
|
||||
# # bad
|
||||
# RSpec.describe User do
|
||||
# subject { described_class.new }
|
||||
#
|
||||
# it 'is valid' do
|
||||
# expect(subject.valid?).to be(true)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# RSpec.describe User do
|
||||
# subject(:user) { described_class.new }
|
||||
#
|
||||
# it 'is valid' do
|
||||
# expect(user.valid?).to be(true)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # also good
|
||||
# RSpec.describe User do
|
||||
# subject(:user) { described_class.new }
|
||||
#
|
||||
# it { is_expected.to be_valid }
|
||||
# end
|
||||
#
|
||||
# @example `EnforcedStyle: named_only`
|
||||
# # bad
|
||||
# RSpec.describe User do
|
||||
# subject(:user) { described_class.new }
|
||||
#
|
||||
# it 'is valid' do
|
||||
# expect(subject.valid?).to be(true)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# RSpec.describe User do
|
||||
# subject(:user) { described_class.new }
|
||||
#
|
||||
# it 'is valid' do
|
||||
# expect(user.valid?).to be(true)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # also good
|
||||
# RSpec.describe User do
|
||||
# subject { described_class.new }
|
||||
#
|
||||
# it { is_expected.to be_valid }
|
||||
# end
|
||||
#
|
||||
# # acceptable
|
||||
# RSpec.describe User do
|
||||
# subject { described_class.new }
|
||||
#
|
||||
# it 'is valid' do
|
||||
# expect(subject.valid?).to be(true)
|
||||
# end
|
||||
# end
|
||||
class NamedSubject < Base
|
||||
include ConfigurableEnforcedStyle
|
||||
|
||||
MSG = 'Name your test subject if you need to reference it explicitly.'
|
||||
|
||||
# @!method example_or_hook_block?(node)
|
||||
def_node_matcher :example_or_hook_block?,
|
||||
block_pattern('{#Examples.all #Hooks.all}')
|
||||
|
||||
# @!method shared_example?(node)
|
||||
def_node_matcher :shared_example?,
|
||||
block_pattern('#SharedGroups.examples')
|
||||
|
||||
# @!method subject_usage(node)
|
||||
def_node_search :subject_usage, '$(send nil? :subject)'
|
||||
|
||||
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
||||
if !example_or_hook_block?(node) || ignored_shared_example?(node)
|
||||
return
|
||||
end
|
||||
|
||||
subject_usage(node) do |subject_node|
|
||||
check_explicit_subject(subject_node)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ignored_shared_example?(node)
|
||||
cop_config['IgnoreSharedExamples'] &&
|
||||
node.each_ancestor(:block).any?(&method(:shared_example?))
|
||||
end
|
||||
|
||||
def check_explicit_subject(node)
|
||||
return if allow_explicit_subject?(node)
|
||||
|
||||
add_offense(node.loc.selector)
|
||||
end
|
||||
|
||||
def allow_explicit_subject?(node)
|
||||
!always? && !named_only?(node)
|
||||
end
|
||||
|
||||
def always?
|
||||
style == :always
|
||||
end
|
||||
|
||||
def named_only?(node)
|
||||
style == :named_only &&
|
||||
subject_definition_is_named?(node)
|
||||
end
|
||||
|
||||
def subject_definition_is_named?(node)
|
||||
subject = nearest_subject(node)
|
||||
|
||||
subject&.send_node&.arguments?
|
||||
end
|
||||
|
||||
def nearest_subject(node)
|
||||
node
|
||||
.each_ancestor(:block)
|
||||
.lazy
|
||||
.map { |block_node| find_subject(block_node) }
|
||||
.find(&:itself)
|
||||
end
|
||||
|
||||
def find_subject(block_node)
|
||||
block_node.body.child_nodes.find { |send_node| subject?(send_node) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -133,7 +133,7 @@ module RuboCop
|
||||
def count_up_nesting?(node, example_group)
|
||||
example_group &&
|
||||
(node.block_type? &&
|
||||
!allowed_groups.include?(node.method_name))
|
||||
!allowed_groups.include?(node.method_name.to_s))
|
||||
end
|
||||
|
||||
def message(nesting)
|
||||
@ -28,7 +28,37 @@ module RuboCop
|
||||
# expect(a?).to be(true)
|
||||
# end
|
||||
#
|
||||
# This cop can be customized with an allowed expectation methods pattern
|
||||
# with an `AllowedPatterns` option. ^expect_ and ^assert_ are allowed
|
||||
# by default.
|
||||
#
|
||||
# @example `AllowedPatterns` configuration
|
||||
#
|
||||
# # .rubocop.yml
|
||||
# # RSpec/NoExpectationExample:
|
||||
# # AllowedPatterns:
|
||||
# # - ^expect_
|
||||
# # - ^assert_
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# it do
|
||||
# not_expect_something
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# it do
|
||||
# expect_something
|
||||
# end
|
||||
#
|
||||
# it do
|
||||
# assert_something
|
||||
# end
|
||||
#
|
||||
class NoExpectationExample < Base
|
||||
include AllowedPattern
|
||||
include SkipOrPending
|
||||
|
||||
MSG = 'No expectation found in this example.'
|
||||
|
||||
# @!method regular_or_focused_example?(node)
|
||||
@ -41,26 +71,29 @@ module RuboCop
|
||||
}
|
||||
PATTERN
|
||||
|
||||
# @!method including_any_expectation?(node)
|
||||
# @!method includes_expectation?(node)
|
||||
# @param [RuboCop::AST::Node] node
|
||||
# @return [Boolean]
|
||||
def_node_search(
|
||||
:including_any_expectation?,
|
||||
send_pattern('#Expectations.all')
|
||||
)
|
||||
def_node_search :includes_expectation?, <<~PATTERN
|
||||
{
|
||||
#{send_pattern('#Expectations.all')}
|
||||
(send nil? `#matches_allowed_pattern? ...)
|
||||
}
|
||||
PATTERN
|
||||
|
||||
# @!method including_any_skip_example?(node)
|
||||
# @!method includes_skip_example?(node)
|
||||
# @param [RuboCop::AST::Node] node
|
||||
# @return [Boolean]
|
||||
def_node_search :including_any_skip_example?, <<~PATTERN
|
||||
def_node_search :includes_skip_example?, <<~PATTERN
|
||||
(send nil? {:pending :skip} ...)
|
||||
PATTERN
|
||||
|
||||
# @param [RuboCop::AST::BlockNode] node
|
||||
def on_block(node)
|
||||
return unless regular_or_focused_example?(node)
|
||||
return if including_any_expectation?(node)
|
||||
return if including_any_skip_example?(node)
|
||||
return if includes_expectation?(node)
|
||||
return if includes_skip_example?(node)
|
||||
return if skipped_in_metadata?(node.send_node)
|
||||
|
||||
add_offense(node)
|
||||
end
|
||||
@ -33,6 +33,8 @@ module RuboCop
|
||||
# end
|
||||
#
|
||||
class Pending < Base
|
||||
include SkipOrPending
|
||||
|
||||
MSG = 'Pending spec found.'
|
||||
|
||||
# @!method skippable?(node)
|
||||
@ -41,17 +43,6 @@ module RuboCop
|
||||
{#ExampleGroups.regular #Examples.regular}
|
||||
PATTERN
|
||||
|
||||
# @!method skipped_in_metadata?(node)
|
||||
def_node_matcher :skipped_in_metadata?, <<-PATTERN
|
||||
{
|
||||
(send _ _ <#skip_or_pending? ...>)
|
||||
(send _ _ ... (hash <(pair #skip_or_pending? { true str }) ...>))
|
||||
}
|
||||
PATTERN
|
||||
|
||||
# @!method skip_or_pending?(node)
|
||||
def_node_matcher :skip_or_pending?, '{(sym :skip) (sym :pending)}'
|
||||
|
||||
# @!method pending_block?(node)
|
||||
def_node_matcher :pending_block?,
|
||||
send_pattern(<<~PATTERN)
|
||||
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