I have a channel which I'm using to push messages to the client when carrying out some kind of sync:
defmodule AppWeb.SyncChannel do
use AppWeb, :channel
def join("sync:database", _payload, socket) do
send(self(), {:sync, :database})
{:ok, socket}
end
def handle_info({:sync, :database}, socket) do
Process.sleep(2000)
push(socket, "one", %{})
Process.sleep(2000)
push(socket, "two", %{})
Process.sleep(2000)
push(socket, "three", %{})
{:noreply, socket}
end
end
I have a test for this channel:
defmodule AppWeb.SyncChannelTest do
use AppWeb.ChannelCase, async: false
alias AppWeb.SyncChannel
describe "sync:database" do
setup do
{:ok, _, socket} = subscribe_and_join(socket(), SyncChannel, "sync:database")
{:ok, socket: socket}
end
test "socket pushes 3 messages", %{socket: _socket} do
assert_push("one", %{})
assert_push("two", %{})
assert_push("three", %{})
end
end
end
But when I run the tests, I am getting the error:
Compiling 1 file (.ex)
...
1) test sync:database socket pushes 3 messages (AppWeb.SyncChannelTest)
test/app_web/channels/sync_channel_test.exs:13
** (exit) exited in: GenServer.call(#PID<0.478.0>, :socket, 5000)
** (EXIT) time out
stacktrace:
(elixir) lib/gen_server.ex:830: GenServer.call/3
(phoenix) lib/phoenix/test/channel_test.ex:360: Phoenix.ChannelTest.join/4
test/app_web/channels/sync_channel_test.exs:8: AppWeb.SyncChannelTest.__ex_unit_setup_1/1
test/app_web/channels/sync_channel_test.exs:1: AppWeb.SyncChannelTest.__ex_unit__/2
.
Finished in 5.2 seconds
5 tests, 1 failure
Randomized with seed 119011
How can I configure the channel timeout in my tests so that handle_info
function is able to run for more than the default 5 seconds.
I have tried looking to configure this in the config/
files, without joy and also in the app_web/channels/user_socket.ex
, but again I can't find anywhere specify a timeout
Phoenix.ChannelTest.join
calls Phoenix.Channel.Server.socket/1
which makes a GenServer call to the channel with no configurable timeout to get the underlying socket from the GenServer's state. I believe since you send a message to self from your join
function, that message is processed by the GenServer before the test code is able to get the socket value and since that call has the default timeout of 5 seconds, you get this timeout error.
A workaround for this would be to slightly delay the send
to self
using Process.send_after/3
:
Process.send_after(self(), {:sync, :database}, 100)
You'll also need to increase the timeout of assert_push
calls as the timeout defaults to 100ms while your messages arrive upto around 6 seconds later.
assert_push ..., ..., 10000
Again, Process.send_after/3
is just a workaround. Someone more knowledgeable might be able to provide a real solution.