Search code examples
ruby-on-railsrubyrspecdevisecancan

Testing views that use CanCan and Devise with RSpec


I was trying to test a simple index view, which has following code inside:

- if can? :destroy, MyModel
  %th Options

MyModelsController has following options (Inherited Resources + CanCan + Devise):

class MyModelsController < ApplicationController
  inherit_resources
  nested_belongs_to :mymodel
  before_filter :authenticate_user!
  load_and_authorize_resource :project
  load_and_authorize_resource :mymodel, :through => :project

When running specs, it crashes at the line - if can? :destroy, MyModel

Failure/Error: render
   ActionView::Template::Error:
      undefined method `authenticate' for nil:NilClass

There's no traceback, nothing to base on...

I thought that maybe I'm not authorized and signed when testing views, but Devise::TestHelpers should only be included in controller tests (and that's how I have it).

I was trying to override method can? in both Ability and the controller, but that gave no effect.


Solution

  • 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