Current section
Files
Jump to
Current section
Files
lib/sandbox_case.ex
defmodule SandboxCase do
@moduledoc """
Batteries-included test isolation for Elixir and Phoenix.
## Endpoint setup
import SandboxCase
sandbox_plugs()
socket_with_sandbox "/live", Phoenix.LiveView.Socket,
websocket: [connect_info: [session: @session_options]]
## LiveView setup
import SandboxCase
sandbox_on_mount()
Outside test env, all macros emit their non-sandbox equivalents
or nothing — zero overhead in production.
"""
@doc """
Emits `plug(mod)` for every plug declared by configured sandbox adapters.
Emits nothing outside test env.
"""
defmacro sandbox_plugs do
if test_env?() do
for mod <- SandboxCase.Sandbox.collect_plugs() do
quote do: plug(unquote(mod))
end
end
end
@doc """
Emits `on_mount(mod)` for every hook declared by configured sandbox adapters.
Emits nothing outside test env.
"""
defmacro sandbox_on_mount do
if test_env?() do
for mod <- SandboxCase.Sandbox.collect_hooks() do
quote do: on_mount(unquote(mod))
end
end
end
@doc """
Declares a Phoenix LiveView socket, injecting `:user_agent` into
`connect_info` in test env so the sandbox Hook can read the owner PID.
In production, emits a plain `socket/3` call without `:user_agent`.
## Example
socket_with_sandbox "/live", Phoenix.LiveView.Socket,
websocket: [connect_info: [session: @session_options]]
In test, this becomes:
socket "/live", Phoenix.LiveView.Socket,
websocket: [connect_info: [:user_agent, session: @session_options]]
"""
defmacro socket_with_sandbox(path, module, opts) do
if test_env?() do
opts = inject_user_agent(opts)
quote do: socket(unquote(path), unquote(module), unquote(opts))
else
quote do: socket(unquote(path), unquote(module), unquote(opts))
end
end
defp inject_user_agent(opts) do
Keyword.update(opts, :websocket, [connect_info: [:user_agent]], fn ws_opts ->
Keyword.update(ws_opts, :connect_info, [:user_agent], fn ci ->
if :user_agent in ci, do: ci, else: [:user_agent | ci]
end)
end)
end
@doc false
def test_env? do
function_exported?(Mix, :env, 0) and Mix.env() == :test
end
end