Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improves assert_delivered_email and adds assert_delivered_with #228

Merged
merged 3 commits into from
Dec 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 67 additions & 24 deletions lib/bamboo/test.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
defmodule Bamboo.Test do
@timeout 100

import ExUnit.Assertions

@moduledoc """
Expand Down Expand Up @@ -159,33 +157,46 @@ defmodule Bamboo.Test do
unsent_email = Bamboo.Email.new_email(subject: "something else")
assert_delivered_email(unsent_email) # Will fail
"""
def assert_delivered_email(%Bamboo.Email{} = email) do
email = normalize_for_testing(email)
do_assert_delivered_email(email)
defmacro assert_delivered_email(email) do
quote do
import ExUnit.Assertions
email = Bamboo.Test.normalize_for_testing(unquote(email))
assert_receive({:delivered_email, ^email}, 100, Bamboo.Test.flunk_with_email_list(email))
end
end

defp do_assert_delivered_email(email) do
receive do
{:delivered_email, ^email} -> true
after
@timeout -> flunk_with_email_list(email)
@doc """
Check whether an email's params are equal to the ones provided.

Must be used with the `Bamboo.TestAdapter` or this will never pass. In case you
are delivering from another process, the assertion waits up to 100ms before
failing. Typically if an email is successfully delivered the assertion will
pass instantly, so test suites will remain fast.

## Examples

email = Bamboo.Email.new_email(subject: "something")
email |> MyApp.Mailer.deliver
assert_delivered_with(subject: "something") # Will pass

unsent_email = Bamboo.Email.new_email(subject: "something else")
assert_delivered_with(subject: "something else") # Will fail
"""
defmacro assert_delivered_with(email_params) do
quote bind_quoted: [email_params: email_params] do
import ExUnit.Assertions
assert_receive({:delivered_email, email}, 100, Bamboo.Test.flunk_no_emails_received)

recieved_email_params = email |> Map.from_struct
assert Enum.all?(email_params, fn({k, v}) -> recieved_email_params[k] == v end),
Bamboo.Test.flunk_attributes_do_not_match(email_params, recieved_email_params)
end
end

defp flunk_with_email_list(email) do
@doc false
def flunk_with_email_list(email) do
if Enum.empty?(delivered_emails) do
flunk """
There were 0 emails delivered to this process.

If you expected an email to be sent, try these ideas:

1) Make sure you call deliver_now/1 or deliver_later/1 to deliver the email
2) Make sure you are using the Bamboo.TestAdapter
3) Use shared mode with Bamboo.Test. This will allow Bamboo.Test
to work across processes: use Bamboo.Test, shared: :true
4) If you are writing an acceptance test through a headless browser, use
shared mode as described in option 3.
"""
flunk_no_emails_received
else
flunk """
There were no matching emails.
Expand All @@ -201,6 +212,37 @@ defmodule Bamboo.Test do
end
end

@doc false
def flunk_no_emails_received do
flunk """
There were 0 emails delivered to this process.

If you expected an email to be sent, try these ideas:

1) Make sure you call deliver_now/1 or deliver_later/1 to deliver the email
2) Make sure you are using the Bamboo.TestAdapter
3) Use shared mode with Bamboo.Test. This will allow Bamboo.Test
to work across processes: use Bamboo.Test, shared: :true
4) If you are writing an acceptance test through a headless browser, use
shared mode as described in option 3.
"""
end

@doc false
def flunk_attributes_do_not_match(params_given, params_received) do
"""
The parameters given do not match.

Parameters given:

#{inspect params_given}

Email recieved:

#{inspect params_received}
"""
end

defp delivered_emails do
{:messages, messages} = Process.info(self, :messages)

Expand Down Expand Up @@ -310,7 +352,8 @@ defmodule Bamboo.Test do
!!Application.get_env(:bamboo, :shared_test_process)
end

defp normalize_for_testing(email) do
@doc false
def normalize_for_testing(email) do
email
|> Bamboo.Mailer.normalize_addresses
|> Bamboo.TestAdapter.clean_assigns
Expand Down
35 changes: 35 additions & 0 deletions test/lib/bamboo/adapters/test_adapter_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ defmodule Bamboo.TestAdapterTest do
assert_raise ExUnit.AssertionError, fn ->
assert_delivered_email %{sent_email | to: "oops"}
end

sent_email |> TestMailer.deliver_now
assert_delivered_with(from: {nil, "foo@bar.com"})

sent_email |> TestMailer.deliver_now
assert_raise ExUnit.AssertionError, fn ->
assert_delivered_with(from: "oops")
end
end

test "assert_delivered_email with no delivered emails" do
Expand Down Expand Up @@ -106,6 +114,33 @@ defmodule Bamboo.TestAdapterTest do
end
end

test "assert_delivered_with with no delivered emails" do
try do
assert_delivered_with from: {nil, "foo@bar.com"}
rescue
error in [ExUnit.AssertionError] ->
assert error.message =~ "0 emails delivered"
else
_ -> flunk "assert_delivered_email should have failed"
end
end

test "assert_delivered_with shows non-matching delivered email" do
sent_email = new_email(from: "foo@bar.com", to: ["foo@bar.com"])

sent_email |> TestMailer.deliver_now

try do
assert_delivered_with to: "oops"
rescue
error in [ExUnit.AssertionError] ->
assert error.message =~ "do not match"
assert error.message =~ sent_email.from
else
_ -> flunk "assert_delivered_email should have failed"
end
end

test "assert_no_emails_delivered shows the delivered email" do
sent_email = new_email(from: "foo@bar.com", to: ["foo@bar.com"])

Expand Down