gianthamster

gianthamster

Accessing assigns in LiveView test?

I’m working on a multiple-choice quiz application that uses LiveView for its interface. The questions are randomly selected from a larger set, and then stored in the socket’s assigns, along with their answers.

When testing the LiveView, I’d like to look at a question contained in the assigns (and along with it, its answer), so I can then test what happens when a right answer or wrong answer is selected by the user. However, I don’t see an easy way to access the socket and its assigns from the test case itself – just the HTML of the rendered view.

Am I missing a simple way to get at socket.assigns in a Phoenix.LiveViewTest, or will I need to mock the quiz interface so it always returns something non-random in the test environment?

Marked As Solved

crisefd

crisefd

Isn’t the socket’s assigns avaiable from conn object ?

Also Liked

chrismccord

chrismccord

Creator of Phoenix

Note that you should test the results of the LV rendered content rather than the assigns. Reaching into the assigns is internal state and will lead to a brittle test. So using the render_* functions and asserting on the expected side effects is the way to go :slight_smile:

13
Post #5
gianthamster

gianthamster

Interesting. The conn before the {:ok, view, html} = live(conn, "/quiz/") call has empty assigns, and the live(conn, "/quiz/") call doesn’t return an updated conn, just the view and the rendered html, so I was going to say the conn object wasn’t even available to the test.

But if I break up the call to live by doing a conn = get(conn, "/quiz") followed by {:ok, view, html} = live(conn), then that intermediate conn does indeed have the data I’m looking for in its assigns.

Thanks for the poke, I’d been assuming conn.assigns both wasn’t available and wasn’t related to the socket.assigns anyway.

I’m still not sure how to access the assigns later on, after they’ve been changed by some handle_event calls, but that doesn’t matter for this test.

gianthamster

gianthamster

I do get that the structure of assigns is a lot more likely to change than the contents of the view, and that other people working on the same code might not expect the tests to depend on the structure of assigns. But since we’re here, here’s my passing test:

  test "correct answer clicked", %{conn: conn} do
    conn = get(conn, "/quiz")
    {:ok, view, _html} = live(conn) 

    correct_answer = conn.assigns.correct_answer
    expected = "Congratulations! You got it right!"

    assert render_click(view, :answer, %{option: correct_answer}) =~ expected
  end

The value of correct_answer is determined by a quiz-generating call during the mount and is completely random – while the answer to ‘What sound does a cat make?’ will always be ‘Meow’, sometimes that’ll be the first answer, sometimes that’ll be the second answer, etc.

I don’t consider myself particularly skilled here, so this is my chance to learn something – instead of doing what I’ve done, how would you test something like this? Mock the quiz-generating function? Pass an anonymous answer-sorting function to the quiz-generating function as a variable, and use a deterministic one in test? Click on every link, add up the results, and assert that the ‘correct answer’ result happened once and only once? Change the implementation so the correct answer isn’t in the assigns at all, but fetched from the backend after every answer? I considered all of these instead of dipping into the assigns, but didn’t love any of them – the increased complexity didn’t seem worth it.

Last Post!

EasterPeanut

EasterPeanut

For anyone reaching this forum post because they wanted to test a part of a LiveView / Live Component, for example the ‘handle_event/3’ implementation, this is how I wrote one of my tests:

    test "raises an error if user is not authorized to delete the upload",
         %{conn: conn, user: user} do
      recipe = insert(:recipe, status: :draft, author: user, cover_image: insert(:cover_image))

      socket = %Phoenix.Socket{} |> Phoenix.Socket.assign(recipe: recipe)

      assert_raise MyApp.Media.NotAuthorizedError, "not authorized", fn ->
        BadgerWeb.Recipes.CoverImageUploadComponent.handle_event("delete-upload", %{}, socket)
      end
    end

Where Next?

Popular in Questions Top

lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement