Integration testing Phoenix LiveView apps

What is the best way to do integration testing in phoenix live view, I have tried setting up wallaby but does not to work as expected.

I could use the built-in testing but is there a way I can continue using wallaby with live view?

1 Like

:wave:

What exactly didn’t work? Were there any errors?

My impression is Wallaby still only supports PhantomJS which has been abandoned for a few years now. I think this is a dead-end. I’d love to be corrected though. Hound supports a few other drivers.

At work we use Cypress and I love it. You have to do a little extra work to build test fixtures (we use a shared fixtures controller in test) and to integrate SQL sandboxing, but it is an extremely productive environment for building and debugging E2E tests. After a failure you can inspect all the state - what the screen looked like and all the DOM nodes, what the network payloads were - at every step of the test and usually instantly see where things are going wrong. We haven’t needed their paid product.

4 Likes

Wallaby also supports Chromedriver and Selenium and no longer requires PhantomJS. It still says the support is “experimental” but it works great for me. I found it worked better with JS-heavy pages than Hound but YMMV. Have not tried it with LiveView yet… seems like it should work.

I finaly managed to set this up but the problem is that live view events are not being handled when we send a click event via wallaby

For example when I click on the delete button, it finds the button and click on it but the user is not deleted. The delete event is handled by phoenix live view

2 Likes

Just setup Wallaby today, and the first button I attempted to press was a live_link…
Will try to go with Cypress now.

Is cypress working well for you?

Yes.
I followed this guide: https://medium.com/@svengehring/phoenix-end-to-end-testing-in-real-life-efdba3a85be1
Took me around an hour to get setup and have my first test running.

2 Likes

hi Doerge, did you set it up on an Ecto 2.x or 3.x project? I see the note about it being different, and I’m just going through setting things up now.

I set it up for Ecto3. I think it worked as is, or a with a simple google for the right module api.

1 Like

Would you mind sharing the few changes you made, for the sake of future readers who might want to implement it. I will try set this up later in the week

2 Likes

I used that same article to set up some tests. Very nice, but now I keep getting this problem:

$ MIX_ENV=test mix ecto.reset


2020-06-01 00:58:33.950 CDT [7084] ERROR:  database "app_test" is being accessed by other users
2020-06-01 00:58:33.950 CDT [7084] DETAIL:  There are 10 other sessions using the database.
2020-06-01 00:58:33.950 CDT [7084] STATEMENT:  DROP DATABASE "app_test"
** (Mix) The database for App.Repo couldn't be dropped: ERROR 55006 (object_in_use) database "app_test" is being accessed by other users

There are 10 other sessions using the database.

Hmm. Looks like I’ve done that to myself by not understanding something about mix shortcuts. This problem goes away entirely when I remove the following that I added to my mix.exs file:

      "test.cy": [
        "cmd MIX_ENV=test mix ecto.reset",
        "cmd MIX_ENV=test mix phx.server"
      ]

Running those two commands (omitting cmd) from terminal works fine. Combining them as I have messes up Postgres somehow.

I am using Ecto 3, and I didn’t really change anything from the article. I did, however, add a nice bit of functionality that allows me to specify additional functions to pipe the resulting entity through in the api call.

For example, the Ex Machina docs suggest that you build your factories such that they might be easily piped. For my part, I have set mine up so that I can do something like

build(:user, {first_name: "Don"}) |> with_password("my password") |> insert()

The medium post gives us a way to invoke the call to build/2, but not to pipe that to with_password/2 before finally inserting.

So I changed the post "db/factory" bit to the following (adding all the business about “variations”):

  post "/db/factory" do
    with {:ok, schema} <- Map.fetch(conn.body_params, "schema"),
         {:ok, attrs} <- Map.fetch(conn.body_params, "attributes"),
         {:ok, variations} <- Map.fetch(conn.body_params, "variations") do
      db_schema = String.to_existing_atom(schema)
      db_attrs = Enum.map(attrs, fn {k, v} -> {String.to_existing_atom(k), v} end)
      db_variations = Enum.map(variations, fn [k, v] -> {String.to_existing_atom(k), v} end)

      db_entry =
        Factory.build(db_schema, db_attrs)
        |> do_variations(db_variations)
        |> Factory.insert()

      # I also removed that Poison dependency here by writing the response manually
      send_resp(conn, 200, "{\"id\": #{db_entry.id}}")
    else
      _ -> send_resp(conn, 401, "schema, attributes, or variations missing")
    end
  end

Supporting functions are:

  defp do_variations(db_entity, [variation | rest]) do
    {function_name, args} = variation

    apply(HappyBoxOffice.Factory, function_name, [db_entity | args])
    |> do_variations(rest)
  end

  defp do_variations(db_entity, []) do
    db_entity
  end

Which allows me to call my example code mentioned above via this line in Cypress:

cy.factoryDb("user",
  {first_name: "Don"},
  [
    ["with_password", ["mypassword"] ]
  ]
)

The nesting of arrays allows for any number of piped functions, each with any number of arguments, all culminating in a final insert.

1 Like

Are there known issues remaining with Wallaby with ChromeDriver when testing LiveView?

1 Like

I’ve followed Wallaby’s official docs and have a problem with DB communication. Specifically I’m navigating between static pages (controllers) and when the test gets to the LiveView part then mount gets run twice, but the second time DB seems empty so it crashes. Not sure where to go from here.

I’m fully sure it’s my fault for not understanding how the shared connection thing works.

Make sure you‘re on most recent phoenix_ecto version. The docs include examples on how to make sure liveview uses the sandbox.

Thanks @LostKobrakai. I’ve turned the test to async: false as suggested in an issue [1], now it works. So to answer @marcandre Things seem to be working just fine.

[1] DBConnection.OwnershipError error in async tests (using LiveView) · Issue #489 · elixir-wallaby/wallaby · GitHub