Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error when using RSpec's `all` matcher with Capybara's `have_css` matcher

I'm just getting started with feature specs using RSpec (and Capybara). I'm testing my ActiveAdmin dashboard and I want to check that all panels have an orders table as shown in this snippet:

feature 'admin dashboard', type: :feature do
  def panels
    page.all('.column .panel')
  end

  describe 'all panels' do
    it 'have an orders table' do
      expect(panels).to all(have_css('table.orders tbody'))
    end
  end
end

I've used the all matcher a lot in my unit tests but it doesn't appear to work when wrapping Capybara's have_css matcher because I'm getting the following error:

Failure/Error: expect(panels).to all(have_css('table.orders tbody'))
TypeError:
  no implicit conversion of Capybara::RackTest::CSSHandlers into String

Am I correct in my assumption that RSpec's built-in all matcher should work with other matchers as well?

Note: I'm using describe and it instead of feature and scenario in this instance because I'm testing output rather than user interaction scenarios (see my other question).

like image 721
tristanm Avatar asked Sep 17 '14 23:09

tristanm


1 Answers

Unfortunately there is a conflict between RSpec's all and Capybara's all see Capybara Issue 1396. The all that you are calling is actually Capybara's all.

Solution 1 - Call BuiltIn::All Directly

The quickest solution would be to call RSpec's all method directly (or at least that code that it executes.

The expectation will work if you use RSpec::Matchers::BuiltIn::All.new instead of all:

expect(panels).to RSpec::Matchers::BuiltIn::All.new(have_css('table.orders tbody'))

Solution 2 - Redefine all

Calling the BuiltIn:All directly does not read nicely so might get annoying if used often. An alternative would be to re-define the all method to be RSpec's all method. To do this, add the module and configuration:

module FixAll
  def all(expected)
    RSpec::Matchers::BuiltIn::All.new(expected)
  end
end

RSpec.configure do |c|
  c.include FixAll
end

With the change, the all in the following line will behave like RSpec's all method.

expect(panels).to all(have_css('table.orders tbody'))

Note that if you want to use Capybara's all method, you would now always need to call it using the session (ie page):

# This will work because "page.all" is used
expect(page.all('table').length).to eq(2)

# This will throw an exception since "all" is used
expect(all('table').length).to eq(2)
like image 120
Justin Ko Avatar answered Oct 17 '22 22:10

Justin Ko