Starting our channel tests

We'll also want to finish up by writing some appropriate tests for our channels. We'll create test/vocial_web/channels/polls_channel_test.exs and start off by declaring our test module, including the appropriate set of testing macros and alias statements:

defmodule VocialWeb.PollChannelTest do
use VocialWeb.ChannelCase

alias VocialWeb.PollsChannel
end

Similar to our controller tests, we'll also need to create a nice big setup block that will create a user account that we can use:

  setup do
{:ok, user} = Vocial.Accounts.create_user(%{
username: "test",
email: "[email protected]",
password: "test",
password_confirmation: "test"
})

We'll also need to make a pre-created poll:

    {:ok, poll} = Vocial.Votes.create_poll_with_options(
%{ "title" => "My New Test Poll", "user_id" => user.id },
["One", "Two", "Three"]
)

Now, we'll need to create a socket that we can simulate our tests against. Phoenix provides a built-in helper via ChannelCase that allows us to create a fake socket and subscribe to a particular topic (remember that our topic was mapped to a specific poll):

    {:ok, _, socket} =
socket("user_id", %{user_id: user.id})
|> subscribe_and_join(PollsChannel, "polls:#{poll.id}")

Finally, we'll need to return all of that out to let our tests pick and choose which they need:

    {:ok, socket: socket, user: user, poll: poll}
end

The first WebSocket event that we created was our ping event because it was by far the simplest to implement, so let's do that for the first channel test we've ever written:

  test "ping replies with status ok", %{socket: socket} do
ref = push socket, "ping", %{}
assert_reply ref, :ok, %{message: "pong"}
end

We apply pattern matching against the arguments to our test to get the socket out, and then we push a ping message onto that with an empty payload. This returns back to us a reference to the mock socket (you can think of this as our modified conn object from our controller tests, although it's not precisely identical).

We then pattern match our reply, asserting that the ping should respond back with an :ok status and a message of pong! The next test that we're going to have to write, though, is going to be much more complicated, unfortunately. This is the test of our vote, and there's a lot we're going to have to do here to make it work, so let's step through it bit-by-bit to make sure we truly understand it:

test "vote replies with status ok", %{socket: socket, poll: poll} do

We start off by pattern matching our arguments to pull the socket and poll out of the setup block. This will give us a good starting point. Similar to what we did in our controller tests, we'll also want to grab the first option from the poll, and then, similar to our ping WebSocket test, we'll want to simulate a ping message on to the server:

option = Enum.at(poll.options, 0)
ref = push socket, "vote", %{"option_id" => option.id}

Now we'll want to actually verify the reply and the broadcast that we send out as part of the handle_in function for the vote message. This has one very tricky part to it that is very easy to get caught on, so I'll write the code out first and then explain it:

assert_reply ref, :ok, %{"option_id" => option_id, "votes" => votes}
assert option_id == option.id
assert votes == option.votes + 1

assert_reply works by looking for a success or failure message, and then the next statement is not asserting a value; instead, it is assigning new variables (option_id and votes) and those values returned are getting pattern matched into those variables. This is why we have the two extra assertions as follows; we need to verify that the returned option_id and votes values match what we're expecting. We then do the same thing with assert_broadcast, except for this we do not need to use the ref variable we used with assert_reply:

assert_broadcast "new_vote", %{"option_id" => option_id, "votes" => votes}
assert option_id == option.id
assert votes == option.votes + 1

The same rules apply regarding the value/variables as with assert_reply. If you assume that it works like a simple assertion, you will likely end up getting error messages about not being able to invoke remote functions or unused variables!

Run our tests again now that we've written our channel tests! If you've followed everything closely and carefully, you should have a fully-green test suite here!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset