Parameterized Mailers

22 views
Skip to first unread message
Message has been deleted

gleb....@myjobglasses.com

unread,
Feb 12, 2019, 10:18:44 AM2/12/19
to rspec
Hello,

Parameterized Mailers were added in Rails 5.1. I would like to use them in my project, however I have not been able to test them with RSpec.
Minitest provides a matcher assert_enqueued_email_with (documented here). Is there a matcher in RSpec that provides similar functionality?

Cheers,
Gleb

Jon Rowe

unread,
Feb 13, 2019, 12:14:30 PM2/13/19
to rs...@googlegroups.com
Hi Gleb

What are you unable to test about them? ParameterizedMailers should act as normal Mailers under test (as we don’t test how they’re created, only the result) and you can see a basic “MailerSpec” here https://relishapp.com/rspec/rspec-rails/v/3-8/docs/mailer-specs.

We do also have Job specs, https://relishapp.com/rspec/rspec-rails/v/3-8/docs/job-specs/job-spec, and coming soon (unreleased but you could use by pointing rspec-rails at GitHub) we’ll have specific helpers for asserting mailer jobs are queued (e.g. have_enqueued) 

Is that of any help?

Jon Rowe
---------------------------

On 12 February 2019 at 15:13, gleb....@myjobglasses.com wrote:
Hello,

Parameterized Mailers were added in Rails 5.1. I would like to use them in my project, but I have not being able to write tests for them using RSpec.
Minitest provides the test helper method assert_enqueued_email_with (documented here). Is there an equivalent in RSpec?

Thanks,
Gleb

gleb....@myjobglasses.com

unread,
Feb 14, 2019, 8:36:49 AM2/14/19
to rspec
 Hi Jon,

Before refactoring to use ParameterizedMailers, I had the following code:

AppointmentMailer.reminder(@appointment, @user).deliver_later

with the corresponding test:

expect(AppointmentMailer).to(receive(:reminder).with(appointment, user)).and_return(appointment_reminder_email)

Once I switched to ParameterizedMailers, my code changed to:

AppointmentMailer.with(appointment: @appointment, recipient: @user).reminder.deliver_later

With this change, the Mailer is invoked with the .with() method, which means the test will not trigger the receive(:reminder). I tried doing something like this:

expect(AppointmentMailer).to(receive(:with).with(appointment: appointment, recipient: user)).and_return(parameterized_appointment_mailer)

However this didn't work as intended because the 
 .with() method returns a new Parameterized::Mailer. I wish to write a test that checks that the parameters were passed to the AppointmentMailer and that the reminder method was called and returned the correct object ( in this example that would be the appointment_reminder_email).

The minitest assert method is useful because it accepts the parameters as arguments:

def test_parameterized_email
  assert_enqueued_email_with
AppointmentMailer, :welcome,
    args
: {appointment: appointment, recipient: user} do
   
AppointmentMailer.with(appointment: appointment, recipient: user).reminder.deliver_later
 
end
end


Does this clarify my use-case?
If there is a better way to test my Mailers in general, please let me know!

Best,
Gleb

Jon Rowe

unread,
Feb 14, 2019, 8:51:34 AM2/14/19
to rs...@googlegroups.com
Hi Gleb

Your original code used partial doubles, which of course are fragile to this kind of change. You should be able to work with them if you want, but the assertion you mention is exactly what the new `have_enqueued_mail` does, https://github.com/rspec/rspec-rails/blob/master/lib/rspec/rails/matchers/have_enqueued_mail.rb which is probably a better way to test.

Cheers
Jon Rowe
---------------------------
Reply all
Reply to author
Forward
0 new messages