Skip to content

Commit

Permalink
wip: server initiated handovers
Browse files Browse the repository at this point in the history
TODO: check flash handling
TODO: refactor js to remove duplicatings between replaceMain and handover
TODO: check if should keep the existing view class or replace it completely,
      passing the old channel to the new one?
  • Loading branch information
SteffenDE committed Oct 29, 2024
1 parent 8518e61 commit 2ec6c6a
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 21 deletions.
40 changes: 40 additions & 0 deletions assets/js/phoenix_live_view/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,8 @@ export default class View {
this.onChannel("redirect", ({to, flash}) => this.onRedirect({to, flash}))
this.onChannel("live_patch", (redir) => this.onLivePatch(redir))
this.onChannel("live_redirect", (redir) => this.onLiveRedirect(redir))
this.onChannel("live_handover", (redir) => this.startHandover(redir))
this.onChannel("phx_handover", (payload) => this.completeHandover(payload))
this.channel.onError(reason => this.onError(reason))
this.channel.onClose(reason => this.onClose(reason))
}
Expand All @@ -790,6 +792,44 @@ export default class View {

onRedirect({to, flash, reloadToken}){ this.liveSocket.redirect(to, flash, reloadToken) }

startHandover(redir){
if(!this.isMain()){
throw new Error("unexpected handover for non main view")
}
let {to, kind, _flash} = redir
let href = this.expandURL(to)
let scroll = window.scrollY
this.liveSocket.withPageLoading({to: href, kind}, done => {
// let liveReferer = this.currentLocation.href
let removeEls = DOM.all(this.el, `[${this.binding("remove")}]`)
let newMainEl = DOM.cloneNode(this.el, "")
this.outGoingEl = this.el
this.el = newMainEl
this.showLoader(this.liveSocket.loaderTimeout)

this.setRedirect(href)
this.liveSocket.transitionRemoves(removeEls, true)
this.handoverCallback = () => {
this.stopCallback = function(){}
this.liveSocket.requestDOMUpdate(() => {
// remove phx-remove els right before we replace the main element
removeEls.forEach(el => el.remove())
DOM.findPhxSticky(document).forEach(el => newMainEl.appendChild(el))
this.outGoingEl.replaceWith(this.el)
Browser.pushState(kind, {type: "redirect", id: this.id, scroll: scroll}, href)
DOM.dispatchEvent(window, "phx:navigate", {detail: {href, patch: false, pop: false}})
this.liveSocket.registerNewLocation(window.location)
done()
})
}
})
}

completeHandover(payload){
this.stopCallback = this.handoverCallback
this.onJoin(payload)
}

isDestroyed(){ return this.destroyed }

joinDead(){ this.isDead = true }
Expand Down
107 changes: 86 additions & 21 deletions lib/phoenix_live_view/channel.ex
Original file line number Diff line number Diff line change
Expand Up @@ -848,9 +848,12 @@ defmodule Phoenix.LiveView.Channel do
opts = copy_flash(new_state, flash, opts)

new_state
|> push_pending_events_on_redirect(new_socket)
|> push_live_redirect(opts, ref)
|> stop_shutdown_redirect(:live_redirect, opts)
|> maybe_handover(opts, ref, fn new_state ->
new_state
|> push_pending_events_on_redirect(new_socket)
|> push_live_redirect(opts, ref)
|> stop_shutdown_redirect(:live_redirect, opts)
end)

{:live, :patch, %{to: _to, kind: _kind} = opts} when root_pid == self() ->
{params, action} = patch_params_and_action!(new_socket, opts)
Expand Down Expand Up @@ -1079,6 +1082,34 @@ defmodule Phoenix.LiveView.Channel do
end
end

# handover from previous LV in the same live session
defp mount({:handover, new_verified, route, url, params}, from, phx_socket)
when is_map_key(phx_socket, :handover_pid) and is_pid(phx_socket.handover_pid) and
phx_socket.handover_pid == new_verified.root_pid do
%Phoenix.Socket{private: %{connect_info: connect_info}} = phx_socket
%Session{view: view} = new_verified

new_verified = %{new_verified | root_pid: self()}

case load_live_view(view) do
{:ok, config} ->
verified_mount(
new_verified,
config,
route,
url,
params,
from,
phx_socket,
connect_info
)

{:error, _reason} ->
GenServer.reply(from, {:error, %{reason: "stale"}})
{:stop, :shutdown, :no_state}
end
end

defp mount(%{}, from, phx_socket) do
Logger.error("Mounting #{phx_socket.topic} failed because no session was provided")
GenServer.reply(from, {:error, %{reason: "stale"}})
Expand All @@ -1098,7 +1129,7 @@ defmodule Phoenix.LiveView.Channel do
end

defp verified_mount(
%Session{} = verified,
%Session{} = verified_session,
config,
route,
url,
Expand All @@ -1110,13 +1141,11 @@ defmodule Phoenix.LiveView.Channel do
%Session{
id: id,
view: view,
root_view: root_view,
parent_pid: parent,
root_pid: root_pid,
session: verified_user_session,
assign_new: assign_new,
router: router
} = verified
} = verified_session

%Phoenix.Socket{
endpoint: endpoint,
Expand All @@ -1138,7 +1167,7 @@ defmodule Phoenix.LiveView.Channel do
connect_params = params["params"]

# Optional verified parts
flash = verify_flash(endpoint, verified, params["flash"], connect_params)
flash = verify_flash(endpoint, verified_session, params["flash"], connect_params)

# connect_info is either a Plug.Conn during tests or a Phoenix.Socket map
socket_session = Map.get(connect_info, :session, %{})
Expand Down Expand Up @@ -1169,9 +1198,7 @@ defmodule Phoenix.LiveView.Channel do
lifecycle = load_lifecycle(config, route)

case mount_private(
parent,
root_view,
assign_new,
verified_session,
connect_params,
connect_info,
lifecycle,
Expand All @@ -1186,7 +1213,7 @@ defmodule Phoenix.LiveView.Channel do
|> Utils.maybe_call_live_view_mount!(view, params, merged_session, url)
|> build_state(phx_socket)
|> maybe_call_mount_handle_params(router, url, params)
|> reply_mount(from, verified, route)
|> reply_mount(from, verified_session, route)
|> maybe_subscribe_to_live_reload()
rescue
exception ->
Expand Down Expand Up @@ -1267,16 +1294,16 @@ defmodule Phoenix.LiveView.Channel do
end

defp mount_private(
nil,
root_view,
assign_new,
%Session{parent_pid: nil, root_view: root_view, assign_new: assign_new} =
verified_session,
connect_params,
connect_info,
lifecycle,
handover_pid
) do
{:ok,
%{
verified_session: verified_session,
connect_params: connect_params,
connect_info: connect_info,
assign_new: {%{}, assign_new},
Expand All @@ -1288,19 +1315,19 @@ defmodule Phoenix.LiveView.Channel do
end

defp mount_private(
parent,
root_view,
assign_new,
%Session{parent_pid: parent_pid, root_view: root_view, assign_new: assign_new} =
verified_session,
connect_params,
connect_info,
lifecycle,
_handover_pid
) do
case get_assigns(parent, assign_new) do
case get_assigns(parent_pid, assign_new) do
{:ok, parent_assigns} ->
# Child live views always ignore the layout on `:use`.
{:ok,
%{
verified_session: verified_session,
connect_params: connect_params,
connect_info: connect_info,
assign_new: {parent_assigns, assign_new},
Expand Down Expand Up @@ -1366,8 +1393,10 @@ defmodule Phoenix.LiveView.Channel do
{:noreply, post_verified_mount(new_state)}

{:live_redirect, opts, new_state} ->
GenServer.reply(from, {:error, %{live_redirect: opts}})
{:stop, :shutdown, new_state}
maybe_handover(new_state, opts, nil, fn new_state ->
GenServer.reply(from, {:error, %{live_redirect: opts}})
{:stop, :shutdown, new_state}
end)

{:redirect, opts, new_state} ->
GenServer.reply(from, {:error, %{redirect: opts}})
Expand Down Expand Up @@ -1609,4 +1638,40 @@ defmodule Phoenix.LiveView.Channel do
%{}
end
end

defp handover? do
phoenix_vsn = to_string(Application.spec(:phoenix)[:vsn])
Version.match?(phoenix_vsn, ">= 1.8.0-dev")
end

defp maybe_handover(state, redirect_opts, ref, fallback) do
%{socket: %{parent_pid: parent, private: %{verified_session: session}} = socket} = state
%{to: to} = redirect_opts
# get the full uri to verify the new session
destructure [path, query], :binary.split(to, "?")
to = %{socket.host_uri | path: path, query: query}
params = (query && Plug.Conn.Query.decode(query)) || %{}

if diff = Diff.get_push_events_diff(socket), do: push_diff(state, diff, ref)

# we can only handover on Phoenix >= 1.8.0 and when we are mounted at the router
with true <- handover?(),
nil <- parent,
{:ok, new_verified, route, url} <-
authorize_session(
session,
socket.endpoint,
%{"redirect" => to}
) do
%{topic: topic, join_ref: join_ref} = state
state = push(state, "live_handover", redirect_opts)

msg_payload = {:handover, new_verified, route, url, params}
send(socket.transport_pid, {:handover, msg_payload, self(), topic, join_ref})

{:noreply, state}
else
_ -> fallback.(state)
end
end
end
20 changes: 20 additions & 0 deletions test/e2e/support/navigation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ defmodule Phoenix.LiveViewTest.E2E.Navigation.ALive do
|> then(&{:noreply, &1})
end

@impl Phoenix.LiveView
def handle_event("push_navigate", _params, socket) do
{:noreply, push_navigate(socket, to: "/navigation/b")}
end

@impl Phoenix.LiveView
def render(assigns) do
~H"""
Expand All @@ -81,6 +86,8 @@ defmodule Phoenix.LiveViewTest.E2E.Navigation.ALive do
<.styled_link patch={"/navigation/a?param=#{@param_next}"}>Patch this LiveView</.styled_link>
<.styled_link patch={"/navigation/a?param=#{@param_next}"} replace>Patch (Replace)</.styled_link>
<.styled_link navigate="/navigation/b#items-item-42">Navigate to 42</.styled_link>
<.styled_link phx-click="push_navigate">push_navigate</.styled_link>
"""
end

Expand Down Expand Up @@ -127,12 +134,25 @@ defmodule Phoenix.LiveViewTest.E2E.Navigation.BLive do
assign(socket, :id, id)
end

@impl Phoenix.LiveView
def handle_event("push_navigate", _params, socket) do
{:noreply, push_navigate(socket, to: "/navigation/a")}
end

@impl Phoenix.LiveView
def render(assigns) do
~H"""
<h1>This is page B</h1>
<p>Foo: <%= @foo %></p>
<a
href="#"
phx-click="push_navigate"
style="margin-bottom: 8px; padding-left: 1rem; padding-right: 1rem; padding-top: 0.5rem; padding-bottom: 0.5rem; background-color: #e2e8f0; display: inline-flex; align-items: center; border-radius: 0.375rem; cursor: pointer;"
>
push_navigate
</a>
<a
href="#items-item-42"
style="margin-bottom: 8px; padding-left: 1rem; padding-right: 1rem; padding-top: 0.5rem; padding-bottom: 0.5rem; background-color: #e2e8f0; display: inline-flex; align-items: center; border-radius: 0.375rem; cursor: pointer;"
Expand Down
22 changes: 22 additions & 0 deletions test/e2e/tests/navigation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,34 @@ test("sharing assigns between live navigation", async ({ page }) => {
await expect(page.getByText("Foo:")).toContainText("bar");
await page.getByRole("link", { name: "LiveView B" }).click();
await syncLV(page);
await expect(page).toHaveURL("/navigation/b");
await expect(page.getByText("Foo:")).toContainText("bar");

await page.reload();
await syncLV(page);
await expect(page.getByText("Foo:")).toContainText("baz");
await page.getByRole("link", { name: "LiveView A" }).click();
await syncLV(page);
await expect(page).toHaveURL("/navigation/a");
await expect(page.getByText("Foo:")).toContainText("baz");
});

test("sharing assigns between live navigation (push_navigate)", async ({ page }) => {
await page.goto("/navigation/a");
await syncLV(page);

await expect(page.getByText("Foo:")).toContainText("bar");
await page.getByRole("link", { name: "push_navigate" }).click();
await syncLV(page);
await expect(page).toHaveURL("/navigation/b");

Check failure on line 267 in test/e2e/tests/navigation.spec.js

View workflow job for this annotation

GitHub Actions / e2e test (1.17.2, 27)

[chromium] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate)

2) [chromium] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate) Error: Timed out 5000ms waiting for expect(locator).toHaveURL(expected) Locator: locator(':root') Expected string: "http://localhost:4004/navigation/b" Received string: "http://localhost:4004/navigation/a" Call log: - expect.toHaveURL with timeout 5000ms - waiting for locator(':root') - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" 265 | await page.getByRole("link", { name: "push_navigate" }).click(); 266 | await syncLV(page); > 267 | await expect(page).toHaveURL("/navigation/b"); | ^ 268 | await expect(page.getByText("Foo:")).toContainText("bar"); 269 | 270 | await page.reload(); at /__w/phoenix_live_view/phoenix_live_view/test/e2e/tests/navigation.spec.js:267:22

Check failure on line 267 in test/e2e/tests/navigation.spec.js

View workflow job for this annotation

GitHub Actions / e2e test (1.17.2, 27)

[chromium] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate)

2) [chromium] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate) Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: Timed out 5000ms waiting for expect(locator).toHaveURL(expected) Locator: locator(':root') Expected string: "http://localhost:4004/navigation/b" Received string: "http://localhost:4004/navigation/a" Call log: - expect.toHaveURL with timeout 5000ms - waiting for locator(':root') - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" 265 | await page.getByRole("link", { name: "push_navigate" }).click(); 266 | await syncLV(page); > 267 | await expect(page).toHaveURL("/navigation/b"); | ^ 268 | await expect(page.getByText("Foo:")).toContainText("bar"); 269 | 270 | await page.reload(); at /__w/phoenix_live_view/phoenix_live_view/test/e2e/tests/navigation.spec.js:267:22

Check failure on line 267 in test/e2e/tests/navigation.spec.js

View workflow job for this annotation

GitHub Actions / e2e test (1.17.2, 27)

[chromium] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate)

2) [chromium] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate) Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: Timed out 5000ms waiting for expect(locator).toHaveURL(expected) Locator: locator(':root') Expected string: "http://localhost:4004/navigation/b" Received string: "http://localhost:4004/navigation/a" Call log: - expect.toHaveURL with timeout 5000ms - waiting for locator(':root') - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" 265 | await page.getByRole("link", { name: "push_navigate" }).click(); 266 | await syncLV(page); > 267 | await expect(page).toHaveURL("/navigation/b"); | ^ 268 | await expect(page.getByText("Foo:")).toContainText("bar"); 269 | 270 | await page.reload(); at /__w/phoenix_live_view/phoenix_live_view/test/e2e/tests/navigation.spec.js:267:22

Check failure on line 267 in test/e2e/tests/navigation.spec.js

View workflow job for this annotation

GitHub Actions / e2e test (1.17.2, 27)

[firefox] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate)

4) [firefox] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate) Error: Timed out 5000ms waiting for expect(locator).toHaveURL(expected) Locator: locator(':root') Expected string: "http://localhost:4004/navigation/b" Received string: "http://localhost:4004/navigation/a" Call log: - expect.toHaveURL with timeout 5000ms - waiting for locator(':root') - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" 265 | await page.getByRole("link", { name: "push_navigate" }).click(); 266 | await syncLV(page); > 267 | await expect(page).toHaveURL("/navigation/b"); | ^ 268 | await expect(page.getByText("Foo:")).toContainText("bar"); 269 | 270 | await page.reload(); at /__w/phoenix_live_view/phoenix_live_view/test/e2e/tests/navigation.spec.js:267:22

Check failure on line 267 in test/e2e/tests/navigation.spec.js

View workflow job for this annotation

GitHub Actions / e2e test (1.17.2, 27)

[chromium] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate)

2) [chromium] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate) Error: Timed out 5000ms waiting for expect(locator).toHaveURL(expected) Locator: locator(':root') Expected string: "http://localhost:4004/navigation/b" Received string: "http://localhost:4004/navigation/a" Call log: - expect.toHaveURL with timeout 5000ms - waiting for locator(':root') - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" 265 | await page.getByRole("link", { name: "push_navigate" }).click(); 266 | await syncLV(page); > 267 | await expect(page).toHaveURL("/navigation/b"); | ^ 268 | await expect(page.getByText("Foo:")).toContainText("bar"); 269 | 270 | await page.reload(); at /__w/phoenix_live_view/phoenix_live_view/test/e2e/tests/navigation.spec.js:267:22

Check failure on line 267 in test/e2e/tests/navigation.spec.js

View workflow job for this annotation

GitHub Actions / e2e test (1.17.2, 27)

[chromium] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate)

2) [chromium] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate) Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: Timed out 5000ms waiting for expect(locator).toHaveURL(expected) Locator: locator(':root') Expected string: "http://localhost:4004/navigation/b" Received string: "http://localhost:4004/navigation/a" Call log: - expect.toHaveURL with timeout 5000ms - waiting for locator(':root') - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" 265 | await page.getByRole("link", { name: "push_navigate" }).click(); 266 | await syncLV(page); > 267 | await expect(page).toHaveURL("/navigation/b"); | ^ 268 | await expect(page.getByText("Foo:")).toContainText("bar"); 269 | 270 | await page.reload(); at /__w/phoenix_live_view/phoenix_live_view/test/e2e/tests/navigation.spec.js:267:22

Check failure on line 267 in test/e2e/tests/navigation.spec.js

View workflow job for this annotation

GitHub Actions / e2e test (1.17.2, 27)

[chromium] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate)

2) [chromium] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate) Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: Timed out 5000ms waiting for expect(locator).toHaveURL(expected) Locator: locator(':root') Expected string: "http://localhost:4004/navigation/b" Received string: "http://localhost:4004/navigation/a" Call log: - expect.toHaveURL with timeout 5000ms - waiting for locator(':root') - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" 265 | await page.getByRole("link", { name: "push_navigate" }).click(); 266 | await syncLV(page); > 267 | await expect(page).toHaveURL("/navigation/b"); | ^ 268 | await expect(page.getByText("Foo:")).toContainText("bar"); 269 | 270 | await page.reload(); at /__w/phoenix_live_view/phoenix_live_view/test/e2e/tests/navigation.spec.js:267:22

Check failure on line 267 in test/e2e/tests/navigation.spec.js

View workflow job for this annotation

GitHub Actions / e2e test (1.17.2, 27)

[firefox] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate)

4) [firefox] › tests/navigation.spec.js:260:1 › sharing assigns between live navigation (push_navigate) Error: Timed out 5000ms waiting for expect(locator).toHaveURL(expected) Locator: locator(':root') Expected string: "http://localhost:4004/navigation/b" Received string: "http://localhost:4004/navigation/a" Call log: - expect.toHaveURL with timeout 5000ms - waiting for locator(':root') - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" - locator resolved to <html>…</html> - unexpected value "http://localhost:4004/navigation/a" 265 | await page.getByRole("link", { name: "push_navigate" }).click(); 266 | await syncLV(page); > 267 | await expect(page).toHaveURL("/navigation/b"); | ^ 268 | await expect(page.getByText("Foo:")).toContainText("bar"); 269 | 270 | await page.reload(); at /__w/phoenix_live_view/phoenix_live_view/test/e2e/tests/navigation.spec.js:267:22
await expect(page.getByText("Foo:")).toContainText("bar");

await page.reload();
await syncLV(page);
await expect(page.getByText("Foo:")).toContainText("baz");
await page.getByRole("link", { name: "push_navigate" }).click();
await syncLV(page);
await expect(page).toHaveURL("/navigation/a");

await expect(page.getByText("Foo:")).toContainText("baz");
});

0 comments on commit 2ec6c6a

Please sign in to comment.