Skip to content

Can't set session in controller test http requests #25394

@murdoch

Description

@murdoch

Steps to reproduce

I generated a new rails 5.0.0.rc1 app along with a home controller and a sessions controller:

    # in routes.rb
    get '/login', to: 'sessions#new', as: 'login'
    root to: 'home#show'

    # sessions controller
    class SessionsController < ApplicationController 
      def new
        if session[:user_id]
          redirect_to root_url, notice: 'Already logged in'
        end
      end 
    end

Now the first thing I notice is that my auto generated test file inherits from ActionDispatch::IntegrationTest:

    # test/controllers/sessions_controller_test.rb
    class SessionsControllerTest < ActionDispatch::IntegrationTest
    end    

So lets try to write a test where we set the user_id session key so we can ensure that our logged in user is redirected to the root path when they visit the login page. According to the Edge Guide we're supposed to use named arguments with HTTP requests in tests now:

    # test/controllers/sessions_controller_test.rb
    class SessionsControllerTest < ActionDispatch::IntegrationTest
      test 'should redirect to root path if a logged in user visits the login page' do
        get login_url, session: { user_id: 42 }
        assert_redirected_to root_url, 'Did not redirect'
      end
    end    

This test fails because the redirect is not followed and we also see the following deprecation message:

DEPRECATION WARNING: ActionDispatch::IntegrationTest HTTP request methods will accept only
the following keyword arguments in future Rails versions:
params, headers, env, xhr

Examples:

get '/profile',
params: { id: 1 },
headers: { 'X-Extra-Header' => '123' },
env: { 'action_dispatch.custom' => 'custom' },
xhr: true

So rails is not letting us set the session in the way we are advised to in the Edge Guide.

It looks like the code that enables the use of a kw_arg named 'session' lives in ActionController::TestCase and in order to fix this issue I had to do the following:

1 - Change SessionsControllerTest to inherit from ActionControllerTestCase:

    class SessionsControllerTest < ActionController::TestCase

2 - Use symbolized action names instead of URL's with http verbs

    # changed from 
    get '/login', session: { user_id: 42 }

   # to
   get :new, session: { user_id: 42 }

It's worth pointing out that we can't even set session variables manually when inheriting from ActionDispatch::IntegrationTest i.e:

    test 'some test' do
      session[:user_id] = 42
      assert something
    end

NoMethodError: undefined method `session' for nil:NilClass

Expected behavior

I was expecting to be able to pass keyword arguments to HTTP verbs in my controller tests like so:

get '/some-url', session: { cart_id: 42 }

Actual behavior

Keyword arguments appear to be ignored unless you inherit from ActionController::TestCase

System configuration

Rails version:
5.0.0.rc1

Ruby version:
mri 2.3.0p0

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions