feat(member): stream the overview with keyset infinite scroll instead of loading every member
This commit is contained in:
parent
b09cdf7f3a
commit
b79d7ac9ea
13 changed files with 1067 additions and 451 deletions
68
test/mv_web/member_live/index_live_region_test.exs
Normal file
68
test/mv_web/member_live/index_live_region_test.exs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
defmodule MvWeb.MemberLive.IndexLiveRegionTest do
|
||||
@moduledoc """
|
||||
§1.9 — The polite live region announces the exact total matching count,
|
||||
computed via a count query for the active filter set.
|
||||
§1.10 — The live region element exists in the DOM before it is filled, and the
|
||||
table region carries `aria-busy`.
|
||||
"""
|
||||
use MvWeb.ConnCase, async: false
|
||||
|
||||
import Phoenix.LiveViewTest
|
||||
|
||||
alias Mv.Helpers.SystemActor
|
||||
|
||||
defp seed(n) do
|
||||
actor = SystemActor.get_system_actor()
|
||||
|
||||
Enum.each(1..n, fn i ->
|
||||
idx = String.pad_leading(Integer.to_string(i), 3, "0")
|
||||
|
||||
{:ok, _} =
|
||||
Mv.Membership.create_member(
|
||||
%{first_name: "Lr#{idx}", last_name: "Region", email: "lr#{idx}@example.com"},
|
||||
actor: actor
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
test "polite live region exists on first render and announces the exact total", %{conn: conn} do
|
||||
seed(60)
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, ~p"/members")
|
||||
|
||||
# Present-before-fill: the live region element is in the initial DOM.
|
||||
assert has_element?(view, "#members-result-count[aria-live='polite']")
|
||||
# Exact total, not the loaded page size (60 matched, only 50 loaded).
|
||||
region = view |> element("#members-result-count") |> render()
|
||||
assert region =~ "60 members"
|
||||
end
|
||||
|
||||
test "table region binds aria-busy to the loading flag (settled after load)", %{conn: conn} do
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, ~p"/members")
|
||||
|
||||
# aria-busy is bound to @loading? (`to_string(@loading?)`), not hardcoded: once
|
||||
# the page has loaded the region is not busy. It is set true across a
|
||||
# filter/sort/search reload patch (push_reload/2, §1.10).
|
||||
assert has_element?(view, "[data-testid='members-table-scroll'][aria-busy='false']")
|
||||
end
|
||||
|
||||
test "count reflects the active filter set, not the whole table", %{conn: conn} do
|
||||
actor = SystemActor.get_system_actor()
|
||||
|
||||
{:ok, _} =
|
||||
Mv.Membership.create_member(
|
||||
%{first_name: "Findme", last_name: "Unique", email: "findme@example.com"},
|
||||
actor: actor
|
||||
)
|
||||
|
||||
seed(5)
|
||||
conn = conn_with_oidc_user(conn)
|
||||
{:ok, view, _html} = live(conn, ~p"/members?query=Findme")
|
||||
|
||||
# Only the single matching member is counted (1 of 6 total).
|
||||
region = view |> element("#members-result-count") |> render()
|
||||
assert region =~ "1 member"
|
||||
refute region =~ "6 member"
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue