I have followed an example in the book Everyday Rails Testing with RSpec to create a custom RSpec matcher for redirecting to the login page (requires_login matcher). The code to this matcher can be seen below:
RSpec::Matchers.define :require_login do
match do |actual|
redirect_to Rails.application.routes.url_helpers.login_path
end
failure_message_for_should do |actual|
"expected to require login to access the method"
end
failure_message_for_should_not do |actual|
"expected not to require login to access method"
end
description do
"redirect to the login form"
end
end
This matcher is then called in the example below:
describe "GET #edit" do
it "requires login" do
user = FactoryGirl.create(:user)
get :edit, id: user
expect(response).to require_login
end
end # End GET #edit
For some reason the above test validates while the following does not (even though it too checks for a redirect to the login path):
describe "GET #edit" do
it "requires login" do
user = FactoryGirl.create(:user)
get :edit, id: user
expect(response).to redirect_to login_path
end
end # End GET #edit
I have looked over my code numerous times as well as the example in the book mentioned above and can't find any errors. Any insight into how to correctly achieve this matcher would be greatly appreciated. Also I am using Ruby 2.0.0, Rails 3.2.13, and RSpec-Rails 2.13.1.
Solution (thanks to Frederick Cheung's advice)
RSpec::Matchers.define :require_login do |attribute|
match do |actual|
expect(attribute).to redirect_to Rails.application.routes.url_helpers.login_path
end
failure_message_for_should do |actual|
"expected to require login to access the method"
end
failure_message_for_should_not do |actual|
"expected not to require login to access method"
end
description do
"redirect to the login form"
end
end
Your match block needs to return whether the matched matched, but at the moment you are returning something that is always truthy.
You probably want to take a similar approach to the redirect_to matcher which calls the rails provided assert_redirected_to
and returns true/false depending on whether ActiveSupport::TestCase::Assertion
is raised or not