Testing views that use CanCan and Devise with RSpec

The 'before :each' code posted by zetetic doesn't work for me. My views bork on the 'can?' method because 'current_ability' in the view returns nil. I fixed it by using this 'before :each' code instead:

@ability = Ability.new(user)
assign(:current_ability, @ability)
controller.stub(:current_user, user)
view.stub(:current_user, user)

The above code simulates a login.


This is described in the CanCan docs for controller testing, and can also be modified to apply to view specs. Here's one way to do it:

require 'spec_helper'

describe "mymodel/index.html.erb" do
  before(:each) do
    assign(:my_model,mock_model(MyModel))
    @ability = Object.new
    @ability.extend(CanCan::Ability)
    controller.stub(:current_ability) { @ability }
  end

  context "authorized user" do
    it "can see the table header" do
      @ability.can :destroy, MyModel
      render
      rendered.should have_selector('th:contains("Options")')
    end
  end

  context "unauthorized user" do
    it "cannot see the table header" do
      render
      rendered.should_not have_selector('th:contains("Options")')
    end
  end
end

In your spec_helper:

config.include Devise::TestHelpers, :type => :view

In your view spec:

controller.stub!(current_user: [some user])
view.stub!(current_user: [some user])

For new RSpec 3.0 syntax

  before(:each) do
    assign(:my_model,mock_model(MyModel))
    @ability = Object.new.extend(CanCan::Ability)
    allow(controller).to receive(:current_ability).and_return(@ability)
  end