290 lines
8.2 KiB
Elixir
290 lines
8.2 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()
|
|
|
|
# Check for a validation error on the name field in a robust way
|
|
assert html =~ "name" or html =~ gettext("has already been taken")
|
|
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
|