Back to Repositories

Testing Unlock Instructions Email Implementation in Devise

This test suite validates the unlock instructions email functionality in Devise’s authentication system, focusing on mailer configuration, content verification, and token handling. The tests ensure proper email delivery and content formatting for account unlocking mechanisms.

Test Coverage Overview

The test suite provides comprehensive coverage of unlock instruction email functionality:

  • Email delivery verification
  • Content type validation
  • Recipient and sender configuration
  • Custom mailer support
  • Internationalization (I18n) integration
  • Unlock token generation and URL validation

Implementation Analysis

The testing approach utilizes ActionMailer::TestCase for mailer testing, implementing setup and teardown methods to ensure consistent test environments. The suite employs factory patterns for user creation and implements lazy loading through memoized instance variables (@mail, @user).

Tests verify both basic email attributes and complex functionality like custom mailer configurations and I18n integration.

Technical Details

Key technical components include:

  • ActionMailer::TestCase framework
  • Devise mailer configuration
  • Token generator for unlock URLs
  • I18n translation system
  • HTML content type validation
  • URL generation with host/port configuration

Best Practices Demonstrated

The test suite exemplifies several testing best practices:

  • Proper test isolation through setup/teardown methods
  • Comprehensive edge case coverage
  • Efficient resource management with memoization
  • Clear test naming conventions
  • Modular test organization
  • Thorough validation of email components

heartcombo/devise

test/mailers/unlock_instructions_test.rb

            
# frozen_string_literal: true

require 'test_helper'

class UnlockInstructionsTest < ActionMailer::TestCase

  def setup
    setup_mailer
    Devise.mailer = 'Devise::Mailer'
    Devise.mailer_sender = '[email protected]'
  end

  def teardown
    Devise.mailer = 'Devise::Mailer'
    Devise.mailer_sender = '[email protected]'
  end

  def user
    @user ||= begin
      user = create_user
      user.lock_access!
      user
    end
  end

  def mail
    @mail ||= begin
      user
      ActionMailer::Base.deliveries.last
    end
  end

  test 'email sent after locking the user' do
    assert_not_nil mail
  end

  test 'content type should be set to html' do
    assert_includes mail.content_type, 'text/html'
  end

  test 'send unlock instructions to the user email' do
    assert_equal [user.email], mail.to
  end

  test 'set up sender from configuration' do
    assert_equal ['[email protected]'], mail.from
  end

  test 'set up sender from custom mailer defaults' do
    Devise.mailer = 'Users::Mailer'
    assert_equal ['[email protected]'], mail.from
  end

  test 'set up sender from custom mailer defaults with proc' do
    Devise.mailer = 'Users::FromProcMailer'
    assert_equal ['[email protected]'], mail.from
  end

  test 'custom mailer renders parent mailer template' do
    Devise.mailer = 'Users::Mailer'
    assert_present mail.body.encoded
  end

  test 'set up reply to as copy from sender' do
    assert_equal ['[email protected]'], mail.reply_to
  end

  test 'set up subject from I18n' do
    store_translations :en, devise: { mailer: { unlock_instructions:  { subject: 'Yo unlock instructions' } } } do
      assert_equal 'Yo unlock instructions', mail.subject
    end
  end

  test 'subject namespaced by model' do
    store_translations :en, devise: { mailer: { unlock_instructions: { user_subject: 'User Unlock Instructions' } } } do
      assert_equal 'User Unlock Instructions', mail.subject
    end
  end

  test 'body should have user info' do
    assert_match user.email, mail.body.encoded
  end

  test 'body should have link to unlock the account' do
    host, port = ActionMailer::Base.default_url_options.values_at :host, :port

    if mail.body.encoded =~ %r{<a href=\"http://#{host}:#{port}/users/unlock\?unlock_token=([^"]+)">}
      assert_equal user.unlock_token, Devise.token_generator.digest(user.class, :unlock_token, $1)
    else
      flunk "expected unlock url regex to match"
    end
  end
end