diff --git a/lib/phoenix_integration/assertions.ex b/lib/phoenix_integration/assertions.ex index 1ab1fed..6c7cbc9 100644 --- a/lib/phoenix_integration/assertions.ex +++ b/lib/phoenix_integration/assertions.ex @@ -45,6 +45,7 @@ defmodule PhoenixIntegration.Assertions do values are `"text/html"` or `"application/json"` * `:body` conn.resp_body should contain the given text. Does not check the content_type. * `:html` checks that content_type is html, then looks for the given text in the body. + * `:text` checks that content_type is html, then looks for the given text in the visible text of the document. * `:json` checks that content_type is json, then checks that the json data equals the given map. * `:path` the route rendered into the conn must equal the given path (or uri). * `:uri` same as `:path` @@ -84,6 +85,7 @@ defmodule PhoenixIntegration.Assertions do :content_type -> assert_content_type(conn, value) :body -> assert_body(conn, value) :html -> assert_body_html(conn, value) + :text -> assert_text(conn, value) :json -> assert_body_json(conn, value) :uri -> assert_uri(conn, value) :path -> assert_uri(conn, value, :path) @@ -110,6 +112,7 @@ defmodule PhoenixIntegration.Assertions do values are `"text/html"` or `"applicaiton/json"` * `:body` conn.resp_body should not contain the given text. Does not check the content_type. * `:html` checks if content_type is html. If it is, it then checks that the given text is not in the body. + * `:text` checks if content_type is html. If it is, it then checks that the given text is not in the document text. * `:json` checks if content_type is json, then checks that the json data does not equal the given map. * `:path` the route rendered into the conn must not equal the given path (or uri). * `:uri` same as `:path` @@ -140,6 +143,7 @@ defmodule PhoenixIntegration.Assertions do :content_type -> refute_content_type(conn, value) :body -> refute_body(conn, value) :html -> refute_body_html(conn, value) + :text -> refute_text(conn, value) :json -> refute_body_json(conn, value) :uri -> refute_uri(conn, value) :path -> refute_uri(conn, value, :path) @@ -381,6 +385,30 @@ defmodule PhoenixIntegration.Assertions do end end + # ---------------------------------------------------------------------------- + defp assert_text(conn, expected, err_type \\ :html) do + assert_content_type(conn, "text/html", err_type) + |> assert_visible_html_text(expected, err_type) + end + + # ---------------------------------------------------------------------------- + defp refute_text(conn, expected, err_type \\ :html) do + # similar to refute body html, ok if content isn't html + case Plug.Conn.get_resp_header(conn, "content-type") do + [] -> + conn + + [header] -> + cond do + header =~ "text/html" -> + refute_visible_html_text(conn, expected, err_type) + + true -> + conn + end + end + end + # ---------------------------------------------------------------------------- defp assert_body_json(conn, expected, err_type \\ :json) do assert_content_type(conn, "application/json", err_type) @@ -455,6 +483,37 @@ defmodule PhoenixIntegration.Assertions do end end + # ---------------------------------------------------------------------------- + defp assert_visible_html_text(conn, expected, err_type) do + visible_text = conn.resp_body |> Floki.parse_document!() |> Floki.text(style: false, sep: " ") + if visible_text =~ expected do + conn + else + msg = + error_msg_type(conn, err_type) <> + error_msg_expected("to find \"#{inspect(expected)}\"") <> + error_msg_found("Not visible in the html text of the response\n") <> IO.ANSI.yellow() <> visible_text + + raise %ResponseError{message: msg} + end + end + + # ---------------------------------------------------------------------------- + defp refute_visible_html_text(conn, expected, err_type) do + visible_text = conn.resp_body |> Floki.parse_document!() |> Floki.text(style: false, sep: " ") + if visible_text =~ expected do + msg = + error_msg_type(conn, err_type) <> + error_msg_expected("NOT to find \"#{inspect(expected)}\"") <> + error_msg_found("in the html text of the response\n") <> IO.ANSI.yellow() <> visible_text + + raise %ResponseError{message: msg} + else + conn + end + end + + # ---------------------------------------------------------------------------- defp assert_status(conn, status, err_type \\ :status) do case conn.status do diff --git a/mix.exs b/mix.exs index 94a8087..0c1e008 100644 --- a/mix.exs +++ b/mix.exs @@ -43,7 +43,6 @@ defmodule PhoenixIntegration.Mixfile do defp deps do [ {:phoenix, "~> 1.3"}, - {:phoenix_html, "~> 2.10 or ~> 3.0"}, {:floki, ">= 0.24.0"}, {:jason, "~> 1.1"}, {:flow_assertions, "~> 0.7", only: :test}, diff --git a/mix.lock b/mix.lock index 90ddfb9..26b6ef9 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,5 @@ %{ "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, - "earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"}, "earmark_parser": {:hex, :earmark_parser, "1.4.15", "b29e8e729f4aa4a00436580dcc2c9c5c51890613457c193cc8525c388ccb2f06", [:mix], [], "hexpm", "044523d6438ea19c1b8ec877ec221b008661d3c27e3b848f4c879f500421ca5c"}, "ex_doc": {:hex, :ex_doc, "0.25.3", "3edf6a0d70a39d2eafde030b8895501b1c93692effcbd21347296c18e47618ce", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "9ebebc2169ec732a38e9e779fd0418c9189b3ca93f4a676c961be6c1527913f5"}, "floki": {:hex, :floki, "0.31.0", "f05ee8a8e6a3ced4e62beeb2c79a63bc8e12ab98fbaaf6e6a3d9b76b1278e23f", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "b05afa372f5c345a5bf240ac25ea1f0f3d5fcfd7490ac0beeb4a203f9444891e"}, @@ -14,7 +13,6 @@ "mime": {:hex, :mime, "2.0.1", "0de4c81303fe07806ebc2494d5321ce8fb4df106e34dd5f9d787b637ebadc256", [:mix], [], "hexpm", "7a86b920d2aedce5fb6280ac8261ac1a739ae6c1a1ad38f5eadf910063008942"}, "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"}, "phoenix": {:hex, :phoenix, "1.6.0", "7b85023f7ddef9a5c70909a51cc37c8b868b474d853f90f4280efd26b0e7cce5", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "52ffdd31f2daeb399b2e1eb57d468f99a1ad6eee5d8ea19d2353492f06c9fc96"}, - "phoenix_html": {:hex, :phoenix_html, "3.0.4", "232d41884fe6a9c42d09f48397c175cd6f0d443aaa34c7424da47604201df2e1", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "ce17fd3cf815b2ed874114073e743507704b1f5288bb03c304a77458485efc8b"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"}, "phoenix_view": {:hex, :phoenix_view, "1.0.0", "fea71ecaaed71178b26dd65c401607de5ec22e2e9ef141389c721b3f3d4d8011", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "82be3e2516f5633220246e2e58181282c71640dab7afc04f70ad94253025db0c"}, "plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"}, diff --git a/test/assertions_test.exs b/test/assertions_test.exs index 87f498e..628724f 100644 --- a/test/assertions_test.exs +++ b/test/assertions_test.exs @@ -246,6 +246,42 @@ defmodule PhoenixIntegration.AssertionsTest do end end + # ---------------------------------------------------------------------------- + # assert text + test "assert_response :text succeeds", %{conn: conn} do + conn = get(conn, "/sample") + + PhoenixIntegration.Assertions.assert_response( + conn, + body: "Sample", + body: "Page" + ) + end + + test "assert_response :text fails if wrong type", %{conn: conn} do + conn = get(conn, "/test_json") + + assert_raise PhoenixIntegration.Assertions.ResponseError, fn -> + PhoenixIntegration.Assertions.assert_response(conn, text: "Sample Page") + end + end + + test "assert_response :text fails if missing content", %{conn: conn} do + conn = get(conn, "/sample") + + assert_raise PhoenixIntegration.Assertions.ResponseError, fn -> + PhoenixIntegration.Assertions.assert_response(conn, text: "href=\"/links/first\"") + end + end + + test "assert_response :text fails if missing content for regexp", %{conn: conn} do + conn = get(conn, "/sample") + + assert_raise PhoenixIntegration.Assertions.ResponseError, fn -> + PhoenixIntegration.Assertions.assert_response(conn, text: ~r/invalid content/) + end + end + # ---------------------------------------------------------------------------- # assert json test "assert_response :json succeeds", %{conn: conn} do @@ -400,6 +436,26 @@ defmodule PhoenixIntegration.AssertionsTest do end end + # ---------------------------------------------------------------------------- + # refute text + test "refute_response :text succeeds with wrong content", %{conn: conn} do + conn = get(conn, "/sample") + PhoenixIntegration.Assertions.refute_response(conn, body: "not_in_body") + end + + test "refute_response :text succeeds if wrong type", %{conn: conn} do + conn = get(conn, "/test_json") + PhoenixIntegration.Assertions.refute_response(conn, text: "Sample") + end + + test "refute_response :text fails if contains content", %{conn: conn} do + conn = get(conn, "/sample") + + assert_raise PhoenixIntegration.Assertions.ResponseError, fn -> + PhoenixIntegration.Assertions.refute_response(conn, text: "Sample Page") + end + end + # ---------------------------------------------------------------------------- # refute json test "refute_response :json succeeds", %{conn: conn} do