96 lines
3.1 KiB
Elixir
96 lines
3.1 KiB
Elixir
defmodule MvWeb.MemberLive.IndexPaginationTest do
|
|
@moduledoc """
|
|
§1.7 — Mount loads only one keyset page, not the whole table.
|
|
§1.8 — phx-viewport-bottom fetches and appends the next page; once the last
|
|
page is reached no further fetch is issued.
|
|
"""
|
|
use MvWeb.ConnCase, async: false
|
|
|
|
import Phoenix.LiveViewTest
|
|
|
|
require Ash.Query
|
|
|
|
alias Mv.Helpers.SystemActor
|
|
|
|
# Matches the :overview default_limit / @page_limit in the LiveView.
|
|
@page_limit 50
|
|
|
|
defp seed_members(n) do
|
|
actor = SystemActor.get_system_actor()
|
|
|
|
Enum.each(1..n, fn i ->
|
|
# Zero-padded names keep first_name-ascending order deterministic.
|
|
idx = String.pad_leading(Integer.to_string(i), 4, "0")
|
|
|
|
{:ok, _} =
|
|
Mv.Membership.create_member(
|
|
%{first_name: "Page#{idx}", last_name: "Member", email: "page#{idx}@example.com"},
|
|
actor: actor
|
|
)
|
|
end)
|
|
end
|
|
|
|
defp row_count(html) do
|
|
~r/<tr[^>]*id="row-/ |> Regex.scan(html) |> length()
|
|
end
|
|
|
|
test "mount loads exactly one page when more members exist", %{conn: conn} do
|
|
seed_members(@page_limit + 10)
|
|
conn = conn_with_oidc_user(conn)
|
|
{:ok, _view, html} = live(conn, ~p"/members")
|
|
|
|
assert row_count(html) == @page_limit
|
|
# More rows remain, so the infinite-scroll sentinel is armed.
|
|
assert html =~ ~s(phx-viewport-bottom="load_more")
|
|
end
|
|
|
|
test "viewport-bottom appends the next page and stops at the last page", %{conn: conn} do
|
|
seed_members(@page_limit + 10)
|
|
conn = conn_with_oidc_user(conn)
|
|
{:ok, view, html} = live(conn, ~p"/members")
|
|
|
|
assert row_count(html) == @page_limit
|
|
|
|
# Fetch the next page: the remaining rows are appended to the stream.
|
|
html_after = render_hook(view, "load_more", %{})
|
|
assert row_count(html_after) == @page_limit + 10
|
|
|
|
# Last page reached: the sentinel is disarmed and a further fetch is a no-op.
|
|
refute html_after =~ ~s(phx-viewport-bottom="load_more")
|
|
html_again = render_hook(view, "load_more", %{})
|
|
assert row_count(html_again) == @page_limit + 10
|
|
end
|
|
|
|
test "selecting a row from a later page re-renders it as checked", %{conn: conn} do
|
|
seed_members(@page_limit + 10)
|
|
conn = conn_with_oidc_user(conn)
|
|
{:ok, view, _html} = live(conn, ~p"/members")
|
|
|
|
# Load the second page so its rows are in the loaded window.
|
|
render_hook(view, "load_more", %{})
|
|
|
|
# The highest-index member sorts last and lives on the second page.
|
|
actor = SystemActor.get_system_actor()
|
|
|
|
last_member =
|
|
Mv.Membership.Member
|
|
|> Ash.Query.sort(first_name: :asc)
|
|
|> Ash.read!(actor: actor)
|
|
|> List.last()
|
|
|
|
html = render_click(view, "select_member", %{"id" => last_member.id})
|
|
|
|
# The re-streamed row for a later-page member reflects the selection.
|
|
assert html =~ ~s(id="row-#{last_member.id}")
|
|
assert has_element?(view, ~s(tr#row-#{last_member.id} input[type="checkbox"][checked]))
|
|
end
|
|
|
|
test "single page does not arm the infinite-scroll sentinel", %{conn: conn} do
|
|
seed_members(3)
|
|
conn = conn_with_oidc_user(conn)
|
|
{:ok, _view, html} = live(conn, ~p"/members")
|
|
|
|
assert row_count(html) == 3
|
|
refute html =~ ~s(phx-viewport-bottom="load_more")
|
|
end
|
|
end
|