feat(member): condense the overview into composite name and address cells
This commit is contained in:
parent
b79d7ac9ea
commit
af2cc2e0d4
17 changed files with 716 additions and 93 deletions
|
|
@ -2,10 +2,14 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
use MvWeb.ConnCase, async: true
|
||||
import Phoenix.LiveViewTest
|
||||
|
||||
# The curated default columns hide the individual name/address sort headers,
|
||||
# so these component tests make every sortable field visible via ?fields=.
|
||||
@cols "first_name,email,street,house_number,postal_code,city,country,join_date"
|
||||
|
||||
describe "rendering" do
|
||||
test "renders with correct attributes", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
{:ok, view, _html} = live(conn, "/members?fields=#{@cols}")
|
||||
|
||||
# Test that the component renders with correct attributes
|
||||
assert has_element?(view, "[data-testid='first_name']")
|
||||
|
|
@ -15,7 +19,7 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "renders all sortable headers", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
{:ok, view, _html} = live(conn, "/members?fields=#{@cols}")
|
||||
|
||||
sortable_fields = [
|
||||
:first_name,
|
||||
|
|
@ -35,7 +39,7 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "renders correct labels", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
{:ok, view, _html} = live(conn, "/members?fields=#{@cols}")
|
||||
|
||||
# Test specific labels
|
||||
assert has_element?(view, "button[phx-value-field='first_name']", "First name")
|
||||
|
|
@ -47,7 +51,7 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
describe "sort icons" do
|
||||
test "shows neutral icon for specific field when not sorted", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
{:ok, view, _html} = live(conn, "/members?fields=#{@cols}")
|
||||
|
||||
# The neutral icon has the opcity class we can test for
|
||||
# Test that EMAIL field specifically shows neutral icon
|
||||
|
|
@ -59,7 +63,9 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "shows ascending icon for specific field when sorted ascending", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, html} = live(conn, "/members?query=&sort_field=city&sort_order=asc")
|
||||
|
||||
{:ok, view, html} =
|
||||
live(conn, "/members?fields=#{@cols}&query=&sort_field=city&sort_order=asc")
|
||||
|
||||
# Test that FIRST_NAME field specifically shows ascending icon
|
||||
# Test CSS classes - no opacity for active state
|
||||
|
|
@ -80,7 +86,9 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "shows descending icon for specific field when sorted descending", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, _view, html} = live(conn, "/members?query=&sort_field=email&sort_order=desc")
|
||||
|
||||
{:ok, _view, html} =
|
||||
live(conn, "/members?fields=#{@cols}&query=&sort_field=email&sort_order=desc")
|
||||
|
||||
# Count occurrences to ensure only one descending sort icon. Dropdown
|
||||
# triggers carry their own trailing "hero-chevron-down size-4" chevron, so
|
||||
|
|
@ -92,7 +100,9 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "multiple fields can have different icon states", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members?query=&sort_field=city&sort_order=asc")
|
||||
|
||||
{:ok, view, _html} =
|
||||
live(conn, "/members?fields=#{@cols}&query=&sort_field=city&sort_order=asc")
|
||||
|
||||
# CITY field should be active (ascending)
|
||||
refute has_element?(view, "[data-testid='city'] .opacity-40")
|
||||
|
|
@ -109,7 +119,7 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "icon state changes correctly when clicking different fields", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
{:ok, view, _html} = live(conn, "/members?fields=#{@cols}")
|
||||
|
||||
# Start: all fields neutral except first name as default
|
||||
assert has_element?(view, "[data-testid='city'] .opacity-40")
|
||||
|
|
@ -139,15 +149,19 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
conn = conn_with_oidc_user(conn)
|
||||
|
||||
# Test EMAIL field specifically
|
||||
{:ok, view, html_asc} = live(conn, "/members?sort_field=email&sort_order=asc")
|
||||
{:ok, view, html_asc} =
|
||||
live(conn, "/members?fields=#{@cols}&sort_field=email&sort_order=asc")
|
||||
|
||||
assert html_asc =~ "hero-chevron-up"
|
||||
refute has_element?(view, "[data-testid='email'] .opacity-40")
|
||||
|
||||
{:ok, view, html_desc} = live(conn, "/members?sort_field=email&sort_order=desc")
|
||||
{:ok, view, html_desc} =
|
||||
live(conn, "/members?fields=#{@cols}&sort_field=email&sort_order=desc")
|
||||
|
||||
assert html_desc =~ "hero-chevron-down"
|
||||
refute has_element?(view, "[data-testid='email'] .opacity-40")
|
||||
|
||||
{:ok, view, html_neutral} = live(conn, "/members")
|
||||
{:ok, view, html_neutral} = live(conn, "/members?fields=#{@cols}")
|
||||
assert html_neutral =~ "hero-chevron-up-down"
|
||||
assert has_element?(view, "[data-testid='email'] .opacity-40")
|
||||
end
|
||||
|
|
@ -156,7 +170,7 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
conn = conn_with_oidc_user(conn)
|
||||
|
||||
# Test neutral state - only one field should have active sort icon
|
||||
{:ok, _view, html_neutral} = live(conn, "/members")
|
||||
{:ok, _view, html_neutral} = live(conn, "/members?fields=#{@cols}")
|
||||
|
||||
# Count active icons (should be exactly 1 - ascending for default sort field)
|
||||
up_count = html_neutral |> String.split("hero-chevron-up ") |> length() |> Kernel.-(1)
|
||||
|
|
@ -166,7 +180,8 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
assert down_count == 0, "Expected 0 descending icons, got #{down_count}"
|
||||
|
||||
# Test descending state
|
||||
{:ok, _view, html_desc} = live(conn, "/members?sort_field=first_name&sort_order=desc")
|
||||
{:ok, _view, html_desc} =
|
||||
live(conn, "/members?fields=#{@cols}&sort_field=first_name&sort_order=desc")
|
||||
|
||||
up_count = html_desc |> String.split("hero-chevron-up ") |> length() |> Kernel.-(1)
|
||||
down_count = active_sort_down_count(html_desc)
|
||||
|
|
@ -190,7 +205,7 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
describe "accessibility" do
|
||||
test "sets aria-label correctly for unsorted state", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
{:ok, view, _html} = live(conn, "/members?fields=#{@cols}")
|
||||
|
||||
# Check aria-label for unsorted state
|
||||
assert has_element?(view, "button[phx-value-field='city'][aria-label='Click to sort']")
|
||||
|
|
@ -198,7 +213,9 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "sets aria-label correctly for ascending sort", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members?sort_field=first_name&sort_order=asc")
|
||||
|
||||
{:ok, view, _html} =
|
||||
live(conn, "/members?fields=#{@cols}&sort_field=first_name&sort_order=asc")
|
||||
|
||||
# Check aria-label for ascending sort
|
||||
assert has_element?(view, "button[phx-value-field='first_name'][aria-label='ascending']")
|
||||
|
|
@ -206,7 +223,9 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "sets aria-label correctly for descending sort", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members?sort_field=first_name&sort_order=desc")
|
||||
|
||||
{:ok, view, _html} =
|
||||
live(conn, "/members?fields=#{@cols}&sort_field=first_name&sort_order=desc")
|
||||
|
||||
# Check aria-label for descending sort
|
||||
assert has_element?(view, "button[phx-value-field='first_name'][aria-label='descending']")
|
||||
|
|
@ -214,7 +233,9 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "includes tooltip with correct aria-label", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members?sort_field=first_name&sort_order=asc")
|
||||
|
||||
{:ok, view, _html} =
|
||||
live(conn, "/members?fields=#{@cols}&sort_field=first_name&sort_order=asc")
|
||||
|
||||
# Check that tooltip div exists with correct data-tip
|
||||
assert has_element?(view, "[data-testid='first_name']")
|
||||
|
|
@ -223,7 +244,7 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "aria-labels work for all sortable fields", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members?sort_field=email&sort_order=desc")
|
||||
{:ok, view, _html} = live(conn, "/members?fields=#{@cols}&sort_field=email&sort_order=desc")
|
||||
|
||||
# Test aria-labels for different fields
|
||||
assert has_element?(view, "button[phx-value-field='email'][aria-label='descending']")
|
||||
|
|
@ -240,7 +261,7 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
describe "component behavior" do
|
||||
test "clicking triggers sort event on parent LiveView", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
{:ok, view, _html} = live(conn, "/members?fields=#{@cols}")
|
||||
|
||||
# Click on the first name sort header
|
||||
view
|
||||
|
|
@ -253,7 +274,7 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "component handles different field types correctly", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
{:ok, view, _html} = live(conn, "/members?fields=#{@cols}")
|
||||
|
||||
# Test that different field types render correctly
|
||||
assert has_element?(view, "button[phx-value-field='first_name']")
|
||||
|
|
@ -265,7 +286,9 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
describe "edge cases" do
|
||||
test "handles invalid sort field gracefully", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, html} = live(conn, "/members?sort_field=invalid_field&sort_order=asc")
|
||||
|
||||
{:ok, view, html} =
|
||||
live(conn, "/members?fields=#{@cols}&sort_field=invalid_field&sort_order=asc")
|
||||
|
||||
# Should not crash and should default sorting for first name
|
||||
assert html =~ "hero-chevron-up-down"
|
||||
|
|
@ -274,7 +297,9 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "handles invalid sort order gracefully", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, html} = live(conn, "/members?sort_field=first_name&sort_order=invalid")
|
||||
|
||||
{:ok, view, html} =
|
||||
live(conn, "/members?fields=#{@cols}&sort_field=first_name&sort_order=invalid")
|
||||
|
||||
# Should default to ascending
|
||||
assert html =~ "hero-chevron-up"
|
||||
|
|
@ -283,7 +308,7 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "handles empty sort parameters", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, html} = live(conn, "/members?sort_field=&sort_order=")
|
||||
{:ok, view, html} = live(conn, "/members?fields=#{@cols}&sort_field=&sort_order=")
|
||||
|
||||
# Should show neutral icons
|
||||
assert html =~ "hero-chevron-up-down"
|
||||
|
|
@ -294,7 +319,7 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
describe "icon state transitions" do
|
||||
test "icon changes when sorting state changes", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
{:ok, view, _html} = live(conn, "/members?fields=#{@cols}")
|
||||
|
||||
# Start with neutral state
|
||||
assert has_element?(view, "[data-testid='city'] .opacity-40")
|
||||
|
|
@ -310,7 +335,7 @@ defmodule MvWeb.Components.SortHeaderComponentTest do
|
|||
|
||||
test "multiple fields can be tested for icon states", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, html} = live(conn, "/members?sort_field=email&sort_order=desc")
|
||||
{:ok, view, html} = live(conn, "/members?fields=#{@cols}&sort_field=email&sort_order=desc")
|
||||
|
||||
# Email should be active (descending)
|
||||
assert html =~ "hero-chevron-down"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue