mitgliederverwaltung/test/mv_web/member_live/show_groups_display_test.exs
Simon 911f308a67
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/promote/production Build is passing
fix: address review comments
2026-02-17 15:30:23 +01:00

262 lines
7.5 KiB
Elixir

defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
@moduledoc """
Tests for displaying groups in the member detail view (Issue #374).
Tests cover:
- Groups in Personal Data (with and without groups)
- Group links with correct names and links to group detail pages
- Edge cases (one group, many groups)
- Security: groups visible only when user may view member
- Accessibility: group links have aria-label for screen readers
## Note on async
async: false to avoid PostgreSQL deadlocks when creating members and groups
in the same test run (same as IndexGroupsDisplayTest).
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
require Ash.Query
use Gettext, backend: MvWeb.Gettext
alias Mv.Membership.{Group, MemberGroup}
describe "groups section" do
setup do
actor = Mv.Helpers.SystemActor.get_system_actor()
{:ok, member} =
create_member(actor, %{
first_name: "Alice",
last_name: "Anderson",
email: "alice@example.com"
})
%{member: member, actor: actor}
end
test "displays Groups section when member has at least one group", %{
conn: conn,
member: member,
actor: actor
} do
{:ok, group} = create_group(actor, "Board Members")
{:ok, _mg} = add_member_to_group(member, group, actor)
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, ~p"/members/#{member}")
assert html =~ gettext("Groups")
assert html =~ group.name
end
test "displays all group links with correct names when member is in multiple groups", %{
conn: conn,
member: member,
actor: actor
} do
{:ok, group1} = create_group(actor, "Board Members")
{:ok, group2} = create_group(actor, "Active Members")
{:ok, _mg1} = add_member_to_group(member, group1, actor)
{:ok, _mg2} = add_member_to_group(member, group2, actor)
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, ~p"/members/#{member}")
assert html =~ gettext("Groups")
assert html =~ group1.name
assert html =~ group2.name
end
test "displays Groups section when member has no groups (empty state)", %{
conn: conn,
member: member
} do
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, ~p"/members/#{member}")
# Groups are in Personal Data; label "Groups" and empty state "No groups" must be present
assert html =~ gettext("Groups")
assert html =~ gettext("No groups")
end
test "renders all group names when member has multiple groups", %{
conn: conn,
member: member,
actor: actor
} do
{:ok, group1} = create_group(actor, "Alpha")
{:ok, group2} = create_group(actor, "Beta")
{:ok, _mg1} = add_member_to_group(member, group1, actor)
{:ok, _mg2} = add_member_to_group(member, group2, actor)
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, ~p"/members/#{member}")
assert html =~ "Alpha"
assert html =~ "Beta"
end
end
describe "groups section links" do
setup do
actor = Mv.Helpers.SystemActor.get_system_actor()
{:ok, member} =
create_member(actor, %{first_name: "Bob", last_name: "Brown", email: "bob@example.com"})
{:ok, group} = create_group(actor, "Board Members")
{:ok, _mg} = add_member_to_group(member, group, actor)
%{member: member, group: group}
end
test "each group link goes to group detail page with correct slug", %{
conn: conn,
member: member,
group: group
} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, ~p"/members/#{member}")
# Link to group detail: /groups/:slug (slug is URL-friendly, e.g. "board-members")
assert has_element?(view, "a[href*='/groups/#{group.slug}']", group.name)
end
test "clicking group link navigates to group detail page", %{
conn: conn,
member: member,
group: group
} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, ~p"/members/#{member}")
view
|> element("a[href*='/groups/#{group.slug}']")
|> render_click()
assert_redirect(view, ~p"/groups/#{group.slug}")
end
end
describe "groups section edge cases" do
setup do
actor = Mv.Helpers.SystemActor.get_system_actor()
{:ok, member} =
create_member(actor, %{
first_name: "Charlie",
last_name: "Clark",
email: "charlie@example.com"
})
%{member: member, actor: actor}
end
test "member in exactly one group shows single link", %{
conn: conn,
member: member,
actor: actor
} do
{:ok, group} = create_group(actor, "Solo Group")
{:ok, _mg} = add_member_to_group(member, group, actor)
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, ~p"/members/#{member}")
assert html =~ gettext("Groups")
assert html =~ group.name
end
test "member in many groups shows all group links", %{
conn: conn,
member: member,
actor: actor
} do
group_names = Enum.map(1..5, fn i -> "Group #{i}" end)
groups =
Enum.map(group_names, fn name ->
{:ok, g} = create_group(actor, name)
g
end)
for g <- groups do
{:ok, _mg} = add_member_to_group(member, g, actor)
end
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, ~p"/members/#{member}")
assert html =~ gettext("Groups")
for name <- group_names do
assert html =~ name
end
end
end
describe "groups section with read_only user" do
@tag role: :read_only
test "user with read permission sees Groups section", %{conn: conn} do
actor = Mv.Helpers.SystemActor.get_system_actor()
{:ok, member} =
create_member(actor, %{
first_name: "Diana",
last_name: "Davis",
email: "diana@example.com"
})
{:ok, group} = create_group(actor, "Readers")
{:ok, _mg} = add_member_to_group(member, group, actor)
{:ok, _view, html} = live(conn, ~p"/members/#{member}")
assert html =~ gettext("Groups")
assert html =~ group.name
end
end
describe "groups section accessibility" do
setup do
actor = Mv.Helpers.SystemActor.get_system_actor()
{:ok, member} =
create_member(actor, %{first_name: "Eve", last_name: "Evans", email: "eve@example.com"})
{:ok, group} = create_group(actor, "A11y Group")
{:ok, _mg} = add_member_to_group(member, group, actor)
%{member: member, group: group}
end
test "group links have aria-label for screen readers", %{
conn: conn,
member: member,
group: group
} do
conn = conn_with_oidc_user(conn)
{:ok, view, html} = live(conn, ~p"/members/#{member}")
assert html =~ group.name
# Group link has aria-label indicating group membership for screen readers
assert has_element?(view, "a[aria-label*='#{group.name}']")
end
end
# Helpers to reduce setup duplication (create member/group, assign member to group).
defp create_member(actor, attrs) do
Mv.Membership.create_member(attrs, actor: actor)
end
defp create_group(actor, name) do
Group
|> Ash.Changeset.for_create(:create, %{name: name})
|> Ash.create(actor: actor)
end
defp add_member_to_group(member, group, actor) do
MemberGroup
|> Ash.Changeset.for_create(:create, %{member_id: member.id, group_id: group.id})
|> Ash.create(actor: actor)
end
end