towerops/test/towerops_web/channels/mobile_socket_test.exs
Graham McIntire 7251930404
add mobile app websocket channel and improve QR linking UX
- add MobileSocket for token-authenticated mobile WebSocket connections
- add MobileChannel with org-level and device-level real-time events
- add /mobile/socket endpoint for iOS app connections
- add "Link Mobile App" to user dropdown menu for discoverability
- improve QR code page with numbered steps and clearer instructions
- add socket/channel tests (17 total)
2026-03-13 17:28:36 -05:00

72 lines
2 KiB
Elixir

defmodule ToweropsWeb.MobileSocketTest do
use Towerops.DataCase, async: true
import Towerops.AccountsFixtures
import Towerops.OrganizationsFixtures
alias Towerops.MobileSessions
alias Towerops.Repo
alias ToweropsWeb.MobileSocket
setup do
user = user_fixture()
_org = organization_fixture(user.id)
{:ok, qr_token} = MobileSessions.create_qr_login_token(user.id)
{:ok, session} =
MobileSessions.complete_qr_login(qr_token.token, %{
device_name: "Test iPhone",
device_os: "iOS 17.0",
app_version: "1.0.0"
})
%{user: user, session: session}
end
describe "connect/3" do
test "authenticates with valid token", %{session: session, user: user} do
assert {:ok, socket} =
MobileSocket.connect(%{"token" => session.raw_token}, socket(), %{})
assert socket.assigns.user_id == user.id
assert socket.assigns.mobile_session_id == session.id
end
test "returns error with no params" do
assert :error = MobileSocket.connect(%{}, socket(), %{})
end
test "returns error with invalid token" do
assert :error = MobileSocket.connect(%{"token" => "bogus-token"}, socket(), %{})
end
test "returns error with expired session", %{session: session} do
# Expire the session by setting expires_at to the past
past = DateTime.utc_now() |> DateTime.add(-1, :day) |> DateTime.truncate(:second)
session
|> Ecto.Changeset.change(expires_at: past)
|> Repo.update!()
assert :error = MobileSocket.connect(%{"token" => session.raw_token}, socket(), %{})
end
end
describe "id/1" do
test "returns correct socket id format", %{session: session, user: user} do
{:ok, socket} =
MobileSocket.connect(%{"token" => session.raw_token}, socket(), %{})
assert MobileSocket.id(socket) == "mobile_socket:#{user.id}"
end
end
defp socket do
%Phoenix.Socket{
transport: :websocket,
serializer: Phoenix.Socket.V2.JSONSerializer,
endpoint: ToweropsWeb.Endpoint
}
end
end