Skip to content

Loading…

current_user, or current_something_else in RSpec view specs? #598

Open
JohnSmall opened this Issue · 18 comments

9 participants

@JohnSmall

In RSpec view specs 'can?' in the view is calling the default 'current_user', which fails because I'm not using current_user, but current_something_else.

I can see how to change the default behaviour of current_ability so that it uses something other than current_user, in my case current_member. This works just fine everywhere, except in Rspec view specs, where 'can?' is somehow calling for current_user, which doesn't exist and breaks my tests.

I'm using Devise 2.0.4, Rails 3.2.1, Rspec 2.8.0 and CanCan 1.6.7. It's proving to be quite tricky to get the combination to work together. I've mostly worked through the issues, and this might even be the last one. The issue seems to be 'Where does RSpec define the controller it uses for testing views?'. I've copied the redefinition of current_ability from ApplicationController into a module that gets included into whatever it is that RSpec invokes when it runs view specs, but it's not working.

When testing views Rspec obviously doesn't use ApplicationController or any methods I've defined in it , the error I get is;- ActionView::Template::Error:
undefined local variable or method `current_user' for #ActionView::TestCase::TestController:0x00000002d8e710

So it looks like I've got to include the method re-definition of 'current_ability' into ActionView::TestCase::TestController. I could just monkey patch it in, but that feels extremely clunky. There must be an elegant way to handle this problem.

Any comments?

By the way, If you're looking for a new topic for RailsCasts, a series on the internals of RSpec and what it's doing behind the curtains would be useful. The baby steps that most blogs/instruction manuals give just aren't comprehensive enough.

Ta

John Small

@andhapp
Collaborator

You are trying to access a helper method defined in controller for your views specs. The way to go is to do something like this:

view.stub(:current_user) { User.new # return a user }

This establishes a separation of view and controllers. However, this doesn't do a full stack testing, so you need to ensure you have integration tests. Here's a link to the rspec documentation.

@andhapp andhapp closed this
@JohnSmall

Unfortunately that completely misses the point. The point being that I don't have a User model. Instead I have a Member model. Even though CanCan allows you to override the default model of 'User' it seems that there's one place in the code where it's hard coded to assume you're using a User model. That shows up when using RSpec to test the views.

I think I'll have to dive into the code, fix it myself, and send you a pull request.

@andhapp
Collaborator
@JohnSmall
@andhapp andhapp was assigned
@andhapp andhapp reopened this
@andhapp
Collaborator

Is it possible for you to create a dummy app with bare minimum feature that replicates this issue? I will pull it down and investigate this.

@JohnSmall
@andhapp
Collaborator

Okay. Thanks. I will create a test app and try and replicate the issue, if I get time.

@giangnguyennet

Me too having this issue at the moment.

Here's the RSpec error:

  1) projects/edit.html.haml should render edit form
     Failure/Error: render
     ActionView::Template::Error:
       undefined local variable or method `current_user' for #<ActionView::TestCase::TestController:0x0000012bb0c3f0>
     # ./app/views/projects/edit.html.haml:12:in `_app_views_projects_edit_html_haml__4467359789244170678_2184742920'
     # ./spec/views/projects/edit.html.haml_spec.rb:13:in `block (2 levels) in <top (required)>'

And projects/edit.html.haml content:

  1 #box
  2   %h2{:class=>"header"}
  3     = raw("#{t_default('edit_project')} &laquo;#{link_to_project(@project)}&raquo;")
  4     
  5   - unless !@project.ideation_processes.empty? && @project.ideation_processes.last.startable?
  6     %p.error
  7       = t_default('ideation_process_not_configured')
  8 
  9   #{t_default('state')}: 
 10   %strong #{@project.workflow_state}
 11 
 12   - if can? :set_states, @project
 13     #{t_default('set_state_to')}:
 14     %strong #{raw(show_transition_links @project)}
 15 
 16   = render :partial => 'form'
 17 
 18   //= render :partial => 'ideation_processes/index'

Any idea?

@andhapp
Collaborator

@ndgiang84: Hey, will you be able to create a dummy app that reproduces this issue and push it in a public repo somewhere and add the link to it in the comments.

@JohnSmall was meant to do it, but I guess he is quite busy.

Thanks.

@giangnguyennet

@andhapp thanks for your response I'll do so when I have time.

FYI, I'm using Authlogic 3.1.0 and Rails 3.1.3.

@djcp

If you stub the current_user method into the controller this will work fine

controller.stub(:current_user) { Account.new }
@luxflux

Any news here?

@rhazegh

Having a similar issue (CanCan 1.6.9, Devise 2.1.2, Rails 3.2.11).

Is there any workarounds for this issue?

@esti

