Devise – Test user timeout in feature/integration specs using Warden

Devise is an excellent framework for strapping authentication features onto your Rails app. One of the very handy modules that provides session timeout features is :timeoutable.

Being a responsible test-driven developer, you start writing tests to ensure your application behaves correctly when the User tries to perform an action that is not allowed after their session timed out. But how to simulate that 30 minutes have gone by? (default config.timeout_in = 30.minutes)

A brief search of the nets offers a few pointers to overriding the Devise User.timedout? method but that doesn’t really help our feature spec when ensuring that User was redirected to the Login page upon performing a session-protected action.

Here’s one solution:

Devise is built on top of Warden, so let’s see if we can’t leverage Warden’s test helpers to simulate our timed out user:

Include Warden::Test::Helpers to put Warden into test mode:

# settings_page_spec.rb

include Warden::Test::Helpers

or

# spec/rails_helper.rb

RSpec.configure do |config|
  ...
    config.include Warden::Test::Helpers, type: :feature
end

Modify the Rack proxy via Warden.on_next_request in order to simulate that the User has been timed out by Devise::SessionsController:

# settings_page_spec.rb

it 'does not allow updating password' do
  expect(current_path).to eq(user_settings_path(user))
  clink_link 'Manage Password'
    expect(page).to have_button('Update Password')
    Warden.on_next_request do |proxy|
      proxy.set_user(nil)
      click_button 'Update Password'
      expect(current_path).to eq(login_path)
    end
end

We now have a method of simulating timed out behavior that does not involve playing games with time elapsed.

updating to ActiveAdmin 0.6.0 and Devise 2.2.3

I decided to upgrade from ActiveAdmin 0.5.1 to 0.6.0 because the configuration syntax for panels, columns, etc. seemed to have been streamlined quite a bit.  Looked cool, right?

Well, this turned to take way longer than it should.  Here’s what you need to do:

After running ‘bundle update’ to get the latest activeadmin gem 0.6.0, I took a look at the “Upgrading” section of the README at https://github.com/gregbell/active_admin

Sure enough, this

$> rails generate active_admin:assets

turned out to be a good thing.  But it wasn’t enough.

Right away I noticed that Devise had been upgraded to 2.2.3 from 2.1.2.  I figured I should probably check out their upgrade steps.  You can find those here: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.2

My specs were still failing with

uninitialized constant Admin::DashboardController

but the AA Readme recommendation to ensure that app/admin/dashboards.rb looked like the default turned out to be a red-herring.

I noticed that a fresh ‘rails generate active_admin:install’ wanted to drop a new app/admin/dashboard.rb file.  This new config file had all the jazzy new configuration syntax, so after copying over my section configs from the dashboards.rb to dashboard.rb, renaming ‘section’ to ‘panel’, and removing the dashboards.rb file, I fired up my specs again.  My newly styled dashboard looked great but there was still a problem: seems that my root ‘/’ path was no longer pointing at a valid controller.  Say huh?

I could see in ‘rake routes’ that I had two routes for ‘/’ – one from my manual route and a mystery one that looked like the commented out root_to configuration in config/initializers/active_admin.rb.  Turns out some other folks had just encountered this: https://github.com/gregbell/active_admin/issues/2049

Following the advice there to move my manual root route up above ActiveAdmin in routes.rb did indeed get me back in shape.  Looking forward to AA 0.6.1…