Is the test LiveView immutable or not?

Someone from my Testing LiveView course recently asked me about the immutability of the view we get from live/2 in LiveView tests.

In the test, we clicked on an element, and then we used the open_browser/2 function to debug the test. Imagine something like this:

test "when users click 'Greet', they see a greeting", %{conn: conn} do
  {:ok, view, _html} = live(conn, "/")

  view
  |> element("#greet", "Greet")
  |> render_click()

  # is the `view` here the one before or after the click?
  open_browser(view)
end

Immutability question… we modify the view by clicking on an element… but at that point, the view variable contains the same view as before the click, cause nothing gets assigned to it.

How come the open_browser displays the updated view? I expected it to be in the state before the click because of the explanation above.

That’s an excellent question. Because, to be honest, something smells of mutation, right?

Variables are immutable. Process state isn’t.

The example above is confusing if we think of the view merely as an in-memory LiveView struct. So, when we use element/3 and render_click/2, we believe we’re only performing data transformations like we would with other immutable data.

A render_click/1 action causes a Client Proxy process to send a message to our LiveView process. The LiveView updates its state, and re-renders the HTML, which the Client Proxy holds. Then, an open_browser/1 action causes the Client Proxy to open the HTML in a brower.

But in LiveView tests, the view has a pointer to a client proxy (that acts in place of a browser), which in turn interacts with our LiveView process. So, when we click a button, we’re actually updating the state of the process and re-rendering the HTML.

Thus, even though the view variable is immutable, the LiveView state can change, and therefore, the HTML rendered can change too.

Want my latest thoughts, posts, and projects in your inbox?

    I will never send you spam. Unsubscribe any time.