mitgliederverwaltung/test/mv_web/live/global_settings_live_test.exs
Simon 605a897045
All checks were successful
continuous-integration/drone/push Build is passing
fix: make sure smtp can be set either via env or ui
2026-05-07 10:01:34 +02:00

273 lines
9.3 KiB
Elixir

defmodule MvWeb.GlobalSettingsLiveTest do
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
alias Mv.Membership
@smtp_env_keys [
"SMTP_HOST",
"SMTP_PORT",
"SMTP_USERNAME",
"SMTP_PASSWORD",
"SMTP_PASSWORD_FILE",
"SMTP_SSL",
"MAIL_FROM_NAME",
"MAIL_FROM_EMAIL"
]
describe "Global Settings LiveView" do
setup %{conn: conn} do
user = create_test_user(%{email: "admin@example.com"})
conn = conn_with_oidc_user(conn, user)
{:ok, conn: conn, user: user}
end
test "renders the global settings page", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/settings")
assert html =~ "Club Settings"
assert html =~ "Settings"
end
test "displays current club name", %{conn: conn} do
# Set initial club name
{:ok, settings} = Membership.get_settings()
{:ok, _updated} = Membership.update_settings(settings, %{club_name: "Test Club"})
{:ok, _view, html} = live(conn, ~p"/settings")
assert html =~ "Test Club"
end
test "can update club name via form", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/settings")
# Submit form with new club name
assert view
|> form("#settings-form", %{setting: %{club_name: "Updated Club Name"}})
|> render_submit()
# Check for success message
assert render(view) =~ "Settings updated successfully"
assert render(view) =~ "Updated Club Name"
end
test "shows error when club_name is empty", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/settings")
# Submit form with empty club name
html =
view
|> form("#settings-form", %{setting: %{club_name: ""}})
|> render_submit()
assert html =~ "must be present"
end
test "shows error when club_name is missing", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/settings")
# Submit form with club_name explicitly set to empty string
# (Phoenix forms will keep existing value if field is omitted)
html =
view
|> form("#settings-form", %{setting: %{club_name: ""}})
|> render_submit()
assert html =~ "must be present"
end
test "shows open button for join page URL in same row as copy", %{conn: conn} do
{:ok, settings} = Membership.get_settings()
{:ok, _} = Membership.update_settings(settings, %{join_form_enabled: true})
{:ok, view, _html} = live(conn, ~p"/settings")
assert has_element?(view, "#copy-join-url-btn")
assert has_element?(
view,
"a[href][target=\"_blank\"][rel=\"noopener noreferrer\"]",
"Open"
)
end
end
describe "SMTP / E-Mail section" do
setup %{conn: conn} do
user = create_test_user(%{email: "admin@example.com"})
conn = conn_with_oidc_user(conn, user)
{:ok, conn: conn, user: user}
end
test "renders SMTP section with host/port fields and test email area", %{conn: conn} do
{:ok, _view, html} = live(conn, ~p"/settings")
# Section title (Gettext key: SMTP or E-Mail per concept)
assert html =~ "SMTP" or html =~ "E-Mail"
end
test "shows Send test email button when SMTP is configured", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/settings")
# When Mv.Config.smtp_configured?() is true, button and recipient input should be present
# In test env SMTP is typically not configured; we only assert the section exists
html = render(view)
assert html =~ "SMTP" or html =~ "E-Mail"
end
test "send test email with valid address shows success or error result", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/settings")
if has_element?(view, "[data-testid='smtp-test-email-form']") do
# Submit the test-email form (phx-submit) with a valid recipient address
view
|> form("[data-testid='smtp-test-email-form']", %{"to_email" => "test@example.com"})
|> render_submit()
# Result area must appear regardless of success or error
assert has_element?(view, "[data-testid='smtp-test-result']")
else
assert render(view) =~ "Settings"
end
end
test "shows warning when SMTP is not configured in production", %{conn: conn} do
# Concept: in prod, show warning "SMTP is not configured. Transactional emails..."
# In test we only check that the section exists; warning visibility is env-dependent
{:ok, _view, html} = live(conn, ~p"/settings")
assert html =~ "SMTP" or html =~ "E-Mail" or html =~ "Settings"
end
@tag :ui
test "disables all SMTP inputs when SMTP_HOST is set", %{conn: conn} do
clear_smtp_env()
System.put_env("SMTP_HOST", "smtp.env-only.example")
on_exit(fn -> clear_smtp_env() end)
{:ok, view, _html} = live(conn, ~p"/settings")
assert has_element?(view, "#setting_smtp_host[disabled]")
assert has_element?(view, "#setting_smtp_port[disabled]")
assert has_element?(view, "#setting_smtp_ssl[disabled]")
assert has_element?(view, "#setting_smtp_username[disabled]")
assert has_element?(view, "#setting_smtp_password[disabled]")
assert has_element?(view, "#setting_smtp_from_email[disabled]")
assert has_element?(view, "#setting_smtp_from_name[disabled]")
end
@tag :ui
test "does not render SMTP save action when SMTP_HOST is set", %{conn: conn} do
clear_smtp_env()
System.put_env("SMTP_HOST", "smtp.env-only.example")
on_exit(fn -> clear_smtp_env() end)
{:ok, view, _html} = live(conn, ~p"/settings")
refute has_element?(view, "#smtp-form button", "Save SMTP Settings")
end
@tag :ui
test "shows explicit ENV-only mode hint when SMTP_HOST is set", %{conn: conn} do
clear_smtp_env()
System.put_env("SMTP_HOST", "smtp.env-only.example")
on_exit(fn -> clear_smtp_env() end)
{:ok, _view, html} = live(conn, ~p"/settings")
assert html =~ "SMTP is fully managed via environment variables"
end
@tag :ui
test "shows warning block for missing required SMTP ENV values in ENV-only mode", %{
conn: conn
} do
clear_smtp_env()
System.put_env("SMTP_HOST", "smtp.env-only.example")
on_exit(fn -> clear_smtp_env() end)
{:ok, _view, html} = live(conn, ~p"/settings")
assert html =~ "SMTP environment configuration appears incomplete"
assert html =~ "SMTP_USERNAME"
assert html =~ "SMTP_PASSWORD/SMTP_PASSWORD_FILE"
end
@tag :ui
test "does not enter ENV-only mode when SMTP_HOST is not set", %{conn: conn} do
clear_smtp_env()
System.put_env("SMTP_USERNAME", "leftover@example.com")
on_exit(fn -> clear_smtp_env() end)
{:ok, view, html} = live(conn, ~p"/settings")
refute html =~ "SMTP is fully managed via environment variables"
refute html =~ "SMTP environment configuration appears incomplete"
refute has_element?(view, "#setting_smtp_host[disabled]")
refute has_element?(view, "#setting_smtp_username[disabled]")
end
end
describe "Authentication section when OIDC-only is enabled" do
setup %{conn: conn} do
user = create_test_user(%{email: "admin@example.com"})
conn = conn_with_oidc_user(conn, user)
{:ok, settings} = Membership.get_settings()
original_oidc_only = Map.get(settings, :oidc_only, false)
{:ok, _} = Membership.update_settings(settings, %{oidc_only: true})
{:ok, conn: conn, original_oidc_only: original_oidc_only}
end
@describetag :ui
test "registration checkbox is disabled when OIDC-only is enabled", %{
conn: conn,
original_oidc_only: original
} do
try do
{:ok, view, _html} = live(conn, ~p"/settings")
assert has_element?(view, "#registration-enabled-checkbox[disabled]")
after
{:ok, s} = Membership.get_settings()
Membership.update_settings(s, %{oidc_only: original})
end
end
@describetag :ui
test "OIDC-only hint is visible when OIDC-only is enabled", %{
conn: conn,
original_oidc_only: original
} do
try do
{:ok, view, _html} = live(conn, ~p"/settings")
assert has_element?(view, "[data-testid='oidc-only-registration-hint']")
after
{:ok, s} = Membership.get_settings()
Membership.update_settings(s, %{oidc_only: original})
end
end
test "when OIDC-only is disabled, registration checkbox is enabled and can be toggled", %{
conn: conn,
original_oidc_only: original
} do
try do
{:ok, settings} = Membership.get_settings()
Membership.update_settings(settings, %{oidc_only: false})
{:ok, view, _html} = live(conn, ~p"/settings")
refute has_element?(view, "#registration-enabled-checkbox[disabled]")
initial_checked =
view |> element("#registration-enabled-checkbox") |> render() =~ "checked"
view
|> element("#registration-enabled-checkbox")
|> render_click()
new_checked = view |> element("#registration-enabled-checkbox") |> render() =~ "checked"
assert new_checked != initial_checked
after
{:ok, s} = Membership.get_settings()
Membership.update_settings(s, %{oidc_only: original})
end
end
end
defp clear_smtp_env do
Enum.each(@smtp_env_keys, &System.delete_env/1)
end
end