I'm was having the same problem: the can? method being called in the view being tested was not aware of the current_user being stub in the test setup. I finally ended up stubbing the method both in the view and in the controller and now it works:

  before(:each) do
    ...
    user = User.new # or whatever
    view.stub!(:current_user).and_return(user)
    controller.stub!(:current_user).and_return(user)
  end
@rhazegh

I tried controller.stub!(:current_user).and_return(user) in the controller RSpec test but I am still getting CanCan::AccessDenied: You are not authorized to access this page.

When I access the controller with curl, it works perfectly and the authorization is enforced as intended.

EDIT:
Problem resolved. See bellow...

@rhazegh

I debugged the code and it turns out the factory that created the user was not assigning any roles to the user. I fixed the factory and now it works perfectly. I didn't even need to stub the current_user.

@fotanus

I'm also affected to this issue. My tests fails adding the following line in a partial named app/views/layouts/_navigation.html.haml, which is called directly from my layout app/views/layouts/application.html.haml:

- if can? :read, Job

I'm using STI to define roles in my models. Here is the factory for my admin:

FactoryGirl.define do
  factory :admin, parent: :user, class: :admin do
    type :admin
  end
end

Testing this view in my spec spec/views/layouts/_navigation.html.haml_spec.rb, I'm got the (minimized) following:

describe "my feature"
  before(:each) do
    admin = build(:admin)
    view.stub(:current_user).and_return(admin)
  end
  it "is a feature" do
    # Test
  end
end

With this code I've got

undefined local variable or method `current_user' for #<ActionView::TestCase::TestController:0x9fb15e0>

However, the test pass if I add this other stub right after the view stub:

controller.stub(:current_user).and_return(admin)

Full trace from the error:

   # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/cancan-1.6.10/lib/cancan/controller_additions.rb:357:in `current_ability'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/cancan-1.6.10/lib/cancan/controller_additions.rb:380:in `can?'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/abstract_controller/helpers.rb:53:in `can?'
     # ./app/views/layouts/_navigation.html.haml:5:in `_app_views_layouts__navigation_html_haml___562165619_96886850'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/template.rb:145:in `block in render'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-3.2.13/lib/active_support/notifications.rb:123:in `block in instrument'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-3.2.13/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-3.2.13/lib/active_support/notifications.rb:123:in `instrument'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/template.rb:143:in `render'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/renderer/template_renderer.rb:47:in `block (2 levels) in render_template'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/renderer/abstract_renderer.rb:38:in `block in instrument'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-3.2.13/lib/active_support/notifications.rb:123:in `block in instrument'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-3.2.13/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/activesupport-3.2.13/lib/active_support/notifications.rb:123:in `instrument'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/renderer/abstract_renderer.rb:38:in `instrument'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/renderer/template_renderer.rb:46:in `block in render_template'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/renderer/template_renderer.rb:54:in `render_with_layout'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/renderer/template_renderer.rb:45:in `render_template'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/renderer/template_renderer.rb:18:in `render'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/renderer/renderer.rb:36:in `render_template'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/renderer/renderer.rb:17:in `render'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/helpers/rendering_helper.rb:24:in `render'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/haml-4.0.3/lib/haml/helpers/action_view_mods.rb:12:in `render_with_haml'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/test_case.rb:170:in `render'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-3.2.13/lib/action_view/test_case.rb:115:in `render'
     # ./spec/views/layouts/_navigation.html.haml_spec.rb:18:in `block (3 levels) in <top (required)>'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example.rb:237:in `instance_eval'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example.rb:237:in `instance_eval'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:21:in `run'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:66:in `block in run'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:66:in `each'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:66:in `run'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:418:in `run_hook'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:334:in `run_before_each_hooks'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example.rb:300:in `run_before_each'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example.rb:113:in `block in run'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example.rb:254:in `with_around_each_hooks'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example.rb:111:in `run'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:390:in `block in run_examples'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:386:in `map'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:386:in `run_examples'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:371:in `run'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:372:in `block in run'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:372:in `map'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:372:in `run'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/command_line.rb:28:in `block (2 levels) in run'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/command_line.rb:28:in `map'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/command_line.rb:28:in `block in run'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/reporter.rb:34:in `report'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/command_line.rb:25:in `run'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/runner.rb:80:in `run'
     # /home/fotanus/.rvm/gems/ruby-2.0.0-p247/gems/rspec-core-2.13.1/lib/rspec/core/runner.rb:17:in `block in autorun'
@xhoy

Thanks for your submission! The ryanb/cancan repository has been inactive since Sep 06, 2013.
Since only Ryan himself has commit permissions, the CanCan project is on a standstill.

CanCan has many open issues, including missing support for Rails 4. To keep CanCan alive, an active fork exists at cancancommunity/cancancan. The new gem is cancancan. More info is available at #994.

If your pull request or issue is still applicable, it would be really appreciated if you resubmit it to CanCanCan.

We hope to see you on the other side!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.