Skip to content

Instantly share code, notes, and snippets.

@joeytrapp
Last active September 6, 2024 23:44
Show Gist options
  • Save joeytrapp/35c984a67cf2eb6eb0f6f4b3ef9e060f to your computer and use it in GitHub Desktop.
Save joeytrapp/35c984a67cf2eb6eb0f6f4b3ef9e060f to your computer and use it in GitHub Desktop.
Demonstrate that manually set request headers are not present in redirect/navigate requests
Mix.install(
[
{:phoenix_playground, "~> 0.1.6"},
{:phoenix_test, "~> 0.3.2"}
],
config: [
phoenix_test: [endpoint: Demo.Endpoint],
phoenix_playground: [
{Demo.Endpoint,
[
render_errors: [view: Demo.ErrorView, layout: false],
secret_key_base: String.duplicate("a", 32),
server: false
]}
]
]
)
defmodule Demo.DemoLive do
use Phoenix.LiveView
import Phoenix.Component
def mount(_params, _session, socket) do
{:ok, socket}
end
def handle_params(_params, _session, socket) do
{:noreply, assign(socket, :title, page_title(socket.assigns.live_action))}
end
def render(assigns) do
~H"""
<h1><%= @title %></h1>
<.link navigate="/">List</.link>
<.link navigate="/new">New</.link>
"""
end
defp page_title(:index), do: "List Page"
defp page_title(:new), do: "New Page"
end
defmodule Demo.Router do
use Phoenix.Router
import Phoenix.LiveView.Router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :put_root_layout, html: {PhoenixPlayground.Layout, :root}
plug :put_secure_browser_headers
plug :expect_req_header
end
scope "/", Demo do
pipe_through :browser
live "/", DemoLive, :index
live "/new", DemoLive, :new
end
#
# This requirement of the request header existing causes the failure
#
def expect_req_header(conn, _opts) do
case Plug.Conn.get_req_header(conn, "required-id") do
[] ->
conn
|> Plug.Conn.send_resp(401, "Unauthorized")
|> Plug.Conn.halt()
[header_value | _] ->
Plug.Conn.assign(conn, :required_id, header_value)
end
end
end
defmodule Demo.ErrorView do
def render("500.html", _assigns), do: nil
end
defmodule Demo.Endpoint do
use Phoenix.Endpoint, otp_app: :phoenix_playground
plug Plug.Logger
socket "/live", Phoenix.LiveView.Socket
plug Plug.Static, from: {:phoenix, "priv/static"}, at: "/assets/phoenix"
plug Plug.Static, from: {:phoenix_live_view, "priv/static"}, at: "/assets/phoenix_live_view"
socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
plug Phoenix.LiveReloader
plug Phoenix.CodeReloader, reloader: &PhoenixPlayground.CodeReloader.reload/2
plug Plug.Session, store: :cookie, key: "_demo_key", signing_salt: "asdfbasd"
plug Demo.Router
end
Logger.configure(level: :warning)
ExUnit.start()
defmodule Demo.DemoLiveTest do
use ExUnit.Case
use PhoenixPlayground.Test, endpoint: Demo.Endpoint
import PhoenixTest
test "fails because required-id is not present for the navigate redirect" do
build_conn()
|> Plug.Conn.put_req_header("required-id", "mock-id-value")
|> visit("/")
|> assert_has("h1", text: "List Page")
|> click_link("New")
|> assert_path("/new")
|> assert_has("h1", text: "New Page")
end
end
$ elixir phoenix_test_example.exs
Running ExUnit with seed: 719174, max_cases: 32
1) test fails because required-id is not present for the navigate redirect (Demo.DemoLiveTest)
phoenix_test_example.exs:103
** (FunctionClauseError) no function clause matching in Phoenix.LiveViewTest.connect_from_static_token/2
The following arguments were given to Phoenix.LiveViewTest.connect_from_static_token/2:
# 1
%Plug.Conn{adapter: {Plug.Adapters.Test.Conn, :...}, assigns: %{}, body_params: %Plug.Conn.Unfetched{aspect: :body_params}, cookies: %{}, halted: true, host: "www.example.com", method: "GET", owner: #PID<0.242.0>, params: %{}, path_info: ["new"], path_params: %{}, port: 80, private: %{:phoenix_live_view => {Demo.DemoLive, [action: :new, router: Demo.Router], %{extra: %{}, name: :default, vsn: 1725665773615184792}}, Demo.Router => [], :phoenix_router => Demo.Router, :plug_session_fetch => :done, :plug_session => %{}, :before_send => [#Function<0.9035112/1 in Plug.Session.before_send/2>, #Function<1.8684523/1 in Plug.Logger.call/2>], :phoenix_endpoint => Demo.Endpoint, :phoenix_format => "html", :phoenix_root_layout => %{"html" => {PhoenixPlayground.Layout, :root}}, :plug_skip_csrf_protection => true, :phoenix_recycled => false}, query_params: %Plug.Conn.Unfetched{aspect: :query_params}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %{}, req_headers: [], request_path: "/new", resp_body: "Unauthorized", resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}, {"referrer-policy", "strict-origin-when-cross-origin"}, {"x-content-type-options", "nosniff"}, {"x-download-options", "noopen"}, {"x-frame-options", "SAMEORIGIN"}, {"x-permitted-cross-domain-policies", "none"}], scheme: :http, script_name: [], secret_key_base: :..., state: :sent, status: 401}
# 2
"/new"
Attempted function clauses (showing 3 out of 3):
defp connect_from_static_token(%Plug.Conn{status: 200, assigns: %{live_module: live_module}} = conn, path)
defp connect_from_static_token(%Plug.Conn{status: 200}, _path)
defp connect_from_static_token(%Plug.Conn{status: redir} = conn, _path) when redir === 301 or redir === 302
code: |> click_link("New")
stacktrace:
(phoenix_live_view 0.20.17) lib/phoenix_live_view/test/live_view_test.ex:318: Phoenix.LiveViewTest.connect_from_static_token/2
(phoenix_test 0.3.2) lib/phoenix_test/live.ex:331: PhoenixTest.Live.maybe_redirect/2
phoenix_test_example.exs:108: (test)
Finished in 0.06 seconds (0.02s on load, 0.00s async, 0.04s sync)
1 test, 1 failure
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment