Skip to content

Commit 22a0692

Browse files
tomrossi7Bryron-shinall
authored
Improvements to assert_enqueued_email_with (rails#45752)
* This is an attempt to make the assert_enqueued_email_with easier to implement. * Update actionmailer/test/test_helper_test.rb Fix spelling. * Documenting additional tests * Missing a closing "end" * Renaming tests for consistency * Updating name * Naming and documentation * Leaving original test unchanged * Fix test name, add new test * Add assert_enqueued_emails examples to Rails guide * Add example to test_helper * Tweaking the Rails guide (#3) * Updating Rails guide for consistency. Co-authored-by: Bry <[email protected]> Co-authored-by: Ron Shinall <[email protected]>
1 parent 8994f09 commit 22a0692

File tree

3 files changed

+164
-20
lines changed

3 files changed

+164
-20
lines changed

actionmailer/lib/action_mailer/test_helper.rb

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,18 +94,43 @@ def assert_enqueued_emails(number, &block)
9494
end
9595

9696
# Asserts that a specific email has been enqueued, optionally
97-
# matching arguments.
97+
# matching arguments and/or params.
9898
#
9999
# def test_email
100100
# ContactMailer.welcome.deliver_later
101101
# assert_enqueued_email_with ContactMailer, :welcome
102102
# end
103103
#
104+
# def test_email_with_parameters
105+
# ContactMailer.with(greeting: "Hello").welcome.deliver_later
106+
# assert_enqueued_email_with ContactMailer, :welcome, args: { greeting: "Hello" }
107+
# end
108+
#
104109
# def test_email_with_arguments
105110
# ContactMailer.welcome("Hello", "Goodbye").deliver_later
106111
# assert_enqueued_email_with ContactMailer, :welcome, args: ["Hello", "Goodbye"]
107112
# end
108113
#
114+
# def test_email_with_named_arguments
115+
# ContactMailer.welcome(greeting: "Hello", farewell: "Goodbye").deliver_later
116+
# assert_enqueued_email_with ContactMailer, :welcome, args: [{ greeting: "Hello", farewell: "Goodbye" }]
117+
# end
118+
#
119+
# def test_email_with_parameters_and_arguments
120+
# ContactMailer.with(greeting: "Hello").welcome("Cheers", "Goodbye").deliver_later
121+
# assert_enqueued_email_with ContactMailer, :welcome, params: { greeting: "Hello" }, args: ["Cheers", "Goodbye"]
122+
# end
123+
#
124+
# def test_email_with_parameters_and_named_arguments
125+
# ContactMailer.with(greeting: "Hello").welcome(farewell: "Goodbye").deliver_later
126+
# assert_enqueued_email_with ContactMailer, :welcome, params: { greeting: "Hello" }, args: [{farewell: "Goodbye"}]
127+
# end
128+
#
129+
# def test_email_with_parameterized_mailer
130+
# ContactMailer.with(greeting: "Hello").welcome.deliver_later
131+
# assert_enqueued_email_with ContactMailer.with(greeting: "Hello"), :welcome
132+
# end
133+
#
109134
# If a block is passed, that block should cause the specified email
110135
# to be enqueued.
111136
#
@@ -123,9 +148,15 @@ def assert_enqueued_emails(number, &block)
123148
# ContactMailer.with(email: '[email protected]').welcome.deliver_later
124149
# end
125150
# end
126-
def assert_enqueued_email_with(mailer, method, args: nil, queue: ActionMailer::Base.deliver_later_queue_name || "default", &block)
151+
def assert_enqueued_email_with(mailer, method, params: nil, args: nil, queue: ActionMailer::Base.deliver_later_queue_name || "default", &block)
152+
if mailer.is_a? ActionMailer::Parameterized::Mailer
153+
params = mailer.instance_variable_get(:@params)
154+
mailer = mailer.instance_variable_get(:@mailer)
155+
end
127156
args = if args.is_a?(Hash)
128157
[mailer.to_s, method.to_s, "deliver_now", params: args, args: []]
158+
elsif params.present?
159+
[mailer.to_s, method.to_s, "deliver_now", params: params, args: Array(args)]
129160
else
130161
[mailer.to_s, method.to_s, "deliver_now", args: Array(args)]
131162
end

actionmailer/test/test_helper_test.rb

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ def test_args(recipient, name)
1717
1818
end
1919

20+
def test_named_args(recipient:, name:)
21+
mail body: render(inline: "Hello, #{name}"),
22+
to: recipient,
23+
24+
end
25+
2026
def test_parameter_args
2127
mail body: render(inline: "All is #{params[:all]}"),
2228
@@ -393,6 +399,46 @@ def test_assert_enqueued_email_with_with_parameterized_args
393399
end
394400
end
395401

402+
def test_assert_enqueued_email_with_with_parameterized_mailer
403+
assert_nothing_raised do
404+
assert_enqueued_email_with TestHelperMailer.with(all: "good"), :test_parameter_args do
405+
silence_stream($stdout) do
406+
TestHelperMailer.with(all: "good").test_parameter_args.deliver_later
407+
end
408+
end
409+
end
410+
end
411+
412+
def test_assert_enqueued_email_with_with_named_args
413+
assert_nothing_raised do
414+
assert_enqueued_email_with TestHelperMailer, :test_named_args, args: [{ email: "some_email", name: "some_name" }] do
415+
silence_stream($stdout) do
416+
TestHelperMailer.test_named_args(email: "some_email", name: "some_name").deliver_later
417+
end
418+
end
419+
end
420+
end
421+
422+
def test_assert_enqueued_email_with_with_params_and_args
423+
assert_nothing_raised do
424+
assert_enqueued_email_with TestHelperMailer, :test_args, params: { all: "good" }, args: ["some_email", "some_name"] do
425+
silence_stream($stdout) do
426+
TestHelperMailer.with(all: "good").test_args("some_email", "some_name").deliver_later
427+
end
428+
end
429+
end
430+
end
431+
432+
def test_assert_enqueued_email_with_with_params_and_named_args
433+
assert_nothing_raised do
434+
assert_enqueued_email_with TestHelperMailer, :test_named_args, params: { all: "good" }, args: [{ email: "some_email", name: "some_name" }] do
435+
silence_stream($stdout) do
436+
TestHelperMailer.with(all: "good").test_named_args(email: "some_email", name: "some_name").deliver_later
437+
end
438+
end
439+
end
440+
end
441+
396442
def test_assert_enqueued_email_with_with_no_block_with_parameterized_args
397443
assert_nothing_raised do
398444
silence_stream($stdout) do

guides/source/testing.md

Lines changed: 85 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1765,14 +1765,9 @@ class UserMailerTest < ActionMailer::TestCase
17651765
end
17661766
```
17671767

1768-
In the test we create the email and store the returned object in the `email`
1769-
variable. We then ensure that it was sent (the first assert), then, in the
1770-
second batch of assertions, we ensure that the email does indeed contain what we
1771-
expect. The helper `read_fixture` is used to read in the content from this file.
1768+
In the test 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. The helper `read_fixture` is used to read in the content from this file.
17721769

1773-
NOTE: `email.body.to_s` is present when there's only one (HTML or text) part present.
1774-
If the mailer provides both, you can test your fixture against specific parts
1775-
with `email.text_part.body.to_s` or `email.html_part.body.to_s`.
1770+
NOTE: `email.body.to_s` is present when there's only one (HTML or text) part present. If the mailer provides both, you can test your fixture against specific parts with `email.text_part.body.to_s` or `email.html_part.body.to_s`.
17761771

17771772
Here's the content of the `invite` fixture:
17781773

@@ -1784,17 +1779,89 @@ You have been invited.
17841779
Cheers!
17851780
```
17861781

1787-
This is the right time to understand a little more about writing tests for your
1788-
mailers. The line `ActionMailer::Base.delivery_method = :test` in
1789-
`config/environments/test.rb` sets the delivery method to test mode so that
1790-
email will not actually be delivered (useful to avoid spamming your users while
1791-
testing) but instead it will be appended to an array
1792-
(`ActionMailer::Base.deliveries`).
1782+
This is the right time to understand a little more about writing tests for your 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 actually be delivered (useful to avoid spamming your users while testing) but instead it will be appended to an array (`ActionMailer::Base.deliveries`).
17931783

1794-
NOTE: The `ActionMailer::Base.deliveries` array is only reset automatically in
1795-
`ActionMailer::TestCase` and `ActionDispatch::IntegrationTest` tests.
1796-
If you want to have a clean slate outside these test cases, you can reset it
1797-
manually with: `ActionMailer::Base.deliveries.clear`
1784+
NOTE: The `ActionMailer::Base.deliveries` array is only reset automatically in `ActionMailer::TestCase` and `ActionDispatch::IntegrationTest` tests. If you want to have a clean slate outside these test cases, you can reset it manually with: `ActionMailer::Base.deliveries.clear`
1785+
1786+
#### Testing Enqueued Emails
1787+
1788+
You can use the `assert_enqueued_email_with` assertion to confirm that the email has been enqueued with all of the expected mailer method arguments and/or parameterized mailer parameters. This allows you to match any email that have been enqueued with the `deliver_later` method.
1789+
1790+
As with the basic test case, we create the email and store the returned object in the `email` variable. The following examples include variations of passing arguments and/or parameters.
1791+
1792+
This example will assert that the email has been enqueued with the correct arguments:
1793+
1794+
```ruby
1795+
require "test_helper"
1796+
1797+
class UserMailerTest < ActionMailer::TestCase
1798+
test "invite" do
1799+
# Create the email and store it for further assertions
1800+
email = UserMailer.create_invite("[email protected]", "[email protected]")
1801+
1802+
# Test that the email got enqueued with the correct arguments
1803+
assert_enqueued_email_with UserMailer, :create_invite, args: ["[email protected]", "[email protected]"] do
1804+
email.deliver_later
1805+
end
1806+
end
1807+
end
1808+
```
1809+
1810+
This example will assert that a mailer has been enqueued with the correct mailer method named arguments by passing a hash of the arguments as `args`:
1811+
1812+
```ruby
1813+
require "test_helper"
1814+
1815+
class UserMailerTest < ActionMailer::TestCase
1816+
test "invite" do
1817+
# Create the email and store it for further assertions
1818+
email = UserMailer.create_invite(from: "[email protected]", to: "[email protected]")
1819+
1820+
# Test that the email got enqueued with the correct named arguments
1821+
assert_enqueued_email_with UserMailer, :create_invite, args: [{ from: "[email protected]",
1822+
to: "[email protected]" }] do
1823+
email.deliver_later
1824+
end
1825+
end
1826+
end
1827+
```
1828+
1829+
This example will assert that a parameterized mailer has been enqueued with the correct parameters and arguments. The mailer parameters are passed as `params` and the mailer method arguments as `args`:
1830+
1831+
```ruby
1832+
require "test_helper"
1833+
1834+
class UserMailerTest < ActionMailer::TestCase
1835+
test "invite" do
1836+
# Create the email and store it for further assertions
1837+
email = UserMailer.with(all: "good").create_invite("[email protected]", "[email protected]")
1838+
1839+
# Test that the email got enqueued with the correct mailer parameters and arguments
1840+
assert_enqueued_email_with UserMailer, :create_invite, params: { all: "good" },
1841+
1842+
email.deliver_later
1843+
end
1844+
end
1845+
end
1846+
```
1847+
1848+
This example shows an alternative way to test that a parameterized mailer has been enqueued with the correct parameters:
1849+
1850+
```ruby
1851+
require "test_helper"
1852+
1853+
class UserMailerTest < ActionMailer::TestCase
1854+
test "invite" do
1855+
# Create the email and store it for further assertions
1856+
email = UserMailer.with(to: "[email protected]").create_invite
1857+
1858+
# Test that the email got enqueued with the correct mailer parameters
1859+
assert_enqueued_email_with UserMailer.with(to: "[email protected]"), :create_invite do
1860+
email.deliver_later
1861+
end
1862+
end
1863+
end
1864+
```
17981865

17991866
### Functional and System Testing
18001867

@@ -1831,7 +1898,7 @@ class UsersTest < ActionDispatch::SystemTestCase
18311898
end
18321899
```
18331900

1834-
NOTE: The `assert_emails` method is not tied to a particular deliver method and will work with emails delivered with either the `deliver_now` or `deliver_later` method. If we explicitly want to assert that the email has been enqueued we can use the `assert_enqueued_emails` method. More information can be found in the [documentation here](https://api.rubyonrails.org/classes/ActionMailer/TestHelper.html).
1901+
NOTE: The `assert_emails` method is not tied to a particular deliver method and will work with emails delivered with either the `deliver_now` or `deliver_later` method. If we explicitly want to assert that the email has been enqueued we can use the `assert_enqueued_email_with` ([examples above](#testing_enqueued_emails)) or `assert_enqueued_emails` methods. More information can be found in the [documentation here](https://api.rubyonrails.org/classes/ActionMailer/TestHelper.html).
18351902

18361903
Testing Jobs
18371904
------------

0 commit comments

Comments
 (0)