Ruby on Rails Pundit's current_user is nil in integration test
Asked Answered
O

1

8

I'm using the gems pundit and devise. I have a delete link that only shows up if you are an admin. I have an integration test that I would like to verify that the delete link only shows up for admins.

test 'comment delete link shows when it should' do
  log_in_as @admin
  get movie_path(@movie)
  assert_select 'a[href=?]', movie_comment_path(comments(:one), @movie.id)
end

My test_helper.rb looks like this:

...
class ActiveSupport::TestCase
  ...
  def log_in_as(user, options = {})
    password = options[:password] || 'password'
    if integration_test?
      post user_session_path, 'user[email]' => user.email, 'user[password]' => user.password
    else
      Devise::TestHelpers.sign_in user
    end
  end

  private

    # Returns true inside an integration test.
    def integration_test?
      defined?(post_via_redirect)
    end

end

The response.body looks all right, but indeed there is no delete link. There is one when I run the development server and visit the page myself. I've narrowed this down to the current_user that pundit uses in the policies is being passed in with a value of nil. This is my comment_policy.rb:

class CommentPolicy
  attr_reader :current_user, :comment

  def initialize(current_user, model)
    @current_user = current_user
    @comment      = model
  end

  def create?
    if @current_user
      @current_user.member? or @current_user.content_creator? or @current_user.moderator? or @current_user.admin?
    end
  end

  def destroy?
    if @current_user
      @current_user == @comment.user or @current_user.moderator? or @current_user.admin?
    end
  end

end

As a closing remark, I've heard that Rails 5 has opted for integration tests instead of controller tests as we know them from Rails 4 for the default type of tests to be generated for our controllers. If this is the case, devise would be a heck of a lot more useful out of the box when using Rails 5 if the sign_in/sign_out helpers that work in controller tests were made to work in integration tests as well. But would I still have this issue of pundit not knowing what current_user is? I'm assuming this all works fine in controller tests because the current_user is scoped to controllers? Any and all light shed on this topic is much appreciated, but I would really like to figure out how to get integration tests to work with this setup because I have about a billion I want to write right now.

Oza answered 15/3, 2016 at 1:39 Comment(0)
P
2

Not that it totally matters, but does it need to be using current_user in the policy or can it just use user in the policy. By this I mean according to the elabs/pundit README on Github I would just use @user and user everywhere instead of current_user. Read the README if I confused you.

Additionally the nil for current_user typically occurs when you don't have a valid CSRF token for your request. When you do this on the website manually by going to localhost:3000 or w/e you are first performing a get on the login path before doing the post on the login path with your credentials. In your integration test I don't seem to see where you are performing that get in order to get the CSRF for your session.

Hope this helps!!!

Pampa answered 19/4, 2017 at 16:15 Comment(1)
thank you a lot, CSRF is a root issue for me, now I at least know what to fix :) Though my issue wasn't related to tests, just an error that happens from time to time on actions which usually works well.Candescent

© 2022 - 2024 — McMap. All rights reserved.