fix: address review comments
This commit is contained in:
parent
b1a9eb8b1d
commit
911f308a67
7 changed files with 88 additions and 164 deletions
|
|
@ -3,7 +3,7 @@ defmodule MvWeb.MemberLive.IndexGroupsAccessibilityTest do
|
|||
Tests for accessibility of groups feature in the member overview.
|
||||
|
||||
Tests cover:
|
||||
- Badges have role="status" and aria-label
|
||||
- Badges have aria-label for group membership (no role="status"; reserved for live regions)
|
||||
- Filter dropdown has aria-label
|
||||
- Sort header has aria-label for screen reader
|
||||
- Keyboard navigation works (Tab through filter, sort header)
|
||||
|
|
@ -44,7 +44,7 @@ defmodule MvWeb.MemberLive.IndexGroupsAccessibilityTest do
|
|||
end
|
||||
|
||||
@tag :ui
|
||||
test "group badges have role and aria-label", %{
|
||||
test "group badges have aria-label for screen readers", %{
|
||||
conn: conn,
|
||||
member1: member1,
|
||||
group1: group1
|
||||
|
|
@ -52,8 +52,8 @@ defmodule MvWeb.MemberLive.IndexGroupsAccessibilityTest do
|
|||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, html} = live(conn, "/members")
|
||||
|
||||
# Verify badges have role="status" and aria-label containing the group name
|
||||
assert has_element?(view, "span[role='status'][aria-label*='#{group1.name}']")
|
||||
# Verify badges have aria-label containing the group name (no role=status on badges)
|
||||
assert has_element?(view, "span[aria-label*='#{group1.name}']")
|
||||
assert html =~ group1.name
|
||||
|
||||
# Verify member1's row contains the badge
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
|
|||
|
||||
Tests cover:
|
||||
- Groups in Personal Data (with and without groups)
|
||||
- Group buttons with correct names and links to group detail pages
|
||||
- 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 role and aria-label
|
||||
- Accessibility: group links have aria-label for screen readers
|
||||
|
||||
## Note on async
|
||||
async: false to avoid PostgreSQL deadlocks when creating members and groups
|
||||
|
|
@ -22,15 +22,16 @@ defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
|
|||
|
||||
describe "groups section" do
|
||||
setup do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
{:ok, member} =
|
||||
Mv.Membership.create_member(
|
||||
%{first_name: "Alice", last_name: "Anderson", email: "alice@example.com"},
|
||||
actor: system_actor
|
||||
)
|
||||
create_member(actor, %{
|
||||
first_name: "Alice",
|
||||
last_name: "Anderson",
|
||||
email: "alice@example.com"
|
||||
})
|
||||
|
||||
%{member: member, actor: system_actor}
|
||||
%{member: member, actor: actor}
|
||||
end
|
||||
|
||||
test "displays Groups section when member has at least one group", %{
|
||||
|
|
@ -38,15 +39,8 @@ defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
|
|||
member: member,
|
||||
actor: actor
|
||||
} do
|
||||
{:ok, group} =
|
||||
Group
|
||||
|> Ash.Changeset.for_create(:create, %{name: "Board Members"})
|
||||
|> Ash.create(actor: actor)
|
||||
|
||||
{:ok, _mg} =
|
||||
MemberGroup
|
||||
|> Ash.Changeset.for_create(:create, %{member_id: member.id, group_id: group.id})
|
||||
|> Ash.create(actor: actor)
|
||||
{: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}")
|
||||
|
|
@ -55,30 +49,15 @@ defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
|
|||
assert html =~ group.name
|
||||
end
|
||||
|
||||
test "displays all groups as badges with correct names when member is in multiple groups", %{
|
||||
test "displays all group links with correct names when member is in multiple groups", %{
|
||||
conn: conn,
|
||||
member: member,
|
||||
actor: actor
|
||||
} do
|
||||
{:ok, group1} =
|
||||
Group
|
||||
|> Ash.Changeset.for_create(:create, %{name: "Board Members"})
|
||||
|> Ash.create(actor: actor)
|
||||
|
||||
{:ok, group2} =
|
||||
Group
|
||||
|> Ash.Changeset.for_create(:create, %{name: "Active Members"})
|
||||
|> Ash.create(actor: actor)
|
||||
|
||||
{:ok, _mg1} =
|
||||
MemberGroup
|
||||
|> Ash.Changeset.for_create(:create, %{member_id: member.id, group_id: group1.id})
|
||||
|> Ash.create(actor: actor)
|
||||
|
||||
{:ok, _mg2} =
|
||||
MemberGroup
|
||||
|> Ash.Changeset.for_create(:create, %{member_id: member.id, group_id: group2.id})
|
||||
|> Ash.create(actor: actor)
|
||||
{: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}")
|
||||
|
|
@ -100,30 +79,15 @@ defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
|
|||
assert html =~ gettext("No groups")
|
||||
end
|
||||
|
||||
test "groups are loaded with member (single request returns all group names)", %{
|
||||
test "renders all group names when member has multiple groups", %{
|
||||
conn: conn,
|
||||
member: member,
|
||||
actor: actor
|
||||
} do
|
||||
{:ok, group1} =
|
||||
Group
|
||||
|> Ash.Changeset.for_create(:create, %{name: "Alpha"})
|
||||
|> Ash.create(actor: actor)
|
||||
|
||||
{:ok, group2} =
|
||||
Group
|
||||
|> Ash.Changeset.for_create(:create, %{name: "Beta"})
|
||||
|> Ash.create(actor: actor)
|
||||
|
||||
{:ok, _mg1} =
|
||||
MemberGroup
|
||||
|> Ash.Changeset.for_create(:create, %{member_id: member.id, group_id: group1.id})
|
||||
|> Ash.create(actor: actor)
|
||||
|
||||
{:ok, _mg2} =
|
||||
MemberGroup
|
||||
|> Ash.Changeset.for_create(:create, %{member_id: member.id, group_id: group2.id})
|
||||
|> Ash.create(actor: actor)
|
||||
{: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}")
|
||||
|
|
@ -135,41 +99,29 @@ defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
|
|||
|
||||
describe "groups section links" do
|
||||
setup do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
{:ok, member} =
|
||||
Mv.Membership.create_member(
|
||||
%{first_name: "Bob", last_name: "Brown", email: "bob@example.com"},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, group} =
|
||||
Group
|
||||
|> Ash.Changeset.for_create(:create, %{name: "Board Members"})
|
||||
|> Ash.create(actor: system_actor)
|
||||
|
||||
{:ok, _mg} =
|
||||
MemberGroup
|
||||
|> Ash.Changeset.for_create(:create, %{member_id: member.id, group_id: group.id})
|
||||
|> Ash.create(actor: system_actor)
|
||||
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 badge links to group detail page with correct slug", %{
|
||||
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}")
|
||||
{:ok, view, _html} = live(conn, ~p"/members/#{member}")
|
||||
|
||||
# Link to group detail: /groups/:slug (slug is URL-friendly, e.g. "board-members")
|
||||
assert html =~
|
||||
~r/href="[^"]*\/groups\/#{Regex.escape(group.slug)}"|navigate="[^"]*\/groups\/#{Regex.escape(group.slug)}"/
|
||||
assert has_element?(view, "a[href*='/groups/#{group.slug}']", group.name)
|
||||
end
|
||||
|
||||
test "clicking group badge navigates to group detail page", %{
|
||||
test "clicking group link navigates to group detail page", %{
|
||||
conn: conn,
|
||||
member: member,
|
||||
group: group
|
||||
|
|
@ -187,31 +139,25 @@ defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
|
|||
|
||||
describe "groups section edge cases" do
|
||||
setup do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
{:ok, member} =
|
||||
Mv.Membership.create_member(
|
||||
%{first_name: "Charlie", last_name: "Clark", email: "charlie@example.com"},
|
||||
actor: system_actor
|
||||
)
|
||||
create_member(actor, %{
|
||||
first_name: "Charlie",
|
||||
last_name: "Clark",
|
||||
email: "charlie@example.com"
|
||||
})
|
||||
|
||||
%{member: member, actor: system_actor}
|
||||
%{member: member, actor: actor}
|
||||
end
|
||||
|
||||
test "member in exactly one group shows single badge", %{
|
||||
test "member in exactly one group shows single link", %{
|
||||
conn: conn,
|
||||
member: member,
|
||||
actor: actor
|
||||
} do
|
||||
{:ok, group} =
|
||||
Group
|
||||
|> Ash.Changeset.for_create(:create, %{name: "Solo Group"})
|
||||
|> Ash.create(actor: actor)
|
||||
|
||||
{:ok, _mg} =
|
||||
MemberGroup
|
||||
|> Ash.Changeset.for_create(:create, %{member_id: member.id, group_id: group.id})
|
||||
|> Ash.create(actor: actor)
|
||||
{: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}")
|
||||
|
|
@ -220,7 +166,7 @@ defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
|
|||
assert html =~ group.name
|
||||
end
|
||||
|
||||
test "member in many groups shows all badges", %{
|
||||
test "member in many groups shows all group links", %{
|
||||
conn: conn,
|
||||
member: member,
|
||||
actor: actor
|
||||
|
|
@ -229,19 +175,12 @@ defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
|
|||
|
||||
groups =
|
||||
Enum.map(group_names, fn name ->
|
||||
{:ok, g} =
|
||||
Group
|
||||
|> Ash.Changeset.for_create(:create, %{name: name})
|
||||
|> Ash.create(actor: actor)
|
||||
|
||||
{:ok, g} = create_group(actor, name)
|
||||
g
|
||||
end)
|
||||
|
||||
for g <- groups do
|
||||
{:ok, _mg} =
|
||||
MemberGroup
|
||||
|> Ash.Changeset.for_create(:create, %{member_id: member.id, group_id: g.id})
|
||||
|> Ash.create(actor: actor)
|
||||
{:ok, _mg} = add_member_to_group(member, g, actor)
|
||||
end
|
||||
|
||||
conn = conn_with_oidc_user(conn)
|
||||
|
|
@ -258,23 +197,17 @@ defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
|
|||
describe "groups section with read_only user" do
|
||||
@tag role: :read_only
|
||||
test "user with read permission sees Groups section", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
{:ok, member} =
|
||||
Mv.Membership.create_member(
|
||||
%{first_name: "Diana", last_name: "Davis", email: "diana@example.com"},
|
||||
actor: system_actor
|
||||
)
|
||||
create_member(actor, %{
|
||||
first_name: "Diana",
|
||||
last_name: "Davis",
|
||||
email: "diana@example.com"
|
||||
})
|
||||
|
||||
{:ok, group} =
|
||||
Group
|
||||
|> Ash.Changeset.for_create(:create, %{name: "Readers"})
|
||||
|> Ash.create(actor: system_actor)
|
||||
|
||||
{:ok, _mg} =
|
||||
MemberGroup
|
||||
|> Ash.Changeset.for_create(:create, %{member_id: member.id, group_id: group.id})
|
||||
|> Ash.create(actor: system_actor)
|
||||
{:ok, group} = create_group(actor, "Readers")
|
||||
{:ok, _mg} = add_member_to_group(member, group, actor)
|
||||
|
||||
{:ok, _view, html} = live(conn, ~p"/members/#{member}")
|
||||
|
||||
|
|
@ -285,28 +218,17 @@ defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
|
|||
|
||||
describe "groups section accessibility" do
|
||||
setup do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
|
||||
{:ok, member} =
|
||||
Mv.Membership.create_member(
|
||||
%{first_name: "Eve", last_name: "Evans", email: "eve@example.com"},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, group} =
|
||||
Group
|
||||
|> Ash.Changeset.for_create(:create, %{name: "A11y Group"})
|
||||
|> Ash.create(actor: system_actor)
|
||||
|
||||
{:ok, _mg} =
|
||||
MemberGroup
|
||||
|> Ash.Changeset.for_create(:create, %{member_id: member.id, group_id: group.id})
|
||||
|> Ash.create(actor: system_actor)
|
||||
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 badges have role and aria-label for screen readers", %{
|
||||
test "group links have aria-label for screen readers", %{
|
||||
conn: conn,
|
||||
member: member,
|
||||
group: group
|
||||
|
|
@ -316,8 +238,25 @@ defmodule MvWeb.MemberLive.ShowGroupsDisplayTest do
|
|||
|
||||
assert html =~ group.name
|
||||
|
||||
# Badge has role="status" and aria-label indicating group membership (architecture: "Member of group X")
|
||||
assert has_element?(view, "[role='status'][aria-label*='#{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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue