I’m working on an integration test that hits a user registration path in Phoenix (using mix.gen.auth). It worked as below:
test "send registration token if email is not within system", %{conn: conn} do
conn =
post(conn, Routes.user_registration_path(conn, :create), %{
"user" => %{"email" => "unknown@example.com"}
})
assert redirected_to(conn) == "/"
assert get_flash(conn, :info) =~ "sign-in link"
assert Repo.all(Accounts.UserToken) != []
end
Then I wrapped the part of the user registration responsible for sending email in a Task.start
so as not to delay rendering of the page while an email is sent. This breaks the tests since generating a registration email takes longer than the tests to complete.
What approach would you take for an end-to-end test with an asynchronous component like this? I’m currently evaluating the following:
- Making the test sleep (easy but can lead to non-deterministic failures)
- Rewriting the Task.start with Task.async in the registration controller, adding a pid to all necessary function params and using assert_receive from the test. This pollutes the controller code and still won’t work end to end since the test couldn’t pass the pid to the post
- Writing a utility function that passes a function to Task.start, unless the mix_env is test, in which case it just runs the function. This is simple, but seems to be a bad path, longer term.
What’s the better solution?