Reputation: 1398
My problem with an RSpec test: I'm following Michael Hartl's Rails tutorial. We define an RSpec matcher have_error_message
that is working for me. I am trying to define a matcher to test the inverse called not_have_error_message
, which I invoke
it { should not_have_error_message }
.
I am doing this because I tried it { should_not have_error_message }
and got the error
Capybara::ExpectationNotMet: expected to find css "div.alert.alert-error" with text "Invalid" but there were no matches
I would like to know 1) if it is possible to accomplish this using should_not and have_error_message and 2) what I am doing wrong that is causing not_have_error_message to fail. Thanks!
Here's the code:
spec/features/authentication_pages_spec.rb (irrelevant part omitted)
describe "Authentication" do
subject { page }
describe "signin" do
...
describe "with invalid information" do
before { click_button "Sign in" }
it { should have_content('Sign in') }
it { should have_title('Sign in') }
it { should have_error_message('Invalid') }
describe "after visiting another page" do
before { click_link "Home" }
it { should_not have_selector('div.alert.alert-error') }
it { should not_have_error_message }
end
end
end
end
spec/support/utilities.rb
include ApplicationHelper
def valid_signin(user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
RSpec::Matchers.define :have_error_message do |message|
match do |page|
expect(page).to have_selector('div.alert.alert-error', text: message)
end
end
RSpec::Matchers.define :not_have_error_message do
match do |page|
expect(page).not_to have_selector('div.alert.alert-error')
end
end
And I'm getting the error:
1) Authentication signin with invalid information after visiting another page
Failure/Error: it { should not_have_error_message }
expected #<Capybara::Session> to not have error message
# ./spec/features/authentication_pages_spec.rb:44:in `block (5 levels) in <top (required)>'
You can see I also run the equivalent test:
it { should_not have_selector('div.alert.alert-error') }
directly above the failing test and it passes.
Upvotes: 0
Views: 728
Reputation: 46846
When defining the RSpec matchers, the block is meant to return true or false (see this wiki).
The way you have defined your matchers, you are actually making the assertion within an assertion. When the inner expectation fails, this raises an exception that causes the outer expectation to give unexpected results.
So that the custom matchers evaluate to true/false, use the has_selector?
and has_not_selector?
methods. Your custom matchers should be:
RSpec::Matchers.define :have_error_message do |message|
match do |page|
page.has_selector?('div.alert.alert-error', text: message)
end
end
RSpec::Matchers.define :not_have_error_message do
match do |page|
page.has_no_selector?('div.alert.alert-error')
end
end
Upvotes: 1