Testing views that use CanCan and Devise with RSpec

farnoy picture farnoy · Feb 16, 2011 · Viewed 7.8k times · Source

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.

Answer

zetetic picture zetetic · Feb 16, 2011

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