test: updated tests
This commit is contained in:
parent
b71df98ba2
commit
41e3a52482
6 changed files with 412 additions and 16 deletions
|
|
@ -44,6 +44,7 @@ defmodule MvWeb.Components.SearchBarComponent do
|
||||||
placeholder={@placeholder}
|
placeholder={@placeholder}
|
||||||
value={@query}
|
value={@query}
|
||||||
name="query"
|
name="query"
|
||||||
|
data-testid="search-input"
|
||||||
phx-change="search"
|
phx-change="search"
|
||||||
phx-target={@myself}
|
phx-target={@myself}
|
||||||
phx-debounce="300"
|
phx-debounce="300"
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ defmodule MvWeb.Components.SortHeaderComponent do
|
||||||
case dir do
|
case dir do
|
||||||
:asc -> gettext("ascending")
|
:asc -> gettext("ascending")
|
||||||
:desc -> gettext("descending")
|
:desc -> gettext("descending")
|
||||||
|
nil -> gettext("Click to sort")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,18 @@ for member_attrs <- [
|
||||||
city: "Berlin",
|
city: "Berlin",
|
||||||
street: "Kastanienallee",
|
street: "Kastanienallee",
|
||||||
house_number: "8"
|
house_number: "8"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
first_name: "Marianne",
|
||||||
|
last_name: "Wagner",
|
||||||
|
email: "marianne.wagner@example.de",
|
||||||
|
birth_date: ~D[1978-11-08],
|
||||||
|
join_date: ~D[2022-11-10],
|
||||||
|
paid: true,
|
||||||
|
phone_number: "+49301122334",
|
||||||
|
city: "Berlin",
|
||||||
|
street: "Kastanienallee",
|
||||||
|
house_number: "8"
|
||||||
}
|
}
|
||||||
] do
|
] do
|
||||||
# Use upsert to prevent duplicates based on email
|
# Use upsert to prevent duplicates based on email
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,14 @@ defmodule MvWeb.Components.SearchBarComponentTest do
|
||||||
html =
|
html =
|
||||||
view
|
view
|
||||||
|> element("form[role=search]")
|
|> element("form[role=search]")
|
||||||
|> render_change(%{"query" => "Friedrich"})
|
|> render_submit(%{"query" => "Friedrich"})
|
||||||
|
|
||||||
refute html =~ "Greta"
|
refute html =~ "Greta"
|
||||||
|
|
||||||
html =
|
html =
|
||||||
view
|
view
|
||||||
|> element("form[role=search]")
|
|> element("form[role=search]")
|
||||||
|> render_change(%{"query" => "Greta"})
|
|> render_submit(%{"query" => "Greta"})
|
||||||
|
|
||||||
refute html =~ "Friedrich"
|
refute html =~ "Friedrich"
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,301 @@
|
||||||
defmodule MvWeb.Components.SortHeaderComponentTest do
|
defmodule MvWeb.Components.SortHeaderComponentTest do
|
||||||
use MvWeb.ConnCase, async: true
|
use MvWeb.ConnCase, async: true
|
||||||
use Phoenix.Component
|
|
||||||
import Phoenix.LiveViewTest
|
import Phoenix.LiveViewTest
|
||||||
|
|
||||||
test "renders sort header with correct attributes", %{conn: conn} do
|
describe "rendering" do
|
||||||
conn = conn_with_oidc_user(conn)
|
test "renders with correct attributes", %{conn: conn} do
|
||||||
{:ok, view, _html} = live(conn, "/members")
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, "/members")
|
||||||
|
|
||||||
assert view |> element("[data-testid='first_name']")
|
# Test that the component renders with correct attributes
|
||||||
|
assert has_element?(view, "[data-testid='first_name']")
|
||||||
|
assert has_element?(view, "button[phx-value-field='city']")
|
||||||
|
assert has_element?(view, "button[phx-value-field='first_name']", "First name")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "renders all sortable headers", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, "/members")
|
||||||
|
|
||||||
|
sortable_fields = [:first_name, :email, :street, :house_number, :postal_code, :city, :phone_number, :join_date]
|
||||||
|
|
||||||
|
for field <- sortable_fields do
|
||||||
|
assert has_element?(view, "button[phx-value-field='#{field}']")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "renders correct labels", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, "/members")
|
||||||
|
|
||||||
|
# Test specific labels
|
||||||
|
assert has_element?(view, "button[phx-value-field='first_name']", "First name")
|
||||||
|
assert has_element?(view, "button[phx-value-field='email']", "Email")
|
||||||
|
assert has_element?(view, "button[phx-value-field='city']", "City")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# The neutral icon has the opcity class we can test for
|
||||||
|
# Test that EMAIL field specifically shows neutral icon
|
||||||
|
assert has_element?(view, "[data-testid='email'] .opacity-40")
|
||||||
|
|
||||||
|
# Test that CITY field specifically shows neutral icon
|
||||||
|
assert has_element?(view, "[data-testid='city'] .opacity-40")
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Test that FIRST_NAME field specifically shows ascending icon
|
||||||
|
# Test CSS classes - no opacity for active state
|
||||||
|
refute has_element?(view, "[data-testid='city'] .opacity-40")
|
||||||
|
|
||||||
|
# Test that OTHER fields still show neutral icons
|
||||||
|
assert has_element?(view, "[data-testid='first_name'] .opacity-40")
|
||||||
|
|
||||||
|
# Test HTML content - should contain chevron-up AND chevron-up-down
|
||||||
|
assert html =~ "hero-chevron-up"
|
||||||
|
assert html =~ "hero-chevron-up-down"
|
||||||
|
|
||||||
|
# Count occurrences to ensure only one ascending icon
|
||||||
|
up_count = html |> String.split("hero-chevron-up ") |> length() |> Kernel.-(1)
|
||||||
|
assert up_count == 1 # Should be exactly one chevron-up icon
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Count occurrences to ensure only one descending icon
|
||||||
|
down_count = html |> String.split("hero-chevron-down ") |> length() |> Kernel.-(1)
|
||||||
|
assert down_count == 1 # Should be exactly one chevron-down icon
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# CITY field should be active (ascending)
|
||||||
|
refute has_element?(view, "[data-testid='city'] .opacity-40")
|
||||||
|
|
||||||
|
# All other fields should be neutral
|
||||||
|
assert has_element?(view, "[data-testid='first_name'] .opacity-40")
|
||||||
|
assert has_element?(view, "[data-testid='email'] .opacity-40")
|
||||||
|
assert has_element?(view, "[data-testid='street'] .opacity-40")
|
||||||
|
assert has_element?(view, "[data-testid='house_number'] .opacity-40")
|
||||||
|
assert has_element?(view, "[data-testid='postal_code'] .opacity-40")
|
||||||
|
assert has_element?(view, "[data-testid='phone_number'] .opacity-40")
|
||||||
|
assert has_element?(view, "[data-testid='join_date'] .opacity-40")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "icon state changes correctly when clicking different fields", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, "/members")
|
||||||
|
|
||||||
|
# Start: all fields neutral except first name as default
|
||||||
|
assert has_element?(view, "[data-testid='city'] .opacity-40")
|
||||||
|
refute has_element?(view, "[data-testid='first_name'] .opacity-40")
|
||||||
|
assert has_element?(view, "[data-testid='email'] .opacity-40")
|
||||||
|
|
||||||
|
# Click city - should become active
|
||||||
|
view
|
||||||
|
|> element("button[phx-value-field='city']")
|
||||||
|
|> render_click()
|
||||||
|
|
||||||
|
# city should be active, email should still be neutral
|
||||||
|
refute has_element?(view, "[data-testid='city'] .opacity-40")
|
||||||
|
assert has_element?(view, "[data-testid='email'] .opacity-40")
|
||||||
|
|
||||||
|
# Click email - should switch active field
|
||||||
|
view
|
||||||
|
|> element("button[phx-value-field='email']")
|
||||||
|
|> render_click()
|
||||||
|
|
||||||
|
# email should be active, city should be neutral again
|
||||||
|
refute has_element?(view, "[data-testid='email'] .opacity-40")
|
||||||
|
assert has_element?(view, "[data-testid='city'] .opacity-40")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "specific field shows correct icon for each sort state", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
|
||||||
|
# Test EMAIL field specifically
|
||||||
|
{:ok, view, html_asc} = live(conn, "/members?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")
|
||||||
|
assert html_desc =~ "hero-chevron-down"
|
||||||
|
refute has_element?(view, "[data-testid='email'] .opacity-40")
|
||||||
|
|
||||||
|
{:ok, view, html_neutral} = live(conn, "/members")
|
||||||
|
assert html_neutral =~ "hero-chevron-up-down"
|
||||||
|
assert has_element?(view, "[data-testid='email'] .opacity-40")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "icon distribution is correct for all fields", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
|
||||||
|
# Test neutral state - all fields except first name (default) should show neutral icons
|
||||||
|
{:ok, _view, html_neutral} = live(conn, "/members")
|
||||||
|
|
||||||
|
# Count neutral icons (should be 7 - one for each field)
|
||||||
|
neutral_count = html_neutral |> String.split("hero-chevron-up-down") |> length() |> Kernel.-(1)
|
||||||
|
assert neutral_count == 7
|
||||||
|
|
||||||
|
# Count active icons (should be 1)
|
||||||
|
up_count = html_neutral |> String.split("hero-chevron-up ") |> length() |> Kernel.-(1)
|
||||||
|
down_count = html_neutral |> String.split("hero-chevron-down ") |> length() |> Kernel.-(1)
|
||||||
|
assert up_count == 1
|
||||||
|
assert down_count == 0
|
||||||
|
|
||||||
|
# Test ascending state - one field active, others neutral
|
||||||
|
{:ok, _view, html_asc} = live(conn, "/members?sort_field=first_name&sort_order=asc")
|
||||||
|
|
||||||
|
# Should have exactly 1 ascending icon and 7 neutral icons
|
||||||
|
up_count = html_asc |> String.split("hero-chevron-up ") |> length() |> Kernel.-(1)
|
||||||
|
neutral_count = html_asc |> String.split("hero-chevron-up-down") |> length() |> Kernel.-(1)
|
||||||
|
down_count = html_asc |> String.split("hero-chevron-down ") |> length() |> Kernel.-(1)
|
||||||
|
|
||||||
|
assert up_count == 1
|
||||||
|
assert neutral_count == 7
|
||||||
|
assert down_count == 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Check aria-label for unsorted state
|
||||||
|
assert has_element?(view, "button[phx-value-field='city'][aria-label='Click to sort']")
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Check aria-label for ascending sort
|
||||||
|
assert has_element?(view, "button[phx-value-field='first_name'][aria-label='ascending']")
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Check aria-label for descending sort
|
||||||
|
assert has_element?(view, "button[phx-value-field='first_name'][aria-label='descending']")
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Check that tooltip div exists with correct data-tip
|
||||||
|
assert has_element?(view, "[data-testid='first_name']")
|
||||||
|
assert has_element?(view, "button[phx-value-field='first_name'][aria-label='ascending']")
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Test aria-labels for different fields
|
||||||
|
assert has_element?(view, "button[phx-value-field='email'][aria-label='descending']")
|
||||||
|
assert has_element?(view, "button[phx-value-field='first_name'][aria-label='Click to sort']")
|
||||||
|
assert has_element?(view, "button[phx-value-field='city'][aria-label='Click to sort']")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "component behavior" do
|
||||||
|
test "clicking sends sort message to parent", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, "/members")
|
||||||
|
|
||||||
|
# Click on the first_name sort header
|
||||||
|
view
|
||||||
|
|> element("button[phx-value-field='first_name']")
|
||||||
|
|> render_click()
|
||||||
|
|
||||||
|
# The component should send a message to the parent LiveView
|
||||||
|
# This is tested indirectly through the URL change in integration tests
|
||||||
|
end
|
||||||
|
|
||||||
|
test "component handles different field types correctly", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, "/members")
|
||||||
|
|
||||||
|
# Test that different field types render correctly
|
||||||
|
assert has_element?(view, "button[phx-value-field='first_name']")
|
||||||
|
assert has_element?(view, "button[phx-value-field='email']")
|
||||||
|
assert has_element?(view, "button[phx-value-field='join_date']")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Should not crash and should default sorting for first name
|
||||||
|
assert html =~ "hero-chevron-up-down"
|
||||||
|
refute has_element?(view, "[data-testid='first_name'] .opacity-40")
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Should default to ascending
|
||||||
|
assert html =~ "hero-chevron-up"
|
||||||
|
refute has_element?(view, "[data-testid='first_name'] [aria-label='ascending']")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "handles empty sort parameters", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, html} = live(conn, "/members?sort_field=&sort_order=")
|
||||||
|
|
||||||
|
# Should show neutral icons
|
||||||
|
assert html =~ "hero-chevron-up-down"
|
||||||
|
assert has_element?(view, "[data-testid='city'] .opacity-40")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Start with neutral state
|
||||||
|
assert has_element?(view, "[data-testid='city'] .opacity-40")
|
||||||
|
|
||||||
|
# Click to sort ascending
|
||||||
|
view
|
||||||
|
|> element("button[phx-value-field='city']")
|
||||||
|
|> render_click()
|
||||||
|
|
||||||
|
# Should now be ascending (no opacity class)
|
||||||
|
refute has_element?(view, "[data-testid='city'] .opacity-40")
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Email should be active (descending)
|
||||||
|
assert html =~ "hero-chevron-down"
|
||||||
|
refute has_element?(view, "[data-testid='email'] .opacity-40")
|
||||||
|
|
||||||
|
# Other fields should be neutral
|
||||||
|
assert has_element?(view, "[data-testid='first_name'] .opacity-40")
|
||||||
|
assert has_element?(view, "[data-testid='city'] .opacity-40")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -74,39 +74,132 @@ defmodule MvWeb.MemberLive.IndexTest do
|
||||||
assert has_element?(index_view, "#flash-group", "Member create successfully")
|
assert has_element?(index_view, "#flash-group", "Member create successfully")
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "sorting interaction" do
|
describe "sorting integration" do
|
||||||
test "clicking a column header toggles sort order and updates the URL", %{conn: conn} do
|
test "clicking a column header toggles sort order and updates the URL", %{conn: conn} do
|
||||||
conn = conn_with_oidc_user(conn)
|
conn = conn_with_oidc_user(conn)
|
||||||
{:ok, view, _html} = live(conn, "/members")
|
{:ok, view, _html} = live(conn, "/members")
|
||||||
|
|
||||||
# The component data test ids are built as "<field>"
|
# The component data test ids are built with the name of the field
|
||||||
# First click – should sort ASC
|
# First click – should sort ASC
|
||||||
view
|
view
|
||||||
|> element("[data-testid='email']")
|
|> element("[data-testid='email']")
|
||||||
|> render_click()
|
|> render_click()
|
||||||
|
|
||||||
# The LiveView pushes a patch with the new query params
|
# The LiveView pushes a patch with the new query params
|
||||||
assert_patch(view, "/members?sort_field=email&sort_order=asc")
|
assert_patch(view, "/members?query=&sort_field=email&sort_order=asc")
|
||||||
|
|
||||||
# Second click – toggles to DESC
|
# Second click – toggles to DESC
|
||||||
view
|
view
|
||||||
|> element("[data-testid='email']")
|
|> element("[data-testid='email']")
|
||||||
|> render_click()
|
|> render_click()
|
||||||
|
|
||||||
assert_patch(view, "/members?sort_field=email&sort_order=desc")
|
assert_patch(view, "/members?query=&sort_field=email&sort_order=desc")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "clicking different column header resets order to ascending", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, "/members?sort_field=email&sort_order=desc")
|
||||||
|
|
||||||
|
# Click on a different column
|
||||||
|
view
|
||||||
|
|> element("[data-testid='first_name']")
|
||||||
|
|> render_click()
|
||||||
|
|
||||||
|
assert_patch(view, "/members?query=&sort_field=first_name&sort_order=asc")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "all sortable columns work correctly", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, "/members")
|
||||||
|
|
||||||
|
# default ascending sorting with first name
|
||||||
|
assert has_element?(view, "[data-testid='first_name'][aria-label='ascending']")
|
||||||
|
|
||||||
|
sortable_fields = [:email, :street, :house_number, :postal_code, :city, :phone_number, :join_date]
|
||||||
|
|
||||||
|
for field <- sortable_fields do
|
||||||
|
view
|
||||||
|
|> element("[data-testid='#{field}']")
|
||||||
|
|> render_click()
|
||||||
|
|
||||||
|
assert_patch(view, "/members?query=&sort_field=#{field}&sort_order=asc")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "sorting works with search query", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, "/members?query=test")
|
||||||
|
|
||||||
|
view
|
||||||
|
|> element("[data-testid='email']")
|
||||||
|
|> render_click()
|
||||||
|
|
||||||
|
assert_patch(view, "/members?query=test&sort_field=email&sort_order=asc")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "sorting maintains search query when toggling order", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, "/members?query=test&sort_field=email&sort_order=asc")
|
||||||
|
|
||||||
|
view
|
||||||
|
|> element("[data-testid='email']")
|
||||||
|
|> render_click()
|
||||||
|
|
||||||
|
assert_patch(view, "/members?query=test&sort_field=email&sort_order=desc")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "URL param handling" do
|
describe "URL param handling" do
|
||||||
test "handle_params reads sort query and applies it", %{conn: conn} do
|
test "handle_params reads sort query and applies it", %{conn: conn} do
|
||||||
conn = conn_with_oidc_user(conn)
|
conn = conn_with_oidc_user(conn)
|
||||||
url = "/members?sort_field=email&sort_order=desc"
|
{:ok, view, _html} = live(conn, "/members?query=&sort_field=email&sort_order=desc")
|
||||||
|
|
||||||
conn = get(conn, url)
|
# Check that the sort state is correctly applied
|
||||||
|
assert has_element?(view, "[data-testid='email'][aria-label='descending']")
|
||||||
|
end
|
||||||
|
|
||||||
# The LiveView must have parsed the params and stored them as atoms.
|
test "handle_params handles invalid sort field gracefully", %{conn: conn} do
|
||||||
assert conn.assigns.sort_field == :email
|
conn = conn_with_oidc_user(conn)
|
||||||
assert conn.assigns.sort_order == :desc
|
{:ok, view, _html} = live(conn, "/members?query=&sort_field=invalid_field&sort_order=asc")
|
||||||
|
|
||||||
|
# Should not crash and should show default first name order
|
||||||
|
assert has_element?(view, "[data-testid='first_name'][aria-label='ascending']")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "handle_params preserves search query with sort params", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, "/members?query=test&sort_field=email&sort_order=desc")
|
||||||
|
|
||||||
|
# Both search and sort should be preserved
|
||||||
|
assert has_element?(view, "[data-testid='email'][aria-label='descending']")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "search and sort integration" do
|
||||||
|
test "search maintains sort state", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, "/members?query=&sort_field=email&sort_order=desc")
|
||||||
|
|
||||||
|
# Perform search
|
||||||
|
view
|
||||||
|
|> element("[data-testid='search-input']")
|
||||||
|
|> render_change(%{value: "test"})
|
||||||
|
|
||||||
|
# Sort state should be maintained
|
||||||
|
assert has_element?(view, "[data-testid='email'][aria-label='descending']")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "sort maintains search state", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, "/members?query=test&sort_field=email&sort_order=asc")
|
||||||
|
|
||||||
|
# Perform sort
|
||||||
|
view
|
||||||
|
|> element("[data-testid='email']")
|
||||||
|
|> render_click()
|
||||||
|
|
||||||
|
# Search state should be maintained
|
||||||
|
assert_patch(view, "/members?query=test&sort_field=email&sort_order=desc")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue