test: add tdd tests for groups administration #372
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
0a2aa3bad0
commit
f05fae3ea3
6 changed files with 962 additions and 4 deletions
285
test/mv_web/live/group_live/form_test.exs
Normal file
285
test/mv_web/live/group_live/form_test.exs
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
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") || html =~ "create"
|
||||
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("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("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("form", group: form_data)
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ gettext("required") || html =~ "name" || html =~ "error"
|
||||
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("form", group: form_data)
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ "100" || html =~ "length" || html =~ "error"
|
||||
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("form", group: form_data)
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ "500" || html =~ "length" || html =~ "error"
|
||||
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("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("form", group: form_data)
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ "error" || html =~ "invalid"
|
||||
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("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("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("form", group: form_data)
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ "already" || html =~ "taken" || html =~ "exists" || html =~ "error"
|
||||
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 || 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("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("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: "/auth/sign_in"}}}, result) ||
|
||||
match?({:error, {:live_redirect, %{to: "/auth/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
|
||||
Loading…
Add table
Add a link
Reference in a new issue