blog.robotex.de

Devise: Testing controllers and requests that need authentication with rspec2

Imagine you have been happily writing your controller test and then, you have to add authentication to your application using devise.

Assume you have a posts controller with following test:

require 'spec_helper'

describe PostsController do
  def mock_post(stubs={})
    @mock_post ||= mock_model(Post, stubs).as_null_object
  end

  describe "GET index" do
    it "assigns all posts as @posts" do
      Post.stub(:all) { [mock_post] }
      get :index
      assigns(:posts).should eq([mock_post])
    end
  end

  describe "GET show" do
    it "assigns the requested post as @post" do
      Post.stub(:find).with("37") { mock_post }
      get :show, :id => "37"
      assigns(:post).should be(mock_post)
    end
  end
end  

First, you'll have to add the Devise TestHelpers. Add a new file spec/support/devise.rb:

RSpec.configure do |config|
  config.include Devise::TestHelpers, :type => :controller
end

You'll need a factory for the admin. I use factory girl. Add the admin factory to Rails.root/spec/factories.rb:

Factory.define(:admin) do |admin|
  admin.email    "admin@example.com"
  admin.password "foobar"
end

Then you throw all your controller tests into a new describe block, that signins in your admin before each test:

describe PostsController do
  describe "as a signed in admin" do
    before(:each) do
      admin = Factory(:admin)
      sign_in admin
    end
    
    def mock_post(stubs={})
      @mock_post ||= mock_model(Post, stubs).as_null_object
    end

    describe "GET index" do
      it "assigns all posts as @posts" do
        Post.stub(:all) { [mock_post] }
        get :index
        assigns(:posts).should eq([mock_post])
      end
    end

    describe "GET show" do
      it "assigns the requested post as @post" do
        Post.stub(:find).with("37") { mock_post }
        get :show, :id => "37"
        assigns(:post).should be(mock_post)
      end
    end
  end
end

Customize the request specs. Before:

require 'spec_helper'

describe "NewsItems" do
  describe "GET /news_items" do
    it "works! (now write some real specs)" do
      # Run the generator again with the --webrat flag if you want to use webrat methods/matchers
      get news_items_path
      response.status.should be(200)
    end
  end
end

and with devise integration:

require 'spec_helper'

describe "NewsItems" do
  context "as logged in admin" do
    before(:each) do
      admin = Factory(:admin)
      get new_admin_session_path
      fill_in :email,    :with => admin.email
      fill_in :password, :with => admin.password
      click_button
    end
    
    describe "GET /news_items" do
      it "works! (now write some real specs)" do
        # Run the generator again with the --webrat flag if you want to use webrat methods/matchers
        get news_items_path
        response.status.should be(200)
      end
    end
  end
end

Back