From e4f5d41f5372d2848070e29a1490d7f5bd950355 Mon Sep 17 00:00:00 2001 From: Tim Rogers Date: Tue, 26 Sep 2017 15:29:40 +0100 Subject: [PATCH] Add cop for Capybara expectations set on `current_path` Setting expectations on `current_path` in our Capybara feature specs leads to flaky tests. Switching to using [Capybara's `have_current_path` matcher](http://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/RSpecMatchers#have_current_path-instance_method) helps since it uses Capybara's [waiting functionality](https://github.com/teamcapybara/capybara/blob/master/README.md#asynchronous-javascript-ajax-and-friends) that ensures that preceding actions (like `click_link`) have completed. This cop tells you not to use `expect(current_path).to match(/lol/)`, encouraging you to use the `have_current_path` matcher instead. --- lib/rubocop-rspec.rb | 1 + .../capybara/current_path_expectation.rb | 30 +++++++++++++++++++ .../capybara/current_path_expectation_spec.rb | 16 ++++++++++ 3 files changed, 47 insertions(+) create mode 100644 lib/rubocop/cop/rspec/capybara/current_path_expectation.rb create mode 100644 spec/rubocop/cop/rspec/capybara/current_path_expectation_spec.rb diff --git a/lib/rubocop-rspec.rb b/lib/rubocop-rspec.rb index f7a212d65..aa7fd69e1 100644 --- a/lib/rubocop-rspec.rb +++ b/lib/rubocop-rspec.rb @@ -29,6 +29,7 @@ require 'rubocop/cop/rspec/around_block' require 'rubocop/cop/rspec/be_eql' require 'rubocop/cop/rspec/before_after_all' +require 'rubocop/cop/rspec/capybara/current_path_expectation' require 'rubocop/cop/rspec/capybara/feature_methods' require 'rubocop/cop/rspec/describe_class' require 'rubocop/cop/rspec/describe_method' diff --git a/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb b/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb new file mode 100644 index 000000000..2b4bf9897 --- /dev/null +++ b/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb @@ -0,0 +1,30 @@ +module RuboCop + module Cop + module RSpec + module Capybara + # Checks for expectations set on `current_path`, where instead the + # `have_current_path` matcher (http://www.rubydoc.info/github/ + # teamcapybara/capybara/master/Capybara/RSpecMatchers#have_current_path- + # instance_method) should be used on `page`, since it uses Capybara's + # waiting functionality (https://github.com/teamcapybara/capybara/blob/ + # master/README.md#asynchronous-javascript-ajax-and-friends) which + # ensures that preceding actions (like `click_link`) have completed. + class CurrentPathExpectation < Cop + MSG = 'Do not set an RSpec expectation on `current_path` in ' \ + 'Capybara feature specs - instead, use the ' \ + '`have_current_path` matcher on `page`' + + def_node_matcher :expectation_set_on_current_path, <<-PATTERN + (send nil :expect (send nil :current_path)) + PATTERN + + def on_send(node) + expectation_set_on_current_path(node) do |match| + add_offense(node, :selector) + end + end + end + end + end + end +end \ No newline at end of file diff --git a/spec/rubocop/cop/rspec/capybara/current_path_expectation_spec.rb b/spec/rubocop/cop/rspec/capybara/current_path_expectation_spec.rb new file mode 100644 index 000000000..d60b3ffaf --- /dev/null +++ b/spec/rubocop/cop/rspec/capybara/current_path_expectation_spec.rb @@ -0,0 +1,16 @@ +RSpec.describe RuboCop::Cop::RSpec::Capybara::CurrentPathExpectation do + subject(:cop) { described_class.new } + + it 'flags violations for `expect(current_path)`' do + expect_offense(<<-RUBY) + expect(current_path).to eq("/callback") + ^^^^^^ Do not set an RSpec expectation on `current_path` in Capybara feature specs - instead, use the `have_current_path` matcher on `page` + RUBY + end + + it 'doesn\'t flag a violation for other expectations' do + expect_no_offenses(<<-RUBY) + expect(current_user).to eq(user) + RUBY + end +end