Rails provide us with useful test helpers to ActionMailer which helps to easily iterate our design, test if our code queues the right email and our email contains the right content.
Getting Started
After creating a rails app we can generate a new Mailer in our app.
rails generate mailer NotificationMailer
With the above command we generate a mailer named NotificationMailer
, this creates:-
- A class
NotificationMailer
inapp/mailers
directory. - A class
NotificationMailerTest
intest/mailers/notification_mailer_test.rb
- A preview class
NotificationMailerPreview
intest/mailer/preview/notificaton_mailer_preview.rb
- A view directory
notification_mailer
inapp/views
Mailer Logic
We are ready to create our first email. To create an email that is sent when users sign up in your application head to NotificationMailer
in app/mailer
class NotificationMailer < ApplicationMailer
default from: 'info@gathuku.tech'
def welcome(user)
@user = user
mail(to: @user.email, subject: 'Welcome to my App')
end
end
We have defined a welcome method that sends a welcome email. The method accepts the user object as the argument.
Note we have defined the
default from
at the top of our class.
Mailer view
After writing our logic remember notification_mailer
directory that was created in our app/view
, head into the directory and create a file named welcome.erb.html
. The file will render HTML design for our email.
Note the naming convention. The name must match the name of our email method.
<!-- <!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
</head>
<body>
<h1>Thanks for signing,<%= @user.email %> </h1>
<p>Welcome to the app</p>
</body>
</html> -->
Mailer Preview
Remember the preview file that was created? Mailer preview enables us to preview our email design. This is helpful since we don't have to send the actual email to see our email design.
All we need is to define a method that implements our mailer. notification_mailer_preview.rb
class NotificationMailerPreview < ActionMailer::Preview
def welcome
user = User.first
NotificationMailer.welcome(user)
end
end
After this ensure your server is running and navigate to route http://localhost:3000/rails/mailers
. All your mailers and specific email methods will be listed. Click welcome
to view the welcome email design.
Testing
Your mailers class just like any other part of Rails application should be tested to ensure they are working properly.
Why should you test your mailers? below are some of the reasons.
- To ensure that emails are being processed (created and sent).
- To ensure that the email content is correct (subject, sender, body, etc).
- To ensure the right emails are being sent at the right times.
There are two aspects of testing mailers.
- Units tests
- Functional tests
Units tests
In unit tests, we run the mailer in isolation with tightly controlled inputs and compare the output to a known value (a fixture.)
In our NotificationMailer
we have welcome
action which is used to send a welcome email when users sign up. Below is the unit test.
# frozen_string_literal: true
require 'test_helper'
class NotificationMailerTest < ActionMailer::TestCase
def setup
@user = users(:one)
end
test 'welcome' do
email = NotificationMailer.welcome(@user)
assert_emails 1 do
email.deliver_later
end
assert_equal email.to, [@user.email]
assert_equal email.from, ['info@gathuku.tech']
assert_equal email.subject, 'Welcome to my App'
assert_match 'Thanks for signing', email.body.encoded
end
end
In the test above, we create the email and store the returned object in the email variable. We then ensure that it was sent (the first assert), then, in the second batch of assertions, we ensure that the email does indeed contain what we expect.
Conclusion
To understand more about mailers. The line ActionMailer::Base.delivery_method = :test
in config/environments/test.rb
sets the delivery method to test mode so that email will not be delivered (useful to avoid spamming your users while testing) but instead, it will be appended to an array (ActionMailer::Base.deliveries
)
You can clear the deliveries array with
ActionMailer::Base.deliveries.clear
Top comments (2)
Very good! You helped me a lot. Thanks Moses ;)
The parameters that the
assert_method
takes in are (expected, actual, [msg]) so that means it should be written:assert_equal 'Welcome to my App', email.subject
docs.ruby-lang.org/en/2.1.0/MiniTe...
I like how you added the bit about setting up the data before running the test.