Cannot test with rspec controller POST create action( devise and cancan)

Dimitris picture Dimitris · Jan 3, 2011 · Viewed 18.2k times · Source

I am having difficulty getting a rspec test for a controller to pass. I would like to test that the POST create action works. I am using rails (3.0.3), cancan (1.4.1), devise (1.1.5), rspec (2.3.0)

The model is dead simple

class Account < ActiveRecord::Base
  attr_accessible :name 
end

The controller is standard as well (straight out of scaffolding)

class AccountsController < ApplicationController
  before_filter :authenticate_user!, :except => [:show, :index]
  load_and_authorize_resource
  ...

  def create
    @account = Account.new(params[:account])

    respond_to do |format|
      if @account.save
        format.html { redirect_to(@account, :notice => 'Account was successfully created.') }
        format.xml  { render :xml => @account, :status => :created, :location => @account }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @account.errors, :status => :unprocessable_entity }
      end
    end
  end

and the rspec test I would like to pass is (excuse the title, perhaps not the most appropriate one)

 it "should call create on account when POST create is called" do
   @user = Factory.create(:user)
   @user.admin = true
   @user.save

   sign_in @user #this is an admin
   post :create, :account => {"name" => "Jimmy Johnes"}
   response.should be_success
   sign_out @user

 end

Yet all I get is

AccountsController get index should call create on account when POST create is called
 Failure/Error: response.should be_success
 expected success? to return true, got false
 # ./spec/controllers/accounts_controller_spec.rb:46

Other actions can be tested and do pass (i.e. GET new)

here is the test for GET new

it "should allow logged in admin to call new on account controller" do
  @user = Factory.create(:user)
  @user.admin=true
  @user.save

  sign_in @user #this is an admin
  get :new
  response.should be_success
  sign_out @user
end

and for completion here is the ability file

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new
    if user.admin?
      can :manage, :all
    else
      can :read, :all
    end
  end
end

Any ideas? My guess is that I am using the wrong rspec expectation, since the code does work (it is just that the test does not perform as desired!)

Answer

zetetic picture zetetic · Jan 3, 2011

response.should be_success returns true if the response code is in the range 200-299. But the create action redirects, so the response code gets set to 302, thus the failure.

You can test this by using response.should redirect_to. Check the output of the standard RSpec controller generator for an example, which might look like this:

  it "redirects to the created account" do
    Account.stub(:new) { mock_account(:save => true) }
    post :create, :account => {}
    response.should redirect_to(account_url(mock_account))
  end