mitgliederverwaltung/test/mv_web/member_live/index_field_visibility_test.exs

452 lines
13 KiB
Elixir

defmodule MvWeb.MemberLive.IndexFieldVisibilityTest do
@moduledoc """
Integration tests for field visibility dropdown functionality.
Tests cover:
- Field selection dropdown rendering
- Toggling field visibility
- URL parameter persistence
- Select all / deselect all
- Integration with member list display
- Custom fields visibility
"""
use MvWeb.ConnCase, async: true
import Phoenix.LiveViewTest
require Ash.Query
alias Mv.Membership.{CustomField, CustomFieldValue, Member}
setup do
# Create test members
{:ok, member1} =
Member
|> Ash.Changeset.for_create(:create_member, %{
first_name: "Alice",
last_name: "Anderson",
email: "alice@example.com",
street: "Main St",
city: "Berlin"
})
|> Ash.create()
{:ok, member2} =
Member
|> Ash.Changeset.for_create(:create_member, %{
first_name: "Bob",
last_name: "Brown",
email: "bob@example.com",
street: "Second St",
city: "Hamburg"
})
|> Ash.create()
# Create custom field
{:ok, custom_field} =
CustomField
|> Ash.Changeset.for_create(:create, %{
name: "membership_number",
value_type: :string,
show_in_overview: true
})
|> Ash.create()
# Create custom field values
{:ok, _cfv1} =
CustomFieldValue
|> Ash.Changeset.for_create(:create, %{
member_id: member1.id,
custom_field_id: custom_field.id,
value: "M001"
})
|> Ash.create()
{:ok, _cfv2} =
CustomFieldValue
|> Ash.Changeset.for_create(:create, %{
member_id: member2.id,
custom_field_id: custom_field.id,
value: "M002"
})
|> Ash.create()
%{
member1: member1,
member2: member2,
custom_field: custom_field
}
end
describe "field visibility dropdown" do
test "renders dropdown button", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/members")
assert html =~ "Columns"
assert html =~ ~s(aria-controls="field-visibility-menu")
end
test "opens dropdown when button is clicked", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
# Initially closed
refute has_element?(view, "ul#field-visibility-menu")
# Click button
view
|> element("button[aria-controls='field-visibility-menu']")
|> render_click()
# Should be open now
assert has_element?(view, "ul#field-visibility-menu")
end
test "displays all member fields in dropdown", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
# Open dropdown
view
|> element("button[aria-controls='field-visibility-menu']")
|> render_click()
html = render(view)
# Check for member fields (formatted labels)
assert html =~ "First Name" or html =~ "first_name"
assert html =~ "Email" or html =~ "email"
assert html =~ "Street" or html =~ "street"
end
test "displays custom fields in dropdown", %{conn: conn, custom_field: custom_field} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
# Open dropdown
view
|> element("button[aria-controls='field-visibility-menu']")
|> render_click()
html = render(view)
assert html =~ custom_field.name
end
end
describe "field visibility toggling" do
test "hiding a field removes it from display", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
# Verify email is visible initially
html = render(view)
assert html =~ "alice@example.com"
# Open dropdown and hide email
view
|> element("button[aria-controls='field-visibility-menu']")
|> render_click()
view
|> element("button[phx-click='select_item'][phx-value-item='email']")
|> render_click()
# Wait for update
:timer.sleep(100)
# Email should no longer be visible
html = render(view)
refute html =~ "alice@example.com"
refute html =~ "bob@example.com"
end
test "hiding custom field removes it from display", %{conn: conn, custom_field: custom_field} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
# Verify custom field is visible initially
html = render(view)
assert html =~ "M001" or html =~ custom_field.name
# Open dropdown and hide custom field
view
|> element("button[aria-controls='field-visibility-menu']")
|> render_click()
custom_field_id = custom_field.id
custom_field_string = "custom_field_#{custom_field_id}"
view
|> element("button[phx-click='select_item'][phx-value-item='#{custom_field_string}']")
|> render_click()
# Wait for update
:timer.sleep(100)
# Custom field should no longer be visible
html = render(view)
refute html =~ "M001"
refute html =~ "M002"
end
end
describe "select all / deselect all" do
test "select all makes all fields visible", %{conn: conn} do
conn = conn_with_oidc_user(conn)
# Start with some fields hidden
{:ok, view, _html} = live(conn, "/members?fields=first_name")
# Open dropdown
view
|> element("button[aria-controls='field-visibility-menu']")
|> render_click()
# Click select all
view
|> element("button[phx-click='select_all']")
|> render_click()
# Wait for update
:timer.sleep(100)
# All fields should be visible
html = render(view)
assert html =~ "alice@example.com"
assert html =~ "Main St"
assert html =~ "Berlin"
end
test "deselect all hides all fields except first_name", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
# Open dropdown
view
|> element("button[aria-controls='field-visibility-menu']")
|> render_click()
# Click deselect all
view
|> element("button[phx-click='select_none']")
|> render_click()
# Wait for update
:timer.sleep(100)
# Only first_name should be visible (it's always shown)
html = render(view)
# Email and street should be hidden
refute html =~ "alice@example.com"
refute html =~ "Main St"
end
end
describe "URL parameter persistence" do
test "field selection is persisted in URL", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
# Open dropdown and hide email
view
|> element("button[aria-controls='field-visibility-menu']")
|> render_click()
view
|> element("button[phx-click='select_item'][phx-value-item='email']")
|> render_click()
# Wait for URL update
:timer.sleep(100)
# Check that URL contains fields parameter
# Note: In LiveView tests, we check the rendered HTML for the updated state
# The actual URL update happens via push_patch
end
test "loading page with fields parameter applies selection", %{conn: conn} do
conn = conn_with_oidc_user(conn)
# Load with first_name and city explicitly set in URL
# Note: Other fields may still be visible due to global settings
{:ok, view, _html} = live(conn, "/members?fields=first_name,city")
html = render(view)
# first_name and city should be visible
assert html =~ "Alice"
assert html =~ "Berlin"
# Note: email and street may still be visible if global settings allow it
# This test verifies that the URL parameters work, not that they hide other fields
end
test "fields parameter works with custom fields", %{conn: conn, custom_field: custom_field} do
conn = conn_with_oidc_user(conn)
custom_field_id = custom_field.id
# Load with custom field visible
{:ok, view, _html} =
live(conn, "/members?fields=first_name,custom_field_#{custom_field_id}")
html = render(view)
# Custom field should be visible
assert html =~ "M001" or html =~ custom_field.name
end
end
describe "integration with global settings" do
test "respects global settings when no user selection", %{conn: conn} do
# This test would require setting up global settings
# For now, we verify that the system works with default settings
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/members")
# All fields should be visible by default
assert html =~ "alice@example.com"
assert html =~ "Main St"
end
test "user selection overrides global settings", %{conn: conn} do
# This would require setting up global settings first
# Then verifying that user selection takes precedence
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
# Hide a field via dropdown
view
|> element("button[aria-controls='field-visibility-menu']")
|> render_click()
view
|> element("button[phx-click='select_item'][phx-value-item='email']")
|> render_click()
:timer.sleep(100)
html = render(view)
refute html =~ "alice@example.com"
end
end
describe "edge cases" do
test "handles empty fields parameter", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/members?fields=")
# Should fall back to global settings
assert html =~ "alice@example.com"
end
test "handles invalid field names in URL", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/members?fields=invalid_field,another_invalid")
# Should ignore invalid fields and use defaults
assert html =~ "alice@example.com"
end
test "handles custom field that doesn't exist", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/members?fields=first_name,custom_field_nonexistent")
# Should work without errors
assert html =~ "Alice"
end
test "handles rapid toggling", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
# Open dropdown
view
|> element("button[aria-controls='field-visibility-menu']")
|> render_click()
# Rapidly toggle a field multiple times
for _ <- 1..5 do
view
|> element("button[phx-click='select_item'][phx-value-item='email']")
|> render_click()
:timer.sleep(50)
end
# Should still work correctly
html = render(view)
assert html =~ "Alice"
end
end
describe "accessibility" do
test "dropdown has proper ARIA attributes", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, _view, html} = live(conn, "/members")
assert html =~ ~s(aria-controls="field-visibility-menu")
assert html =~ ~s(aria-haspopup="menu")
assert html =~ ~s(role="button")
end
test "menu items have proper ARIA attributes when open", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
# Open dropdown
view
|> element("button[aria-controls='field-visibility-menu']")
|> render_click()
html = render(view)
assert html =~ ~s(role="menu")
assert html =~ ~s(role="menuitemcheckbox")
assert html =~ ~s(aria-checked)
end
test "keyboard navigation works", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
# Open dropdown
view
|> element("button[aria-controls='field-visibility-menu']")
|> render_click()
# Check that elements are keyboard accessible
html = render(view)
assert html =~ ~s(tabindex="0")
# Check that keyboard events are supported
assert html =~ ~s(phx-keydown="select_item")
assert html =~ ~s(phx-key="Enter")
end
test "keyboard activation with Enter key works", %{conn: conn} do
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, "/members")
# Verify email is visible initially
html = render(view)
assert html =~ "alice@example.com"
# Open dropdown
view
|> element("button[aria-controls='field-visibility-menu']")
|> render_click()
# Simulate Enter key press on email field button
view
|> element("button[phx-click='select_item'][phx-value-item='email']")
|> render_keydown(%{key: "Enter"})
# Wait for update
:timer.sleep(100)
# Email should no longer be visible
html = render(view)
refute html =~ "alice@example.com"
end
end
end