defmodule FrancisE2ETest do
use ExUnit.Case
@moduletag :e2e
setup do
port = Enum.random(10_000..20_000)
on_exit(fn ->
case System.cmd("lsof", ["-ti", ":#{port}"], stderr_to_stdout: true) do
{pid_str, 0} when pid_str != "" ->
pid = String.trim(pid_str) |> String.to_integer()
System.cmd("kill", ["-INT", to_string(pid)])
Process.sleep(100)
_ ->
:ok
end
end)
%{port: port}
end
describe "e2e: HTML response handlers" do
@tag :capture_log
test "html/2 serves HTML with correct headers over HTTP", %{port: port} do
handler =
quote do
get("/", fn conn -> html(conn, "
Hello, World!
") end)
end
mod = Support.RouteTester.generate_module(handler, bandit_opts: [port: port])
start_supervised!(mod)
response = Req.get!("http://localhost:#{port}/")
assert response.status == 200
assert response.headers["content-type"] == ["text/html; charset=utf-8"]
assert response.headers["cache-control"] == [
"no-cache, no-store, must-revalidate"
]
assert response.body == "Hello, World!
"
end
@tag :capture_log
test "html/3 serves HTML with custom status over HTTP", %{port: port} do
handler =
quote do
get("/", fn conn -> html(conn, 201, "Created
") end)
end
mod = Support.RouteTester.generate_module(handler, bandit_opts: [port: port])
start_supervised!(mod)
response = Req.get!("http://localhost:#{port}/")
assert response.status == 201
assert response.headers["content-type"] == ["text/html; charset=utf-8"]
assert response.headers["cache-control"] == [
"no-cache, no-store, must-revalidate"
]
end
@tag :capture_log
test "safe_html/2 escapes content and serves over HTTP", %{port: port} do
handler =
quote do
get("/", fn conn ->
safe_html(conn, "")
end)
end
mod = Support.RouteTester.generate_module(handler, bandit_opts: [port: port])
start_supervised!(mod)
response = Req.get!("http://localhost:#{port}/")
assert response.status == 200
assert response.headers["content-type"] == ["text/html; charset=utf-8"]
assert response.body == "<script>alert('xss')</script>"
refute response.body =~ "")
end)
end
mod = Support.RouteTester.generate_module(handler, bandit_opts: [port: port])
start_supervised!(mod)
response = Req.get!("http://localhost:#{port}/")
assert response.status == 200
# XSS payload is escaped
refute response.body =~ "")
end)
end
mod = Support.RouteTester.generate_module(handler, bandit_opts: [port: port])
start_supervised!(mod)
# HTML route
html_resp = Req.get!("http://localhost:#{port}/html")
assert html_resp.status == 200
assert html_resp.body == "HTML Page
"
assert html_resp.headers["content-type"] == ["text/html; charset=utf-8"]
assert html_resp.headers["cache-control"] == [
"no-cache, no-store, must-revalidate"
]
assert html_resp.headers["x-content-type-options"] == ["nosniff"]
# JSON route
json_resp = Req.get!("http://localhost:#{port}/json")
assert json_resp.status == 200
assert json_resp.body == %{"message" => "hello"}
assert json_resp.headers["content-type"] == [
"application/json; charset=utf-8"
]
assert json_resp.headers["x-content-type-options"] == ["nosniff"]
# Text route
text_resp = Req.get!("http://localhost:#{port}/text")
assert text_resp.status == 200
assert text_resp.body == "plain text"
assert text_resp.headers["content-type"] == ["text/plain; charset=utf-8"]
# Safe HTML route
safe_resp = Req.get!("http://localhost:#{port}/safe")
assert safe_resp.status == 200
refute safe_resp.body =~ "