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 ).
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)
I used a very similar approach to the accepted answer, but in a Cucumber environment I was getting errors about RSpec.configure
not existing. Also, I wanted to call the matcher something besides all
so that I could use them both without conflicts. This is what I ended up with
# features/support/rspec_each.rb
module RSpecEach
def each(expected)
RSpec::Matchers::BuiltIn::All.new(expected)
end
end
World(RSpecEach) # extends the Cucumber World environment
Now I can do things like:
expect(page.all('#employees_by_dept td.counts')).to each(have_text('1'))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.