Application.put_env(:phoenix, Example.Endpoint,
http: [ip: {127, 0, 0, 1}, port: 5001],
server: true,
live_view: [signing_salt: "aaaaaaaa"],
secret_key_base: String.duplicate("a", 64)
)
Mix.install([
{:plug_cowboy, "~> 2.5"},
{:jason, "~> 1.0"},
{:phoenix, "~> 1.7.10", override: true},
{:phoenix_live_view, "0.20.2"},
{:floki, ">= 0.30.0"}
])
ExUnit.start()
defmodule Example.ErrorView do
def render(template, _), do: Phoenix.Controller.status_message_from_template(template)
end
defmodule Example.HomeLive do
use Phoenix.LiveView, layout: {__MODULE__, :live}
def mount(_params, _session, socket) do
socket
|> stream(:items, [
%{id: "a", name: "A"},
%{id: "b", name: "B"},
%{id: "c", name: "C"},
%{id: "d", name: "D"}
])
|> then(&{:ok, &1})
end
def handle_event("reorder", _, socket) do
{:noreply,
stream(
socket,
:items,
[
%{id: "e", name: "E"},
%{id: "a", name: "A"},
%{id: "f", name: "F"},
%{id: "g", name: "G"}
],
reset: true
)}
end
def render("live.html", assigns) do
~H"""
<script src="https://cdn.jsdelivr.net/npm/phoenix@1.7.10/priv/static/phoenix.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/phoenixframework/phoenix_live_view@0.20.2/priv/static/phoenix_live_view.js"></script>
<script>
let liveSocket = new window.LiveView.LiveSocket("/live", window.Phoenix.Socket, {
hooks: {
FakeHook: {
mounted() {}
}
}
})
liveSocket.connect()
</script>
<style>
* { font-size: 1.1em; }
</style>
<%= @inner_content %>
"""
end
def render(assigns) do
~H"""
<ul phx-update="stream" id="thelist">
<li id={id} :for={{id, item} <- @streams.items}>
<%= item.name %>
</li>
</ul>
<button phx-click="reorder">Reorder</button>
"""
end
end
defmodule Example.Router do
use Phoenix.Router
import Phoenix.LiveView.Router
pipeline :browser do
plug(:accepts, ["html"])
end
scope "/", Example do
pipe_through(:browser)
live("/", HomeLive, :index)
end
end
defmodule Example.Endpoint do
use Phoenix.Endpoint, otp_app: :phoenix
socket("/live", Phoenix.LiveView.Socket)
plug(Example.Router)
end
defmodule Example.HomeLiveTest do
use ExUnit.Case
import Phoenix.ConnTest
import Plug.Conn
import Phoenix.LiveViewTest
@endpoint Example.Endpoint
test "works properly" do
conn = Phoenix.ConnTest.build_conn()
{:ok, live, html} = live(conn, "/")
assert Floki.parse(html)
|> Floki.find("ul")
|> Floki.find("li")
|> Enum.map(fn html ->
html |> Floki.text() |> String.trim()
end) == ["A", "B", "C", "D"]
assert html =
live
|> element("button")
|> render_click()
assert Floki.parse(html)
|> Floki.find("ul")
|> Floki.find("li")
|> Enum.map(fn html ->
html |> Floki.text() |> String.trim()
end) == ["E", "A", "F", "G"]
end
end
{:ok, _} = Supervisor.start_link([Example.Endpoint], strategy: :one_for_one)
ExUnit.run()
Process.sleep(:infinity)
Note that we initialize a stream of items as [a, b, c, d] and later reset the stream to [e, a, f, g]. With LV 0.20.2 (and main) the stream is reset as [a, e, f, g] instead.
Environment
Actual behavior
File to reproduce:
Note that we initialize a stream of items as [a, b, c, d] and later reset the stream to [e, a, f, g]. With LV 0.20.2 (and main) the stream is reset as [a, e, f, g] instead.
Expected behavior
The test should pass. This is interesting because now the test clients shows the same broken behaviour that I am trying to fix for the real client in https://github.com/phoenixframework/phoenix_live_view/pull/2969