Define custom RSpec matcher
11 March 2022 (Updated 24 April 2022)
On this page
Example use case
Suppose you’re writing a feature test and want to assert that a given route requires authentication. More specifically, you want to test that on visiting a protected route, two things happen:
- The current path is the login path.
- An error message is displayed.
You can do this using the default Capybara matchers:
RSpec.describe 'Create quote', type: :feature do
it 'User must be signed in to access create quote page' do
visit new_quote_path
expect(page).to have_current_path new_user_session_path
expect(page).to have_text unauthenticated_message
end
end
That doesn’t read bad but this is a test that’ll probably be repeated several times so let’s try and make it more succint and expressive:
RSpec.describe 'Create quote', type: :feature do
it 'User must be signed in to access create quote page' do
expect(new_quote_path).to require_authentication
end
end
The custom matcher here is require_authentication
.
How to define the custom matcher
Create a file spec/support/custom_matchers.rb
, make sure this file from your rails_helper.rb
, and set its contents to:
RSpec::Matchers.define :require_authentication do
match do |path|
visit path
page.has_current_path?(new_user_session_path) &&
page.has_text?(unauthenticated_message)
end
failure_message do |path|
<<~MSG
expected that visiting #{path} would redirect the user to#{' '}
#{new_user_session_path} and show the message \"#{unauthenticated_message}\"
MSG
end
end
This matcher can also be rewritten to take a block instead. See this post.
Sources
Tagged:
Rails testing
Thanks for your comment 🙏. Once it's approved, it will appear here.
Leave a comment