Some checks failed
deploy / deploy (push) Has been cancelled
- semantic HTML: step numbers inside h2, strong provider names, details for adapter configs, strong error messages, fieldset drawer toggle hidden - inline field errors via flash for no-JS controller fallback - single form POST button for test email (works with and without JS) - admin sidebar: remove brand/view-shop, move user email to footer nav - replace inline style with .admin-setup-step-spaced class - clean up unused CSS (.admin-brand, .admin-sidebar-header, etc.) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
280 lines
8.9 KiB
Elixir
280 lines
8.9 KiB
Elixir
defmodule BerrypodWeb.Admin.EmailSettingsTest do
|
|
use BerrypodWeb.ConnCase, async: false
|
|
|
|
import Phoenix.LiveViewTest
|
|
import Berrypod.AccountsFixtures
|
|
|
|
alias Berrypod.{Mailer, Settings}
|
|
|
|
setup do
|
|
# Ensure mailer starts as test adapter and restore on exit
|
|
original = Application.get_env(:berrypod, Berrypod.Mailer)
|
|
Application.put_env(:berrypod, Berrypod.Mailer, adapter: Swoosh.Adapters.Test)
|
|
|
|
on_exit(fn ->
|
|
Application.put_env(:berrypod, Berrypod.Mailer, original)
|
|
end)
|
|
|
|
user = user_fixture()
|
|
%{user: user}
|
|
end
|
|
|
|
describe "authenticated" do
|
|
setup %{conn: conn, user: user} do
|
|
conn = log_in_user(conn, user)
|
|
%{conn: conn}
|
|
end
|
|
|
|
test "renders email settings page with provider cards", %{conn: conn} do
|
|
{:ok, _view, html} = live(conn, ~p"/admin/settings/email")
|
|
|
|
assert html =~ "Email settings"
|
|
assert html =~ "Choose a provider"
|
|
# Provider names rendered as radio cards
|
|
assert html =~ "Brevo"
|
|
assert html =~ "Mailjet"
|
|
assert html =~ "Postal"
|
|
end
|
|
|
|
test "shows providers and advanced section", %{conn: conn} do
|
|
{:ok, _view, html} = live(conn, ~p"/admin/settings/email")
|
|
|
|
assert html =~ "Brevo"
|
|
assert html =~ "SendGrid"
|
|
assert html =~ "Mailjet"
|
|
assert html =~ "MailerSend"
|
|
|
|
# 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"
|
|
end
|
|
|
|
test "renders all adapter field sections in the form", %{conn: conn} do
|
|
{:ok, _view, html} = live(conn, ~p"/admin/settings/email")
|
|
|
|
# All adapters have their config sections rendered (CSS controls visibility)
|
|
assert html =~ ~s(data-adapter="brevo")
|
|
assert html =~ ~s(data-adapter="sendgrid")
|
|
assert html =~ ~s(data-adapter="mailjet")
|
|
assert html =~ ~s(data-adapter="smtp")
|
|
assert html =~ ~s(data-adapter="postal")
|
|
end
|
|
|
|
test "selecting a provider updates via phx-change", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/settings/email")
|
|
|
|
# Select SMTP via form change (radio inputs fire phx-change)
|
|
html =
|
|
view
|
|
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "smtp"}})
|
|
|> render_change()
|
|
|
|
# SMTP fields are always rendered; check the step title changes
|
|
assert html =~ "Server host"
|
|
assert html =~ "Port"
|
|
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=\"form_change\"]", %{email: %{adapter: "brevo"}})
|
|
|> render_change()
|
|
|
|
# Submit with namespaced fields: email[brevo][api_key]
|
|
html =
|
|
view
|
|
|> form("form[phx-submit=\"save\"]", %{
|
|
email: %{adapter: "brevo", brevo: %{api_key: "xkeysib-abc123def456"}}
|
|
})
|
|
|> render_submit()
|
|
|
|
assert html =~ "Settings saved"
|
|
assert Settings.get_setting("email_adapter") == "brevo"
|
|
end
|
|
|
|
test "saving without required fields shows error", %{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()
|
|
|
|
# Submit without API key
|
|
html =
|
|
view
|
|
|> form("form[phx-submit=\"save\"]", %{
|
|
email: %{adapter: "brevo", brevo: %{api_key: ""}}
|
|
})
|
|
|> render_submit()
|
|
|
|
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", 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", "brevo")
|
|
Settings.put_secret("email_brevo_api_key", "xkeysib-test-abc")
|
|
|
|
{:ok, _view, html} = live(conn, ~p"/admin/settings/email")
|
|
|
|
assert html =~ "Send a test email"
|
|
assert html =~ "Send test email"
|
|
end
|
|
|
|
test "hides test email section when not configured", %{conn: conn} do
|
|
# Ensure clean state — no adapter configured
|
|
Settings.delete_setting("email_adapter")
|
|
Application.put_env(:berrypod, Berrypod.Mailer, adapter: Swoosh.Adapters.Local)
|
|
|
|
{:ok, _view, html} = live(conn, ~p"/admin/settings/email")
|
|
|
|
refute html =~ "Send test email"
|
|
end
|
|
|
|
test "sending test email shows success and sets verified flag", %{conn: conn} do
|
|
Settings.put_setting("email_adapter", "brevo")
|
|
Settings.put_secret("email_brevo_api_key", "xkeysib-test-abc")
|
|
|
|
{:ok, view, _html} = live(conn, ~p"/admin/settings/email")
|
|
|
|
# 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"
|
|
assert Mailer.email_verified?()
|
|
end
|
|
|
|
test "switching provider clears old provider settings", %{conn: conn} do
|
|
# Save Mailjet config first
|
|
Settings.put_setting("email_adapter", "mailjet")
|
|
Settings.put_secret("email_mailjet_api_key", "mj-key-123")
|
|
Settings.put_secret("email_mailjet_secret", "mj-secret-456")
|
|
|
|
{:ok, view, _html} = live(conn, ~p"/admin/settings/email")
|
|
|
|
# Switch to Brevo and save (namespaced fields)
|
|
view
|
|
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
|
|
|> render_change()
|
|
|
|
view
|
|
|> form("form[phx-submit=\"save\"]", %{
|
|
email: %{adapter: "brevo", brevo: %{api_key: "xkeysib-switch-test"}}
|
|
})
|
|
|> render_submit()
|
|
|
|
# Old Mailjet settings should be deleted
|
|
assert Settings.get_setting("email_adapter") == "brevo"
|
|
refute Settings.has_secret?("email_mailjet_api_key")
|
|
refute Settings.has_secret?("email_mailjet_secret")
|
|
# New Brevo key should exist
|
|
assert Settings.has_secret?("email_brevo_api_key")
|
|
end
|
|
|
|
test "saving config clears verified flag", %{conn: conn} do
|
|
Mailer.mark_email_verified()
|
|
assert Mailer.email_verified?()
|
|
|
|
{:ok, view, _html} = live(conn, ~p"/admin/settings/email")
|
|
|
|
view
|
|
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "brevo"}})
|
|
|> render_change()
|
|
|
|
view
|
|
|> form("form[phx-submit=\"save\"]", %{
|
|
email: %{adapter: "brevo", brevo: %{api_key: "xkeysib-def789ghi012"}}
|
|
})
|
|
|> render_submit()
|
|
|
|
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 "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
|
|
|
|
test "only selected adapter config is open (details element)", %{conn: conn} do
|
|
{:ok, view, _html} = live(conn, ~p"/admin/settings/email")
|
|
|
|
# Select SMTP
|
|
view
|
|
|> form("form[phx-change=\"form_change\"]", %{email: %{adapter: "smtp"}})
|
|
|> render_change()
|
|
|
|
# SMTP details should be open
|
|
assert has_element?(view, ~s(details[data-adapter="smtp"][open]))
|
|
# Others should not be open
|
|
refute has_element?(view, ~s(details[data-adapter="brevo"][open]))
|
|
refute has_element?(view, ~s(details[data-adapter="sendgrid"][open]))
|
|
refute has_element?(view, ~s(details[data-adapter="postal"][open]))
|
|
end
|
|
end
|
|
|
|
describe "unauthenticated" do
|
|
test "redirects to login", %{conn: conn} do
|
|
{:error, redirect} = live(conn, ~p"/admin/settings/email")
|
|
assert {:redirect, %{to: path}} = redirect
|
|
assert path == ~p"/users/log-in"
|
|
end
|
|
end
|
|
end
|