diff --git a/CHANGELOG.md b/CHANGELOG.md index 525f190e4..3ee347370 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Fix `RSpec/DescribedClass`'s error when a `described_class` is part of the namespace. ([@pirj][]) * Fix `RSpec/ExampleWording` autocorrect of multi-line docstrings. ([@pirj][]) * Add `RSpec/ContextMethod` cop, to detect method names in `context`. ([@geniou][]) +* Update RuboCop dependency to 0.68.1 with support for children matching node pattern syntax. ([@pirj][]) ## 1.35.0 (2019-08-02) diff --git a/lib/rubocop/cop/rspec/describe_class.rb b/lib/rubocop/cop/rspec/describe_class.rb index 3cabb5085..101fabecb 100644 --- a/lib/rubocop/cop/rspec/describe_class.rb +++ b/lib/rubocop/cop/rspec/describe_class.rb @@ -29,17 +29,17 @@ class DescribeClass < Cop } PATTERN - def_node_matcher :describe_with_metadata, <<-PATTERN - (send #{RSPEC} :describe - !const - ... - (hash $...)) + def_node_matcher :describe_with_rails_metadata?, <<-PATTERN + (send #{RSPEC} :describe !const ... + (hash <#rails_metadata? ...>) + ) PATTERN def_node_matcher :rails_metadata?, <<-PATTERN (pair (sym :type) - (sym {:request :feature :system :routing :view})) + (sym {:request :feature :system :routing :view}) + ) PATTERN def_node_matcher :shared_group?, SharedGroups::ALL.block_pattern @@ -47,10 +47,7 @@ class DescribeClass < Cop def on_top_level_describe(node, args) return if shared_group?(root_node) return if valid_describe?(node) - - describe_with_metadata(node) do |pairs| - return if pairs.any?(&method(:rails_metadata?)) - end + return if describe_with_rails_metadata?(node) add_offense(args.first) end diff --git a/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb b/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb index 6d2d37e19..863eb401f 100644 --- a/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +++ b/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb @@ -38,7 +38,7 @@ class AttributeDefinedStatically < Cop def on_block(node) factory_attributes(node).to_a.flatten.each do |attribute| next unless offensive_receiver?(attribute.receiver, node) - next if proc?(attribute) || association?(attribute) + next if proc?(attribute) || association?(attribute.first_argument) add_offense(attribute) end @@ -72,14 +72,7 @@ def proc?(attribute) value_matcher(attribute).to_a.all?(&:block_pass_type?) end - def association?(attribute) - argument = attribute.first_argument - argument.hash_type? && factory_key?(argument) - end - - def factory_key?(hash_node) - hash_node.keys.any? { |key| key.sym_type? && key.value == :factory } - end + def_node_matcher :association?, '(hash <(pair (sym :factory) _) ...>)' def autocorrect_replacing_parens(node) left_braces, right_braces = braces(node) diff --git a/lib/rubocop/cop/rspec/multiple_expectations.rb b/lib/rubocop/cop/rspec/multiple_expectations.rb index 86c253e9b..2910d5213 100644 --- a/lib/rubocop/cop/rspec/multiple_expectations.rb +++ b/lib/rubocop/cop/rspec/multiple_expectations.rb @@ -50,14 +50,23 @@ class MultipleExpectations < Cop MSG = 'Example has too many expectations [%d/%d].' - def_node_search :with_aggregate_failures?, '(sym :aggregate_failures)' - def_node_search :disabled_aggregate_failures?, <<-PATTERN - (pair (sym :aggregate_failures) (false)) + def_node_matcher :aggregate_failures?, <<-PATTERN + (block { + (send _ _ <(sym :aggregate_failures) ...>) + (send _ _ ... (hash <(pair (sym :aggregate_failures) true) ...>)) + } ...) + PATTERN + + def_node_matcher :aggregate_failures_present?, <<-PATTERN + (block { + (send _ _ <(sym :aggregate_failures) ...>) + (send _ _ ... (hash <(pair (sym :aggregate_failures) _) ...>)) + } ...) PATTERN def_node_matcher :expect?, Expectations::ALL.send_pattern def_node_matcher :aggregate_failures_block?, <<-PATTERN - (block (send _ :aggregate_failures ...) ...) + (block (send nil? :aggregate_failures ...) ...) PATTERN def on_block(node) @@ -88,23 +97,6 @@ def find_aggregate_failures(example_node) .find { |block_node| aggregate_failures_present?(block_node) } end - def aggregate_failures_present?(node) - metadata(node)&.any?(&method(:with_aggregate_failures?)) - end - - def aggregate_failures?(example_or_group_node) - metadata(example_or_group_node)&.any? do |metadata| - with_aggregate_failures?(metadata) && - !disabled_aggregate_failures?(metadata) - end - end - - def metadata(example_or_group_node) - RuboCop::RSpec::Example - .new(example_or_group_node) - .metadata - end - def find_expectation(node, &block) yield if expect?(node) || aggregate_failures_block?(node) diff --git a/lib/rubocop/cop/rspec/pending.rb b/lib/rubocop/cop/rspec/pending.rb index 7db0641f4..1405e5ca0 100644 --- a/lib/rubocop/cop/rspec/pending.rb +++ b/lib/rubocop/cop/rspec/pending.rb @@ -12,6 +12,12 @@ module RSpec # end # # describe MyClass do + # it "should be true", skip: true do + # expect(1).to eq(2) + # end + # end + # + # describe MyClass do # it "should be true" do # pending # end @@ -28,43 +34,31 @@ module RSpec class Pending < Cop MSG = 'Pending spec found.' - PENDING_EXAMPLES = Examples::PENDING + Examples::SKIPPED \ - + ExampleGroups::SKIPPED - SKIPPABLE_EXAMPLES = ExampleGroups::GROUPS + Examples::EXAMPLES - SKIPPABLE_SELECTORS = SKIPPABLE_EXAMPLES.node_pattern_union + PENDING = Examples::PENDING + Examples::SKIPPED + ExampleGroups::SKIPPED + SKIPPABLE = ExampleGroups::GROUPS + Examples::EXAMPLES - SKIP_SYMBOL = s(:sym, :skip) - PENDING_SYMBOL = s(:sym, :pending) + def_node_matcher :skippable?, SKIPPABLE.send_pattern - def_node_matcher :metadata, <<-PATTERN - {(send #{RSPEC} #{SKIPPABLE_SELECTORS} ... (hash $...)) - (send #{RSPEC} #{SKIPPABLE_SELECTORS} $...)} + def_node_matcher :skipped_in_metadata?, <<-PATTERN + { + (send _ _ <#skip_or_pending? ...>) + (send _ _ ... (hash <(pair #skip_or_pending? true) ...>)) + } PATTERN - def_node_matcher :pending_block?, PENDING_EXAMPLES.send_pattern + def_node_matcher :skip_or_pending?, '{(sym :skip) (sym :pending)}' + def_node_matcher :pending_block?, PENDING.send_pattern def on_send(node) - return unless pending_block?(node) || skipped_from_metadata?(node) + return unless pending_block?(node) || skipped?(node) add_offense(node) end private - def skipped_from_metadata?(node) - (metadata(node) || []).any? { |n| skip_node?(n) } - end - - def skip_node?(node) - if node.respond_to?(:key) - skip_symbol?(node.key) && node.value.truthy_literal? - else - skip_symbol?(node) - end - end - - def skip_symbol?(symbol_node) - [SKIP_SYMBOL, PENDING_SYMBOL].include?(symbol_node) + def skipped?(node) + skippable?(node) && skipped_in_metadata?(node) end end end diff --git a/manual/cops_rspec.md b/manual/cops_rspec.md index 90d629274..3d06292dd 100644 --- a/manual/cops_rspec.md +++ b/manual/cops_rspec.md @@ -2257,6 +2257,12 @@ describe MyClass do it "should be true" end +describe MyClass do + it "should be true", skip: true do + expect(1).to eq(2) + end +end + describe MyClass do it "should be true" do pending diff --git a/rubocop-rspec.gemspec b/rubocop-rspec.gemspec index 57f40cd05..7090003ee 100644 --- a/rubocop-rspec.gemspec +++ b/rubocop-rspec.gemspec @@ -39,7 +39,7 @@ Gem::Specification.new do |spec| 'documentation_uri' => 'https://rubocop-rspec.readthedocs.io/' } - spec.add_runtime_dependency 'rubocop', '>= 0.60.0' + spec.add_runtime_dependency 'rubocop', '>= 0.68.1' spec.add_development_dependency 'rack' spec.add_development_dependency 'rake' diff --git a/spec/rubocop/cop/rspec/pending_spec.rb b/spec/rubocop/cop/rspec/pending_spec.rb index f5dfdcd05..11f254452 100644 --- a/spec/rubocop/cop/rspec/pending_spec.rb +++ b/spec/rubocop/cop/rspec/pending_spec.rb @@ -124,61 +124,61 @@ RUBY end - it 'does not flag describe' do + it 'ignores describe' do expect_no_offenses(<<-RUBY) describe 'test' do; end RUBY end - it 'does not flag example' do + it 'ignores example' do expect_no_offenses(<<-RUBY) example 'test' do; end RUBY end - it 'does not flag scenario' do + it 'ignores scenario' do expect_no_offenses(<<-RUBY) scenario 'test' do; end RUBY end - it 'does not flag specify' do + it 'ignores specify' do expect_no_offenses(<<-RUBY) - specify 'test' do; end + specify do; end RUBY end - it 'does not flag feature' do + it 'ignores feature' do expect_no_offenses(<<-RUBY) feature 'test' do; end RUBY end - it 'does not flag context' do + it 'ignores context' do expect_no_offenses(<<-RUBY) context 'test' do; end RUBY end - it 'does not flag it' do + it 'ignores it' do expect_no_offenses(<<-RUBY) it 'test' do; end RUBY end - it 'does not flag it with skip: false metadata' do + it 'ignores it with skip: false metadata' do expect_no_offenses(<<-RUBY) it 'test', skip: false do; end RUBY end - it 'does not flag example_group' do + it 'ignores example_group' do expect_no_offenses(<<-RUBY) example_group 'test' do; end RUBY end - it 'does not flag method called pending' do + it 'ignores method called pending' do expect_no_offenses(<<-RUBY) subject { Project.pending } RUBY