Skip to content

Commit

Permalink
Add open_browser/1 (#31)
Browse files Browse the repository at this point in the history
What changed? 
==============

This introduces a new `open_browser/1` helper to open the default 
browser to display current HTML of `session`.

The `Live` implementation mostly wraps LiveView's `open_browser/1` 
implementation. But for the `Static` implementation, we bring a lot 
of the work that was done in LiveView into `PhoenixTest`. The 
biggest difference is that we do not bring LiveView's unique integer
generation. Instead, we rely on `System.unique_integer` to help us
generate unique names for the files. 

Finally, we opt for using the name `open_browser/1` (as opposed to 
the original suggestion of `preview`) to try to align with LiveView's
existing language so it's (hopefully) more intuitive to LiveView 
users who are already accustomed to the behavior.
  • Loading branch information
sodapopcan authored Feb 20, 2024
1 parent d699792 commit b9d8347
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 0 deletions.
6 changes: 6 additions & 0 deletions lib/phoenix_test.ex
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,12 @@ defmodule PhoenixTest do
"""
defdelegate submit_form(session, selector, data), to: Driver

@doc """
Open the default browser to display current HTML of `session`.
"""
defdelegate open_browser(session), to: Driver
defdelegate open_browser(session, open_fun), to: Driver

@doc """
Assert helper to ensure an element with given CSS selector and `text` is
present.
Expand Down
2 changes: 2 additions & 0 deletions lib/phoenix_test/driver.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ defprotocol PhoenixTest.Driver do
def click_button(session, selector, text)
def fill_form(session, selector, form_data)
def submit_form(session, selector, form_data)
def open_browser(session)
def open_browser(session, open_fun)
end
5 changes: 5 additions & 0 deletions lib/phoenix_test/live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ defimpl PhoenixTest.Driver, for: PhoenixTest.Live do
phx_change != nil && phx_change != ""
end

def open_browser(%{view: view} = session, open_fun \\ &Phoenix.LiveViewTest.open_browser/1) do
open_fun.(view)
session
end

defp maybe_redirect({:error, {:redirect, %{to: path}}}, session) do
PhoenixTest.visit(session.conn, path)
end
Expand Down
76 changes: 76 additions & 0 deletions lib/phoenix_test/open_browser.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
defmodule PhoenixTest.OpenBrowser do
@moduledoc false

# This module contains private functionality ported over from
# `Phoenix.LiveViewTest` to make `open_browser` work with `Static` tests.

@doc """
Fully qualifies static assets paths so the browser can find them.
"""
def prefix_static_paths(node, endpoint) do
static_path = static_path(endpoint)

case node do
# Remove script tags
{"script", _, _} -> nil
# Skip prefixing src attributes on anchor tags
{"a", _, _} = link -> link
{el, attrs, children} -> {el, maybe_prefix_static_path(attrs, static_path), children}
el -> el
end
end

defp static_path(endpoint) do
static_url = endpoint.config(:static_url) || []
priv_dir = :otp_app |> endpoint.config() |> Application.app_dir("priv")

if Keyword.get(static_url, :path) do
priv_dir
else
Path.join(priv_dir, "static")
end
end

defp maybe_prefix_static_path(attrs, nil), do: attrs

defp maybe_prefix_static_path(attrs, static_path) do
Enum.map(attrs, fn
{"src", path} -> {"src", prefix_static_path(path, static_path)}
{"href", path} -> {"href", prefix_static_path(path, static_path)}
attr -> attr
end)
end

defp prefix_static_path(<<"//" <> _::binary>> = url, _prefix), do: url

defp prefix_static_path(<<"/" <> _::binary>> = path, prefix) do
"file://#{Path.join([prefix, path])}"
end

defp prefix_static_path(url, _), do: url

@doc """
System agnostic function to open the default browser with the given `path`.
This is ripped verbatim from `Phoenix.LiveViewTest`.
"""
def open_with_system_cmd(path) do
{cmd, args} =
case :os.type() do
{:win32, _} ->
{"cmd", ["/c", "start", path]}

{:unix, :darwin} ->
{"open", [path]}

{:unix, _} ->
if System.find_executable("cmd.exe") do
{"cmd.exe", ["/c", "start", path]}
else
{"xdg-open", [path]}
end
end

System.cmd(cmd, args)
end
end
17 changes: 17 additions & 0 deletions lib/phoenix_test/static.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ defimpl PhoenixTest.Driver, for: PhoenixTest.Static do

alias PhoenixTest.Html
alias PhoenixTest.Query
alias PhoenixTest.OpenBrowser

def render_page_title(session) do
session
Expand Down Expand Up @@ -177,6 +178,22 @@ defimpl PhoenixTest.Driver, for: PhoenixTest.Static do
|> maybe_redirect(session)
end

def open_browser(session, open_fun \\ &OpenBrowser.open_with_system_cmd/1) do
path = Path.join([System.tmp_dir!(), "phx-test#{System.unique_integer([:monotonic])}.html"])

html =
session.conn.resp_body
|> Floki.parse_document!()
|> Floki.traverse_and_update(&OpenBrowser.prefix_static_paths(&1, @endpoint))
|> Floki.raw_html()

File.write!(path, html)

open_fun.(path)

session
end

defp maybe_redirect(conn, session) do
case conn do
%{status: 302} ->
Expand Down
17 changes: 17 additions & 0 deletions test/phoenix_test/live_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -333,4 +333,21 @@ defmodule PhoenixTest.LiveTest do
end
end
end

describe "open_browser" do
setup do
open_fun = fn view ->
assert %Phoenix.LiveViewTest.View{} = view
end

%{open_fun: open_fun}
end

test "opens the browser", %{conn: conn, open_fun: open_fun} do
conn
|> visit("/live/index")
|> open_browser(open_fun)
|> assert_has("h1", "LiveView main page")
end
end
end
31 changes: 31 additions & 0 deletions test/phoenix_test/static_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -337,4 +337,35 @@ defmodule PhoenixTest.StaticTest do
end
end
end

describe "open_browser" do
setup do
open_fun = fn path ->
assert content = File.read!(path)

assert content =~
~r[<link rel="stylesheet" href="file:.*phoenix_test\/priv\/assets\/app\.css"\/>]

assert content =~ "<link rel=\"stylesheet\" href=\"//example.com/cool-styles.css\"/>"
assert content =~ "body { font-size: 12px; }"

assert content =~ ~r/<h1.*Main page/

refute content =~ "<script>"
refute content =~ "console.log(\"Hey, I'm some JavaScript!\")"
refute content =~ "</script>"

path
end

%{open_fun: open_fun}
end

test "opens the browser ", %{conn: conn, open_fun: open_fun} do
conn
|> visit("/page/index")
|> open_browser(open_fun)
|> assert_has("h1", "Main page")
end
end
end
8 changes: 8 additions & 0 deletions test/support/page_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ defmodule PhoenixTest.PageView do
<html lang="en">
<head>
<title><%= assigns[:page_title] || "PhoenixTest is the best!" %></title>
<link rel="stylesheet" href="/assets/app.css" />
<link rel="stylesheet" href="//example.com/cool-styles.css" />
<script>
console.log("Hey, I'm some JavaScript!")
</script>
<style>
body { font-size: 12px; }
</style>
</head>
<body>
<%= @inner_content %>
Expand Down

0 comments on commit b9d8347

Please sign in to comment.