Back to Repositories

Testing Session Timeout Implementation in Devise Authentication

This test suite validates the Timeoutable module functionality in Devise, focusing on session timeout behavior and configuration. The tests ensure proper handling of timeout intervals, custom timeout methods, and integration with Devise’s configuration system.

Test Coverage Overview

The test suite provides comprehensive coverage of the Timeoutable module’s core functionality:

  • Basic timeout validation for standard intervals
  • Custom timeout_in method implementations
  • Nil parameter handling
  • Devise configuration fallbacks
  • Integration with rememberable feature

Implementation Analysis

The testing approach utilizes ActiveSupport::TestCase with focused unit tests that validate discrete timeout scenarios. The implementation employs Ruby’s time manipulation capabilities and Devise’s swap configuration pattern for temporary config modifications.

Key patterns include instance_eval for dynamic method definition and explicit time interval testing.

Technical Details

Testing tools and configuration:

  • Minitest framework
  • ActiveSupport::TestCase as the base test class
  • Devise’s test helper integration
  • Time manipulation using Rails’ time helpers
  • Custom user factory methods

Best Practices Demonstrated

The test suite exemplifies several testing best practices:

  • Isolated test cases with clear, descriptive names
  • Comprehensive edge case coverage
  • Proper setup and teardown using Devise’s swap mechanism
  • Consistent assertion patterns
  • Effective testing of both positive and negative scenarios

heartcombo/devise

test/models/timeoutable_test.rb

            
# frozen_string_literal: true

require 'test_helper'

class TimeoutableTest < ActiveSupport::TestCase

  test 'should be expired' do
    assert new_user.timedout?(31.minutes.ago)
  end

  test 'should not be expired' do
    assert_not new_user.timedout?(29.minutes.ago)
  end

  test 'should not be expired when params is nil' do
    assert_not new_user.timedout?(nil)
  end

  test 'should use timeout_in method' do
    user = new_user
    user.instance_eval { def timeout_in; 10.minutes end }

    assert user.timedout?(12.minutes.ago)
    assert_not user.timedout?(8.minutes.ago)
  end

  test 'should not be expired when timeout_in method returns nil' do
    user = new_user
    user.instance_eval { def timeout_in; nil end }
    assert_not user.timedout?(10.hours.ago)
  end

  test 'fallback to Devise config option' do
    swap Devise, timeout_in: 1.minute do
      user = new_user
      assert user.timedout?(2.minutes.ago)
      assert_not user.timedout?(30.seconds.ago)

      Devise.timeout_in = 5.minutes
      assert_not user.timedout?(2.minutes.ago)
      assert user.timedout?(6.minutes.ago)
    end
  end

  test 'required_fields should contain the fields that Devise uses' do
    assert_equal [], Devise::Models::Timeoutable.required_fields(User)
  end

  test 'should not raise error if remember_created_at is not empty and rememberable is disabled' do
    user = create_admin(remember_created_at: Time.current)
    assert user.timedout?(31.minutes.ago)
  end
end