Testing authorization using RSpec parametrized shared examples
I have a rails app, that uses Devise for authentication and CanCan for authorization. There is a group of controllers in my application, that should be accessible by administrators only. I was thinking about a DRY way to test these resources and their accessibility by administrators only (using request specs with RSpec and Capybara).
The idea is to have shared examples, which try to visit resource url as unauthenicated user, authenicated non-privileged user and administrator, and check if desired resource was loaded or not. I will show, how I used RSpec’s shared examples (with resource url as parameter) for this.
Create shared example group in request_shared_examples.rb
file in spec/support
directory:
shared_examples "accessible by admin" do |url|
let(:url_path) { send(url) }
context "unauthenticated" do
it "redirects to root page with error" do
visit url_path
current_path.should == root_path
page.should have_selector(".alert-error")
end
end
context "for unauthorized user" do
it "redirects to root page with error" do
login_user(admin: false)
visit url_path
current_path.should == root_path
page.should have_selector(".alert-error")
end
end
context "for authorized user" do
it "displays page without errors" do
login_user(admin: true)
visit url_path
current_path.should == url_path
page.should_not have_selector(".alert-error")
end
end
end
Include these examples in your specs with it_should_behave_like
method:
describe "Items", :type => :request do
it_should_behave_like("accessible by admin", :admin_items_path)
# other examples
end
describe "Categories", :type => :request do
it_should_behave_like("accessible by admin", :admin_categories_path)
# other examples
end
NOTE: I’m passing url helpers’ names as symbols and evaluate them in shared example group (with let
and send
), because they can’t be evaluated in ExampleGroup context.