Back to Repositories

Testing Email Confirmation Instructions in Devise Authentication System

This test suite validates the email confirmation functionality in Devise’s mailer system, focusing on confirmation instructions delivery and content verification. The tests ensure proper email configuration, content formatting, and localization support for user account confirmation flows.

Test Coverage Overview

The test suite provides comprehensive coverage of Devise’s confirmation email system, validating both core functionality and edge cases.

  • Email delivery verification and content type validation
  • Sender configuration and reply-to header handling
  • Localization support for email subjects
  • Confirmation token generation and URL validation
  • Custom mailer implementation testing

Implementation Analysis

The testing approach utilizes ActionMailer::TestCase for email testing, implementing setup and teardown methods to ensure consistent test environments. The suite employs Ruby’s minitest framework with assertion-based testing patterns, leveraging Devise’s mailer configuration flexibility.

  • Modular test structure with setup/teardown hooks
  • Custom mailer class testing
  • I18n integration testing
  • URL and token validation patterns

Technical Details

  • Testing Framework: Minitest
  • Mail Testing: ActionMailer::TestCase
  • Configuration: Devise.mailer and Devise.mailer_sender
  • Helpers: Custom user creation and mail setup methods
  • I18n Integration: store_translations helper
  • URL Validation: Regex pattern matching

Best Practices Demonstrated

The test suite exemplifies robust testing practices for email functionality in Rails applications. It demonstrates proper isolation of test cases, comprehensive assertion coverage, and effective use of helper methods.

  • Isolated test setup and teardown
  • Thorough content validation
  • Configuration testing patterns
  • Localization testing strategies
  • Clear test case organization

heartcombo/devise

test/mailers/confirmation_instructions_test.rb

            
# frozen_string_literal: true

require 'test_helper'

class ConfirmationInstructionsTest < 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 ||= create_user
  end

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

  test 'email sent after creating 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 confirmation instructions to the user email' do
    mail
    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 reply to as different if set in defaults' do
    Devise.mailer = 'Users::ReplyToMailer'
    assert_equal ['[email protected]'], mail.from
    assert_equal ['[email protected]'], mail.reply_to
  end

  test 'set up subject from I18n' do
    store_translations :en, devise: { mailer: { confirmation_instructions: { subject: 'Account Confirmation' } } } do
      assert_equal 'Account Confirmation', mail.subject
    end
  end

  test 'subject namespaced by model' do
    store_translations :en, devise: { mailer: { confirmation_instructions: { user_subject: 'User Account Confirmation' } } } do
      assert_equal 'User Account Confirmation', 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 confirm 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/confirmation\?confirmation_token=([^"]+)">}
      assert_equal user.confirmation_token, $1
    else
      flunk "expected confirmation url regex to match"
    end
  end

  test 'renders a scoped if scoped_views is set to true' do
    swap Devise, scoped_views: true do
      assert_equal user.email, mail.body.decoded
    end
  end

  test 'renders a scoped if scoped_views is set in the mailer class' do
    begin
      Devise::Mailer.scoped_views = true
      assert_equal user.email, mail.body.decoded
    ensure
      Devise::Mailer.send :remove_instance_variable, :@scoped_views
    end
  end

  test 'mailer sender accepts a proc' do
    swap Devise, mailer_sender: proc { "[email protected]" } do
      assert_equal ['[email protected]'], mail.from
    end
  end
end