feat(member): stream the overview with keyset infinite scroll instead of loading every member

This commit is contained in:
Simon 2026-07-03 11:31:44 +02:00
parent b09cdf7f3a
commit b79d7ac9ea
13 changed files with 1067 additions and 451 deletions

View file

@ -0,0 +1,71 @@
defmodule MvWeb.MemberLive.IndexBulkScopeTest do
@moduledoc """
§1.17 Bulk "all" scope spans the whole filtered set (re-queried from the DB),
not only the loaded/visible page, and the count reflects the full filtered
total.
"""
use MvWeb.ConnCase, async: false
import Phoenix.LiveViewTest
alias Mv.Helpers.SystemActor
# More than one keyset page so "loaded" and "all matching" differ.
@total 60
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: "Bulk#{idx}", last_name: "Scope", email: "bulk#{idx}@example.com"},
actor: actor
)
end)
end
defp scope_badge_text(view) do
view
|> render()
|> LazyHTML.from_fragment()
|> LazyHTML.query(~s([data-testid="bulk-actions-scope-badge"]))
|> LazyHTML.text()
|> String.trim()
end
test "select all selects the whole filtered set, not just the loaded page", %{conn: conn} do
seed(@total)
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, ~p"/members")
view |> element("[phx-click='select_all']") |> render_click()
# The selection count badge reflects all matching members, not the 50 loaded.
assert scope_badge_text(view) == "#{@total}"
end
test "copy-emails with no selection copies every matching member's email", %{conn: conn} do
seed(@total)
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, ~p"/members")
result = render_hook(view, "copy_emails", %{})
# All 60 matching members are copied, not only the 50 loaded rows.
assert result =~ "#{@total}"
end
test "select-all then copy copies the whole filtered set", %{conn: conn} do
seed(@total)
conn = conn_with_oidc_user(conn)
{:ok, view, _html} = live(conn, ~p"/members")
view |> element("[phx-click='select_all']") |> render_click()
result = render_hook(view, "copy_emails", %{})
assert result =~ "#{@total}"
end
end