defmodule FrancisTest do use ExUnit.Case, async: true import ExUnit.CaptureLog alias Francis describe "get/1" do test "returns a response with the given body" do handler = quote do: get("/", fn _ -> "test" end) mod = Support.RouteTester.generate_module(handler) Macro.to_string(mod) assert Req.get!("/", plug: mod).body == "test" end end describe "post/1" do test "returns a response with the given body" do handler = quote do: post("/", fn _ -> "test" end) mod = Support.RouteTester.generate_module(handler) assert Req.post!("/", plug: mod).body == "test" end end describe "put/1" do test "returns a response with the given body" do handler = quote do: put("/", fn _ -> "test" end) mod = Support.RouteTester.generate_module(handler) assert Req.put!("/", plug: mod).body == "test" end end describe "delete/1" do test "returns a response with the given body" do handler = quote do: delete("/", fn _ -> "test" end) mod = Support.RouteTester.generate_module(handler) assert Req.delete!("/", plug: mod).body == "test" end end describe "patch/1" do test "returns a response with the given body" do handler = quote do: patch("/", fn _ -> "test" end) mod = Support.RouteTester.generate_module(handler) assert Req.patch!("/", plug: mod).body == "test" end test "setups a HEAD handler" do handler = quote do: get("/", fn _ -> "test" end) mod = Support.RouteTester.generate_module(handler) assert Req.head!("/", plug: mod).status == 200 assert Req.head!("/", plug: mod).body == "" end end describe "ws/1" do setup do port = Enum.random(5000..10_000) %{port: port} end test "returns a response with the given body", %{port: port} do parent_pid = self() path = 10 |> :crypto.strong_rand_bytes() |> Base.encode16(case: :lower) handler = quote do ws(unquote(path), fn "test", socket -> send(unquote(parent_pid), {:handler, "handler_received"}) send(socket.transport, "late_sent") send(socket.transport, %{key: "value"}) send(socket.transport, [1, 2, 3]) {:reply, "reply"} end) end bandit_opts = [port: port] mod = Support.RouteTester.generate_module(handler, bandit_opts: bandit_opts) assert capture_log(fn -> {:ok, _} = start_supervised(mod) end) =~ "Running #{mod |> Module.split() |> List.last()} with Bandit #{Application.spec(:bandit, :vsn)} at 0.0.0.0:#{port}" tester_pid = start_supervised!( {Support.WsTester, %{url: "ws://localhost:#{port}/#{path}", parent_pid: parent_pid}} ) WebSockex.send_frame(tester_pid, {:text, "test"}) assert_receive {:handler, "handler_received"} assert_receive {:client, "late_sent"} assert_receive {:client, %{"key" => "value"}} assert_receive {:client, [1, 2, 3]} :ok end @tag :capture_log test "does not return a response with the given body", %{port: port} do parent_pid = self() path = 10 |> :crypto.strong_rand_bytes() |> Base.encode16(case: :lower) handler = quote do ws(unquote(path), fn "test", socket -> send(unquote(parent_pid), {:handler, "handler_received"}) :noreply end) end bandit_opts = [port: port] mod = Support.RouteTester.generate_module(handler, bandit_opts: bandit_opts) {:ok, _} = start_supervised(mod) tester_pid = start_supervised!( {Support.WsTester, %{url: "ws://localhost:#{port}/#{path}", parent_pid: parent_pid}} ) WebSockex.send_frame(tester_pid, {:text, "test"}) assert_receive {:handler, "handler_received"} refute_receive :_, 500 :ok end end describe "redirect/2" do test "redirects to the given path" do handler = quote do get("/", fn conn -> redirect(conn, "/new_path") end) end mod = Support.RouteTester.generate_module(handler) response = Req.get!("/", plug: mod, redirect: false) assert response.status == 302 assert response.headers["location"] == ["/new_path"] end test "redirects to the given URL" do handler = quote do get("/", fn conn -> redirect(conn, "http://example.com/new_path") end) end mod = Support.RouteTester.generate_module(handler) response = Req.get!("/", plug: mod, redirect: false) assert response.status == 302 assert response.headers["location"] == ["http://example.com/new_path"] end test "redirects with a 301 status" do handler = quote do get("/", fn conn -> redirect(conn, "/new_path", status: 301) end) end mod = Support.RouteTester.generate_module(handler) response = Req.get!("/", plug: mod, redirect: false) assert response.status == 301 assert response.headers["location"] == ["/new_path"] end end describe "json/2" do test "returns a JSON response with 200 status" do handler = quote do get("/", fn conn -> json(conn, %{message: "success"}) end) end mod = Support.RouteTester.generate_module(handler) response = Req.get!("/", plug: mod) assert response.status == 200 assert response.headers["content-type"] == ["application/json; charset=utf-8"] assert response.body == %{"message" => "success"} end test "returns a JSON response with list data" do handler = quote do get("/", fn conn -> json(conn, [1, 2, 3]) end) end mod = Support.RouteTester.generate_module(handler) response = Req.get!("/", plug: mod) assert response.status == 200 assert response.headers["content-type"] == ["application/json; charset=utf-8"] assert response.body == [1, 2, 3] end end describe "json/3" do test "returns a JSON response with custom status" do handler = quote do get("/", fn conn -> json(conn, 201, %{id: 123, created: true}) end) end mod = Support.RouteTester.generate_module(handler) response = Req.get!("/", plug: mod) assert response.status == 201 assert response.headers["content-type"] == ["application/json; charset=utf-8"] assert response.body == %{"id" => 123, "created" => true} end end describe "text/2" do test "returns a text response with 200 status" do handler = quote do get("/", fn conn -> text(conn, "Hello, World!") end) end mod = Support.RouteTester.generate_module(handler) response = Req.get!("/", plug: mod) assert response.status == 200 assert response.headers["content-type"] == ["text/plain; charset=utf-8"] assert response.body == "Hello, World!" end end describe "text/3" do test "returns a text response with custom status" do handler = quote do get("/", fn conn -> text(conn, 201, "Resource created successfully") end) end mod = Support.RouteTester.generate_module(handler) response = Req.get!("/", plug: mod) assert response.status == 201 assert response.headers["content-type"] == ["text/plain; charset=utf-8"] assert response.body == "Resource created successfully" end end describe "html/2" do test "returns an HTML response with 200 status" do handler = quote do get("/", fn conn -> html(conn, "