fix email settings: missing providers, a11y, no-JS support
show all 10 providers in three groups (popular, transactional, advanced) with category headings. fix phx-change clobbering text fields, async test email sending state, integer parse crash on bad port. add keyboard focus on card radios, fieldset legend, WCAG-compliant badge contrast, responsive grid. extract shared save_config into Mailer, add no-JS controller fallback with configured_adapter hidden field for adapter change detection. remove CardRadioScroll JS hook (no longer needed). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -37,11 +37,33 @@ defmodule BerrypodWeb.Admin.EmailSettingsTest do
|
||||
assert html =~ "Postal"
|
||||
end
|
||||
|
||||
test "shows all three provider groups", %{conn: conn} do
|
||||
{:ok, _view, html} = live(conn, ~p"/admin/settings/email")
|
||||
|
||||
# All-email providers
|
||||
assert html =~ "Popular providers"
|
||||
assert html =~ "Brevo"
|
||||
assert html =~ "SendGrid"
|
||||
assert html =~ "Mailjet"
|
||||
assert html =~ "MailerSend"
|
||||
|
||||
# Transactional providers
|
||||
assert html =~ "Transactional only"
|
||||
assert html =~ "Resend"
|
||||
assert html =~ "Postmark"
|
||||
assert html =~ "Mailgun"
|
||||
assert html =~ "MailPace"
|
||||
|
||||
# Advanced in details
|
||||
assert html =~ "Already have your own email server?"
|
||||
assert html =~ "SMTP"
|
||||
assert html =~ "Postal"
|
||||
end
|
||||
|
||||
test "shows setup guidance", %{conn: conn} do
|
||||
{:ok, _view, html} = live(conn, ~p"/admin/settings/email")
|
||||
|
||||
assert html =~ "needs an email provider"
|
||||
assert html =~ "Paste your API key"
|
||||
assert html =~ "300 emails/day free"
|
||||
end
|
||||
|
||||
@@ -51,7 +73,7 @@ defmodule BerrypodWeb.Admin.EmailSettingsTest do
|
||||
# Select SMTP via form change (radio inputs fire phx-change)
|
||||
html =
|
||||
view
|
||||
|> form("form[phx-change=\"change_adapter\"]", %{email: %{adapter: "smtp"}})
|
||||
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "smtp"}})
|
||||
|> render_change()
|
||||
|
||||
assert html =~ "Server host"
|
||||
@@ -66,19 +88,31 @@ defmodule BerrypodWeb.Admin.EmailSettingsTest do
|
||||
# Select Brevo which needs just an api_key
|
||||
html =
|
||||
view
|
||||
|> form("form[phx-change=\"change_adapter\"]", %{email: %{adapter: "brevo"}})
|
||||
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
|
||||
|> render_change()
|
||||
|
||||
assert html =~ "API key"
|
||||
assert html =~ "Brevo"
|
||||
end
|
||||
|
||||
test "selecting a transactional provider shows its config", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, ~p"/admin/settings/email")
|
||||
|
||||
html =
|
||||
view
|
||||
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "resend"}})
|
||||
|> render_change()
|
||||
|
||||
assert html =~ "API key"
|
||||
assert html =~ "Resend"
|
||||
end
|
||||
|
||||
test "saving config persists settings", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, ~p"/admin/settings/email")
|
||||
|
||||
# Select Brevo via form change
|
||||
view
|
||||
|> form("form[phx-change=\"change_adapter\"]", %{email: %{adapter: "brevo"}})
|
||||
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
|
||||
|> render_change()
|
||||
|
||||
# Submit with an API key
|
||||
@@ -98,7 +132,7 @@ defmodule BerrypodWeb.Admin.EmailSettingsTest do
|
||||
|
||||
# Select Brevo
|
||||
view
|
||||
|> form("form[phx-change=\"change_adapter\"]", %{email: %{adapter: "brevo"}})
|
||||
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
|
||||
|> render_change()
|
||||
|
||||
# Submit without API key
|
||||
@@ -110,6 +144,23 @@ defmodule BerrypodWeb.Admin.EmailSettingsTest do
|
||||
assert html =~ "API key is required"
|
||||
end
|
||||
|
||||
test "saving with invalid port shows error", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, ~p"/admin/settings/email")
|
||||
|
||||
view
|
||||
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "smtp"}})
|
||||
|> render_change()
|
||||
|
||||
html =
|
||||
view
|
||||
|> form("form[phx-submit=\"save\"]", %{
|
||||
email: %{adapter: "smtp", relay: "smtp.example.com", port: "abc"}
|
||||
})
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ "must be a number"
|
||||
end
|
||||
|
||||
test "shows test email section when configured", %{conn: conn} do
|
||||
Settings.put_setting("email_adapter", "postmark")
|
||||
Settings.put_secret("email_postmark_api_key", "pm_test_abc")
|
||||
@@ -136,7 +187,10 @@ defmodule BerrypodWeb.Admin.EmailSettingsTest do
|
||||
|
||||
{:ok, view, _html} = live(conn, ~p"/admin/settings/email")
|
||||
|
||||
html = render_click(view, "send_test")
|
||||
# send_test is now async — click triggers the event, then handle_info completes it
|
||||
render_click(view, "send_test")
|
||||
# Wait for the async handle_info to complete
|
||||
html = render(view)
|
||||
|
||||
assert html =~ "Email is working"
|
||||
assert html =~ "Send again"
|
||||
@@ -153,7 +207,7 @@ defmodule BerrypodWeb.Admin.EmailSettingsTest do
|
||||
|
||||
# Switch to Brevo and save
|
||||
view
|
||||
|> form("form[phx-change=\"change_adapter\"]", %{email: %{adapter: "brevo"}})
|
||||
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
|
||||
|> render_change()
|
||||
|
||||
view
|
||||
@@ -177,7 +231,7 @@ defmodule BerrypodWeb.Admin.EmailSettingsTest do
|
||||
{:ok, view, _html} = live(conn, ~p"/admin/settings/email")
|
||||
|
||||
view
|
||||
|> form("form[phx-change=\"change_adapter\"]", %{email: %{adapter: "brevo"}})
|
||||
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
|
||||
|> render_change()
|
||||
|
||||
view
|
||||
@@ -188,6 +242,46 @@ defmodule BerrypodWeb.Admin.EmailSettingsTest do
|
||||
|
||||
refute Mailer.email_verified?()
|
||||
end
|
||||
|
||||
test "phx-change is no-op when adapter hasn't changed", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, ~p"/admin/settings/email")
|
||||
|
||||
# Select Brevo
|
||||
view
|
||||
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
|
||||
|> render_change()
|
||||
|
||||
# Trigger another change with the same adapter (simulates text field input)
|
||||
html =
|
||||
view
|
||||
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
|
||||
|> render_change()
|
||||
|
||||
# Should still show Brevo config
|
||||
assert html =~ "Brevo"
|
||||
assert html =~ "API key"
|
||||
end
|
||||
|
||||
test "adapter query param preselects provider", %{conn: conn} do
|
||||
{:ok, _view, html} = live(conn, ~p"/admin/settings/email?adapter=resend")
|
||||
|
||||
assert html =~ "Resend"
|
||||
assert html =~ "API key"
|
||||
end
|
||||
|
||||
test "from_checklist param shows checklist banner", %{conn: conn} do
|
||||
{:ok, _view, html} = live(conn, ~p"/admin/settings/email?from=checklist")
|
||||
|
||||
assert html =~ "setting up email"
|
||||
assert html =~ "Back to checklist"
|
||||
end
|
||||
|
||||
test "has fieldset legend for accessibility", %{conn: conn} do
|
||||
{:ok, _view, html} = live(conn, ~p"/admin/settings/email")
|
||||
|
||||
assert html =~ "Email provider"
|
||||
assert html =~ "sr-only"
|
||||
end
|
||||
end
|
||||
|
||||
describe "unauthenticated" do
|
||||
|
||||
Reference in New Issue
Block a user