mitgliederverwaltung/test/mv_web/live/group_live/form_test.exs
Simon 9991291b2f
All checks were successful
continuous-integration/drone/push Build is passing
test: adapt tests to reflect implementation details
2026-01-27 23:40:12 +01:00

289 lines
8.1 KiB
Elixir

defmodule MvWeb.GroupLive.FormTest do
@moduledoc """
Tests for the group create/edit form.
Tests cover:
- Creating groups
- Editing groups
- Form validations
- Edge cases
- Security
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
use Gettext, backend: MvWeb.Gettext
alias Mv.Fixtures
describe "create form" do
test "form renders with empty fields", %{conn: conn} do
{:ok, view, html} = live(conn, "/groups/new")
assert html =~ gettext("Create Group") or html =~ "create" or html =~ "Gruppe erstellen"
assert has_element?(view, "form")
end
test "creates group successfully with name and description", %{conn: conn} do
{:ok, view, _html} = live(conn, "/groups/new")
form_data = %{
"name" => "New Group",
"description" => "Group description"
}
view
|> form("#group-form", group: form_data)
|> render_submit()
# Should redirect to groups list or show page
assert_redirect(view, "/groups")
end
test "creates group successfully with name only (description optional)", %{conn: conn} do
{:ok, view, _html} = live(conn, "/groups/new")
form_data = %{
"name" => "Group Without Description"
}
view
|> form("#group-form", group: form_data)
|> render_submit()
assert_redirect(view, "/groups")
end
test "shows error when name is missing", %{conn: conn} do
{:ok, view, _html} = live(conn, "/groups/new")
form_data = %{
"description" => "Description without name"
}
html =
view
|> form("#group-form", group: form_data)
|> render_submit()
assert html =~ gettext("required") or html =~ "name" or html =~ "error" or
html =~ "erforderlich"
end
test "shows error when name exceeds 100 characters", %{conn: conn} do
{:ok, view, _html} = live(conn, "/groups/new")
long_name = String.duplicate("a", 101)
form_data = %{"name" => long_name}
html =
view
|> form("#group-form", group: form_data)
|> render_submit()
assert html =~ "100" or html =~ "length" or html =~ "error" or html =~ "Länge"
end
test "shows error when description exceeds 500 characters", %{conn: conn} do
{:ok, view, _html} = live(conn, "/groups/new")
long_description = String.duplicate("a", 501)
form_data = %{
"name" => "Test Group",
"description" => long_description
}
html =
view
|> form("#group-form", group: form_data)
|> render_submit()
assert html =~ "500" or html =~ "length" or html =~ "error" or html =~ "Länge"
end
test "shows error when name already exists (case-insensitive)", %{conn: conn} do
_existing_group = Fixtures.group_fixture(%{name: "Existing Group"})
{:ok, view, _html} = live(conn, "/groups/new")
form_data = %{
"name" => "EXISTING GROUP"
}
html =
view
|> form("#group-form", group: form_data)
|> render_submit()
assert html =~ "already" || html =~ "taken" || html =~ "exists" || html =~ "error"
end
test "shows error when name generates empty slug", %{conn: conn} do
{:ok, view, _html} = live(conn, "/groups/new")
form_data = %{
"name" => "!!!"
}
html =
view
|> form("#group-form", group: form_data)
|> render_submit()
assert html =~ "error" or html =~ "invalid" or html =~ "Fehler" or html =~ "ungültig"
end
end
describe "edit form" do
test "form renders with existing group data", %{conn: conn} do
group =
Fixtures.group_fixture(%{name: "Original Name", description: "Original Description"})
{:ok, view, html} = live(conn, "/groups/#{group.slug}/edit")
assert html =~ "Original Name"
assert html =~ "Original Description"
assert has_element?(view, "form")
end
test "updates group name successfully (slug remains unchanged)", %{conn: conn} do
group = Fixtures.group_fixture(%{name: "Original Name"})
original_slug = group.slug
{:ok, view, _html} = live(conn, "/groups/#{group.slug}/edit")
form_data = %{
"name" => "Updated Name"
}
view
|> form("#group-form", group: form_data)
|> render_submit()
# Verify slug didn't change by checking redirect URL or reloading
assert_redirect(view, "/groups/#{original_slug}")
end
test "updates group description successfully", %{conn: conn} do
group = Fixtures.group_fixture(%{description: "Old Description"})
{:ok, view, _html} = live(conn, "/groups/#{group.slug}/edit")
form_data = %{
"description" => "New Description"
}
view
|> form("#group-form", group: form_data)
|> render_submit()
assert_redirect(view, "/groups/#{group.slug}")
end
test "shows error when updating to duplicate name (case-insensitive)", %{conn: conn} do
_group1 = Fixtures.group_fixture(%{name: "Group One"})
group2 = Fixtures.group_fixture(%{name: "Group Two"})
{:ok, view, _html} = live(conn, "/groups/#{group2.slug}/edit")
form_data = %{
"name" => "GROUP ONE"
}
html =
view
|> form("#group-form", group: form_data)
|> render_submit()
assert html =~ "already" or html =~ "taken" or html =~ "exists" or html =~ "error" or
html =~ "bereits" or html =~ "vergeben"
end
test "slug is not displayed in form (immutable)", %{conn: conn} do
group = Fixtures.group_fixture(%{name: "Test Group"})
{:ok, _view, html} = live(conn, "/groups/#{group.slug}/edit")
# Slug should not be in form (it's immutable)
refute html =~ ~r/slug.*input/i or html =~ ~r/input.*slug/i
end
end
describe "edge cases" do
test "handles whitespace trimming correctly", %{conn: conn} do
{:ok, view, _html} = live(conn, "/groups/new")
form_data = %{
"name" => " Trimmed Group "
}
view
|> form("#group-form", group: form_data)
|> render_submit()
# Name should be trimmed
assert_redirect(view, "/groups")
end
test "handles umlauts in name correctly", %{conn: conn} do
{:ok, view, _html} = live(conn, "/groups/new")
form_data = %{
"name" => "Müller Gruppe"
}
view
|> form("#group-form", group: form_data)
|> render_submit()
assert_redirect(view, "/groups")
end
end
describe "security" do
@tag role: :member
test "non-admin users cannot access create form", %{conn: conn} do
result = live(conn, "/groups/new")
assert match?({:error, {:redirect, %{to: _}}}, result) ||
match?({:error, {:live_redirect, %{to: _}}}, result)
end
@tag role: :member
test "non-admin users cannot access edit form", %{conn: conn} do
group = Fixtures.group_fixture()
result = live(conn, "/groups/#{group.slug}/edit")
assert match?({:error, {:redirect, %{to: _}}}, result) ||
match?({:error, {:live_redirect, %{to: _}}}, result)
end
@tag role: :unauthenticated
test "unauthenticated users are redirected to login", %{conn: conn} do
result = live(conn, "/groups/new")
assert match?({:error, {:redirect, %{to: "/sign-in"}}}, result) ||
match?({:error, {:live_redirect, %{to: "/sign-in"}}}, result)
end
test "user cannot edit group with non-existent slug", %{conn: conn} do
non_existent_slug = "non-existent-group-slug"
result = live(conn, "/groups/#{non_existent_slug}/edit")
assert match?({:error, {:redirect, %{to: "/groups"}}}, result) ||
match?({:error, {:live_redirect, %{to: "/groups"}}}, result)
end
test "user cannot edit group with wrong slug (case mismatch)", %{conn: conn} do
group = Fixtures.group_fixture(%{name: "Test Group"})
wrong_case_slug = String.upcase(group.slug)
result = live(conn, "/groups/#{wrong_case_slug}/edit")
assert match?({:error, {:redirect, %{to: "/groups"}}}, result) ||
match?({:error, {:live_redirect, %{to: "/groups"}}}, result)
end
end
end