Skip to content

Commit

Permalink
preserve order of appended items in stream (#2960)
Browse files Browse the repository at this point in the history
Signed-off-by: Tw <tw19881113@gmail.com>
  • Loading branch information
tw4452852 committed Jan 1, 2024
1 parent 7c65bf5 commit d4f4e0e
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 5 deletions.
9 changes: 4 additions & 5 deletions lib/phoenix_live_view/test/dom.ex
Original file line number Diff line number Diff line change
Expand Up @@ -434,10 +434,9 @@ defmodule Phoenix.LiveViewTest.DOM do
Enum.reduce(stream_inserts, children, fn {id, {ref, insert_at, _limit}}, acc ->
old_index = Enum.find_index(acc, &(attribute(&1, "id") == id))

not_appended? =
is_nil(Enum.find_index(updated_appended, &(attribute(&1, "id") == id)))
appended? = Enum.any?(updated_appended, &(attribute(&1, "id") == id))

existing? = Enum.find_index(updated_existing_children, &(attribute(&1, "id") == id))
existing? = Enum.any?(updated_existing_children, &(attribute(&1, "id") == id))
deleted? = MapSet.member?(stream_deletes, id)

child =
Expand All @@ -453,11 +452,11 @@ defmodule Phoenix.LiveViewTest.DOM do
acc

# skip added children that aren't ours if they are not being appended
not_appended? && parent_id && parent_id != container_id ->
not appended? && parent_id && parent_id != container_id ->
acc

# do not append existing child if already present, only update in place
old_index && insert_at == -1 && existing? ->
old_index && insert_at == -1 && (existing? or appended?) ->
if deleted? do
acc |> List.delete_at(old_index) |> List.insert_at(insert_at, child)
else
Expand Down
8 changes: 8 additions & 0 deletions test/phoenix_live_view/integrations/stream_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,14 @@ defmodule Phoenix.LiveView.StreamTest do
refute lv |> element("#users div") |> has_element?()
end

test "should preserve the order of appended items", %{conn: conn} do
{:ok, lv, _} = live(conn, "/stream")
assert lv |> element("#users div:last-child") |> render =~ "callan"

lv |> render_hook("append-users", %{})
assert lv |> element("#users div:last-child") |> render =~ "last_user"
end

test "stream reset on patch", %{conn: conn} do
{:ok, lv, _html} = live(conn, "/healthy/fruits")

Expand Down
9 changes: 9 additions & 0 deletions test/support/live_views/streams.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ defmodule Phoenix.LiveViewTest.StreamLive do
%{id: 2, name: "callan"}
]

@append_users [
%{id: 4, name: "foo"},
%{id: 3, name: "last_user"},
]

def mount(_params, _session, socket) do
{:ok,
socket
Expand Down Expand Up @@ -88,6 +93,10 @@ defmodule Phoenix.LiveViewTest.StreamLive do
{:noreply, stream(socket, :users, @users)}
end

def handle_event("append-users", _, socket) do
{:noreply, stream(socket, :users, @append_users, at: -1)}
end

def handle_event("admin-delete", %{"id" => dom_id}, socket) do
{:noreply, stream_delete_by_dom_id(socket, :admins, dom_id)}
end
Expand Down

0 comments on commit d4f4e0e

Please sign in to comment.