How to test in LiveSvelte?

Hello everyone :wave:. So i was doing some searches about LiveSvelte project, an awesome project by the way, but i had a question though: What about testing?

So live view comes with a bunch of macros for test, you can assert that a view rendered offline or connected, assert that after click event the view was redirect and much more, but when using live svelte your ui is driven mostly on “Svelte side”, so how would i test the code? Should i just ignore this live view ready to go test infrastructure and do svelte tests ? Have you guys had such experience with this or even know some example project that uses LiveSvelte and has tests?

Hope it was clear enough, thanks mates :saluting_face: :handshake:

The topic seems important, I was surprised no one in the repository continued this discussion How to test components using live_svelte · woutdp/live_svelte · Discussion #160 · GitHub. Completed with the error examples

I would be glad if someone could share some advice

I’m copying here my response from the discussion in the live_svelte repository

I migrated a part of LiveView to live_svelte and encountered errors in tests with LiveViewTest. Can someone share an approach to testing? testing is the biggest challenge for me so far

I made an example that shows the error

Branch

git clone -b live_svetle_test_demo https://github.com/ravecat/runa.git

Run

mix setup
mix test.only

During development everything is great and the transition was almost painless, however when testing I get an error (Attempting to reconnect)


just migrated the test environment for the client side to wallaby, keep it for the history here

Hi, I’m the creator of LiveVue library heavily inspired by LiveSvelte.

I can add 2cents from my side, there are two valid approaches to testing:

  1. Easier, test rendered props passed to svelte component
  2. Harder, proper end to end tests with Wallaby etc.

Approach 2 is kinda obvious, and gives you the most value but with significant initial investment.

But, I wanted to explain a bit more about 1). In LiveSvelte props are rendered simply in data-props attribute of a LiveSvelte root element. So it should be fairly trivial to decode them. Something along the lines (extracted from LiveVue version):

def get_svelte(html, opts) when is_binary(html) do
    if Code.ensure_loaded?(Floki) do
      svelte =
        html
        |> Floki.parse_document!()
        |> Floki.find("[phx-hook='SvelteHook']")
        # TODO - handle cases when there are more than 1 component
        |> List.first()

      %{
        props: Jason.decode!(attr(svelte, "data-props")),
        component: attr(svelte, "data-name"),
        id: attr(svelte, "id"),
        ssr: attr(svelte, "data-ssr") |> String.to_existing_atom(),
        class: attr(svelte, "class")
      }
    else
      raise "Floki is not installed. Add {:floki, \">= 0.30.0\", only: :test} to your dependencies"
    end
  end

Then, you can make assertions on these props, in the same way as you’d be testing a normal LiveView application.

test "test render", %{conn: conn} do
    {:ok, view, html} = live(conn, "/")
    %{props: props} = get_svelte(html)
    assert props["statement"] == "I love Svelte and Vue"

    html = render_hook(view, "randomize", %{}) 
    %{props: props} = get_svelte(html)
    assert props["statement"] == "I love Elixir"
end

This simple approach let’s you test all the updates inside the Live process, and check if rendered props are what you’d expect. Obviously it’s not checking actual rendered HTML, event handlers etc, but often it’s a good tradeoff.

Maybe @woutdp would be willing to incorporate such a helper inside LiveSvelte as well? :wink:

2 Likes

Thanks for the comment, but I expect the testing to just test the actual html and handlers. Tying tests to framemork attributes is a so-so idea in my opinion

1 Like

Well, it’s basically a valid way to get up-to-date props of your svelte component. All the rest happens on the client-side.

It already allows you to test your whole view - mounting, handling various events and asserting on props passed down to your svelte component. If you’ll throw SSR to the mix you’ll be able to assert on rendered HTML as well. For some developers this might be a good tradeoff between complexity and brittleness of headless browser tests.

But yeah, that way you won’t be able to test eg button clicks or client-side state. For that you have to use Wallaby or similar, as you’re already doing.

Regarding your issue with “Attempting to reconnect” - this is always rendered by your flash_group core component, just not visible. Then client-side phoenix code shows and hides it on websocket connect and disconnect, like this:

      <.flash
        id="client-error"
        kind={:error}
        title="We can't find the internet"
        phx-disconnected={show(".phx-client-error #client-error")}
        phx-connected={hide("#client-error")}
        hidden
      >
        Attempting to reconnect <.icon name="hero-arrow-path" class="ml-1 h-3 w-3 animate-spin" />
      </.flash>

In other words, it’s always present in HTML returned by your view, as long as you use flash_group in your app.html.heex. Hope this helps :+1: