181 lines
4.9 KiB
Elixir
181 lines
4.9 KiB
Elixir
defmodule MvWeb.MemberLive.IndexGroupsAccessibilityTest do
|
|
@moduledoc """
|
|
Tests for accessibility of groups feature in the member overview.
|
|
|
|
Tests cover:
|
|
- Badges have role="status" and aria-label
|
|
- Filter dropdown has aria-label
|
|
- Sort header has aria-label for screen reader
|
|
- Keyboard navigation works (Tab through filter, sort header)
|
|
"""
|
|
# async: false to prevent PostgreSQL deadlocks when creating members and groups
|
|
use MvWeb.ConnCase, async: false
|
|
import Phoenix.LiveViewTest
|
|
require Ash.Query
|
|
|
|
alias Mv.Membership.{Group, MemberGroup}
|
|
|
|
setup do
|
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
|
|
# Create test members
|
|
{:ok, member1} =
|
|
Mv.Membership.create_member(
|
|
%{first_name: "Alice", last_name: "Anderson", email: "alice@example.com"},
|
|
actor: system_actor
|
|
)
|
|
|
|
# Create test groups
|
|
{:ok, group1} =
|
|
Group
|
|
|> Ash.Changeset.for_create(:create, %{name: "Board Members"})
|
|
|> Ash.create(actor: system_actor)
|
|
|
|
# Create member-group associations
|
|
{:ok, _mg1} =
|
|
MemberGroup
|
|
|> Ash.Changeset.for_create(:create, %{member_id: member1.id, group_id: group1.id})
|
|
|> Ash.create(actor: system_actor)
|
|
|
|
%{
|
|
member1: member1,
|
|
group1: group1
|
|
}
|
|
end
|
|
|
|
@tag :ui
|
|
test "group badges have role and aria-label", %{
|
|
conn: conn,
|
|
member1: member1,
|
|
group1: group1
|
|
} do
|
|
conn = conn_with_oidc_user(conn)
|
|
{:ok, view, html} = live(conn, "/members")
|
|
|
|
# Verify badges have accessibility attributes
|
|
# Badges should have role="status" and aria-label describing the group
|
|
assert html =~ ~r/role=["']status["']/ or html =~ ~r/aria-label=.*#{group1.name}/
|
|
assert html =~ group1.name
|
|
|
|
# Verify member1's row contains the badge
|
|
assert html =~ member1.first_name
|
|
end
|
|
|
|
@tag :ui
|
|
test "filter dropdown has group presence section with legend", %{
|
|
conn: conn
|
|
} do
|
|
conn = conn_with_oidc_user(conn)
|
|
{:ok, view, _html} = live(conn, "/members")
|
|
|
|
# Open filter dropdown
|
|
view
|
|
|> element("button[aria-label='Filter members']")
|
|
|> render_click()
|
|
|
|
html = render(view)
|
|
# Groups section: legend "Member has groups" and radios (Any / Yes / No)
|
|
assert html =~ ~r/[Gg]roups/
|
|
assert has_element?(view, "[data-testid='member-filter-form']")
|
|
end
|
|
|
|
@tag :ui
|
|
test "sort header has aria-label for screen reader", %{
|
|
conn: conn
|
|
} do
|
|
conn = conn_with_oidc_user(conn)
|
|
{:ok, view, html} = live(conn, "/members")
|
|
|
|
# Verify sort header has aria-label
|
|
# Sort header should have aria-label describing the sort state
|
|
assert html =~ ~r/aria-label=.*[Gg]roup/ or
|
|
has_element?(view, "[data-testid='groups'][aria-label]")
|
|
end
|
|
|
|
@tag :ui
|
|
test "keyboard navigation works for filter dropdown", %{
|
|
conn: conn,
|
|
member1: member1,
|
|
group1: group1
|
|
} do
|
|
conn = conn_with_oidc_user(conn)
|
|
{:ok, view, _html} = live(conn, "/members")
|
|
|
|
view
|
|
|> element("button[aria-label='Filter members']")
|
|
|> render_click()
|
|
|
|
view
|
|
|> element("[data-testid='member-filter-form']")
|
|
|> render_change(%{"group_#{group1.id}" => "in", "payment_filter" => "all"})
|
|
|
|
html = render(view)
|
|
assert html =~ member1.first_name
|
|
end
|
|
|
|
@tag :ui
|
|
test "keyboard navigation works for sort header", %{
|
|
conn: conn
|
|
} do
|
|
conn = conn_with_oidc_user(conn)
|
|
{:ok, view, _html} = live(conn, "/members")
|
|
|
|
assert has_element?(view, "[data-testid='groups']")
|
|
|
|
view
|
|
|> element("[data-testid='groups']")
|
|
|> render_click()
|
|
|
|
# Verify sort was applied (URL may include other params)
|
|
assert has_element?(view, "[data-testid='groups'][aria-label*='ascending']")
|
|
end
|
|
|
|
@tag :ui
|
|
test "screen reader announcements for filter changes", %{
|
|
conn: conn,
|
|
member1: member1,
|
|
group1: group1
|
|
} do
|
|
conn = conn_with_oidc_user(conn)
|
|
{:ok, view, _html} = live(conn, "/members")
|
|
|
|
view
|
|
|> element("button[aria-label='Filter members']")
|
|
|> render_click()
|
|
|
|
view
|
|
|> element("[data-testid='member-filter-form']")
|
|
|> render_change(%{"group_#{group1.id}" => "in", "payment_filter" => "all"})
|
|
|
|
html = render(view)
|
|
assert html =~ member1.first_name
|
|
end
|
|
|
|
@tag :ui
|
|
test "multiple badges are announced correctly", %{
|
|
conn: conn,
|
|
member1: member1
|
|
} do
|
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
|
|
# Create multiple groups for member1
|
|
{:ok, group2} =
|
|
Group
|
|
|> Ash.Changeset.for_create(:create, %{name: "Active Members"})
|
|
|> Ash.create(actor: system_actor)
|
|
|
|
{:ok, _mg} =
|
|
MemberGroup
|
|
|> Ash.Changeset.for_create(:create, %{member_id: member1.id, group_id: group2.id})
|
|
|> Ash.create(actor: system_actor)
|
|
|
|
conn = conn_with_oidc_user(conn)
|
|
{:ok, view, html} = live(conn, "/members")
|
|
|
|
# Verify multiple badges are present
|
|
assert html =~ member1.first_name
|
|
# Both groups should be visible
|
|
# Screen reader should be able to distinguish between multiple badges
|
|
assert html
|
|
end
|
|
end
|