From dd0e79c400c264bc5b114b94c314e13c2278f34b Mon Sep 17 00:00:00 2001 From: KKlochko Date: Tue, 1 Aug 2023 18:09:01 +0300 Subject: [PATCH] Add tests for the API. --- CHANGELOG.org | 2 + .../api/v1/link_controller_test.exs | 97 +++++++++++++++++++ .../controllers/page_controller_test.exs | 8 ++ .../views/error_view_test.exs | 14 +++ .../views/layout_view_test.exs | 8 ++ .../views/page_view_test.exs | 3 + test/support/conn_case.ex | 38 ++++++++ test/support/data_case.ex | 58 +++++++++++ test/support/fixtures/links_fixtures.ex | 24 +++++ test/test_helper.exs | 2 + 10 files changed, 254 insertions(+) create mode 100644 test/link_shortener_web/controllers/api/v1/link_controller_test.exs create mode 100644 test/link_shortener_web/controllers/page_controller_test.exs create mode 100644 test/link_shortener_web/views/error_view_test.exs create mode 100644 test/link_shortener_web/views/layout_view_test.exs create mode 100644 test/link_shortener_web/views/page_view_test.exs create mode 100644 test/support/conn_case.ex create mode 100644 test/support/data_case.ex create mode 100644 test/support/fixtures/links_fixtures.ex create mode 100644 test/test_helper.exs diff --git a/CHANGELOG.org b/CHANGELOG.org index bd4d557..4d98f2b 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -34,4 +34,6 @@ Fix the route path in LinkController.create/2. ** 0.4.6 <2023-08-01 Tue> Add the API to update the Link model. +** 0.4.7 <2023-08-01 Tue> + Add tests for the API. diff --git a/test/link_shortener_web/controllers/api/v1/link_controller_test.exs b/test/link_shortener_web/controllers/api/v1/link_controller_test.exs new file mode 100644 index 0000000..67fca24 --- /dev/null +++ b/test/link_shortener_web/controllers/api/v1/link_controller_test.exs @@ -0,0 +1,97 @@ +defmodule LinkShortenerWeb.Api.V1.LinkControllerTest do + use LinkShortenerWeb.ConnCase + + import LinkShortener.LinksFixtures + + alias LinkShortener.Links.Link + alias LinkShortener.Links.Links + + @create_attrs %{ + name: "some link name", + url: "https://gitlab.com/KKlochko/link_shortener", + shorten: "git_repo", + } + @update_attrs %{ + name: "some updated link name", + url: "https://gitlab.com/KKlochko/link_shortener2", + shorten: "new_git_repo", + } + @invalid_attrs %{ + name: nil, + url: nil, + shorten: nil, + } + + setup %{conn: conn} do + {:ok, conn: put_req_header(conn, "accept", "application/json")} + end + + describe "index" do + test "lists all links", %{conn: conn} do + conn = get(conn, Routes.v1_link_path(conn, :index)) + assert json_response(conn, 200)["data"] == [] + end + end + + describe "create link" do + test "renders link when data is valid", %{conn: conn} do + conn = post(conn, Routes.v1_link_path(conn, :create), link: @create_attrs) + assert %{"id" => id} = json_response(conn, 201)["data"] + + conn = get(conn, Routes.v1_link_path(conn, :show, id)) + + assert %{ + "id" => ^id, + "name" => "some link name", + "url" => "https://gitlab.com/KKlochko/link_shortener", + "shorten" => "git_repo", + } = json_response(conn, 200)["data"] + end + + test "renders errors when data is invalid", %{conn: conn} do + conn = post(conn, Routes.v1_link_path(conn, :create), link: @invalid_attrs) + assert json_response(conn, 422)["errors"] != %{} + end + end + + describe "update link" do + setup [:create_link] + + test "renders link when data is valid", %{conn: conn, link: %Link{id: id} = link} do + conn = put(conn, Routes.v1_link_path(conn, :update, link), link: @update_attrs) + assert %{"id" => ^id} = json_response(conn, 200)["data"] + + conn = get(conn, Routes.v1_link_path(conn, :show, id)) + + assert %{ + "id" => ^id, + "name" => "some updated link name", + "url" => "https://gitlab.com/KKlochko/link_shortener2", + "shorten" => "new_git_repo", + } = json_response(conn, 200)["data"] + end + + test "renders errors when data is invalid", %{conn: conn, link: link} do + conn = put(conn, Routes.v1_link_path(conn, :update, link), link: @invalid_attrs) + assert json_response(conn, 422)["errors"] != %{} + end + end + + describe "delete link" do + setup [:create_link] + + test "deletes chosen link", %{conn: conn, link: link} do + conn = delete(conn, Routes.v1_link_path(conn, :delete, link)) + assert response(conn, 204) + + assert_error_sent 404, fn -> + get(conn, Routes.v1_link_path(conn, :show, link)) + end + end + end + + defp create_link(_) do + link = link_fixture() + %{link: link} + end +end diff --git a/test/link_shortener_web/controllers/page_controller_test.exs b/test/link_shortener_web/controllers/page_controller_test.exs new file mode 100644 index 0000000..a11164b --- /dev/null +++ b/test/link_shortener_web/controllers/page_controller_test.exs @@ -0,0 +1,8 @@ +defmodule LinkShortenerWeb.PageControllerTest do + use LinkShortenerWeb.ConnCase + + test "GET /", %{conn: conn} do + conn = get(conn, "/") + assert html_response(conn, 200) =~ "Usage" + end +end diff --git a/test/link_shortener_web/views/error_view_test.exs b/test/link_shortener_web/views/error_view_test.exs new file mode 100644 index 0000000..796b732 --- /dev/null +++ b/test/link_shortener_web/views/error_view_test.exs @@ -0,0 +1,14 @@ +defmodule LinkShortenerWeb.ErrorViewTest do + use LinkShortenerWeb.ConnCase, async: true + + # Bring render/3 and render_to_string/3 for testing custom views + import Phoenix.View + + test "renders 404.html" do + assert render_to_string(LinkShortenerWeb.ErrorView, "404.html", []) == "Not Found" + end + + test "renders 500.html" do + assert render_to_string(LinkShortenerWeb.ErrorView, "500.html", []) == "Internal Server Error" + end +end diff --git a/test/link_shortener_web/views/layout_view_test.exs b/test/link_shortener_web/views/layout_view_test.exs new file mode 100644 index 0000000..1c2276f --- /dev/null +++ b/test/link_shortener_web/views/layout_view_test.exs @@ -0,0 +1,8 @@ +defmodule LinkShortenerWeb.LayoutViewTest do + use LinkShortenerWeb.ConnCase, async: true + + # When testing helpers, you may want to import Phoenix.HTML and + # use functions such as safe_to_string() to convert the helper + # result into an HTML string. + # import Phoenix.HTML +end diff --git a/test/link_shortener_web/views/page_view_test.exs b/test/link_shortener_web/views/page_view_test.exs new file mode 100644 index 0000000..5d6cc0e --- /dev/null +++ b/test/link_shortener_web/views/page_view_test.exs @@ -0,0 +1,3 @@ +defmodule LinkShortenerWeb.PageViewTest do + use LinkShortenerWeb.ConnCase, async: true +end diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex new file mode 100644 index 0000000..1955e33 --- /dev/null +++ b/test/support/conn_case.ex @@ -0,0 +1,38 @@ +defmodule LinkShortenerWeb.ConnCase do + @moduledoc """ + This module defines the test case to be used by + tests that require setting up a connection. + + Such tests rely on `Phoenix.ConnTest` and also + import other functionality to make it easier + to build common data structures and query the data layer. + + Finally, if the test case interacts with the database, + we enable the SQL sandbox, so changes done to the database + are reverted at the end of every test. If you are using + PostgreSQL, you can even run database tests asynchronously + by setting `use LinkShortenerWeb.ConnCase, async: true`, although + this option is not recommended for other databases. + """ + + use ExUnit.CaseTemplate + + using do + quote do + # Import conveniences for testing with connections + import Plug.Conn + import Phoenix.ConnTest + import LinkShortenerWeb.ConnCase + + alias LinkShortenerWeb.Router.Helpers, as: Routes + + # The default endpoint for testing + @endpoint LinkShortenerWeb.Endpoint + end + end + + setup tags do + LinkShortener.DataCase.setup_sandbox(tags) + {:ok, conn: Phoenix.ConnTest.build_conn()} + end +end diff --git a/test/support/data_case.ex b/test/support/data_case.ex new file mode 100644 index 0000000..cbb80ec --- /dev/null +++ b/test/support/data_case.ex @@ -0,0 +1,58 @@ +defmodule LinkShortener.DataCase do + @moduledoc """ + This module defines the setup for tests requiring + access to the application's data layer. + + You may define functions here to be used as helpers in + your tests. + + Finally, if the test case interacts with the database, + we enable the SQL sandbox, so changes done to the database + are reverted at the end of every test. If you are using + PostgreSQL, you can even run database tests asynchronously + by setting `use LinkShortener.DataCase, async: true`, although + this option is not recommended for other databases. + """ + + use ExUnit.CaseTemplate + + using do + quote do + alias LinkShortener.Repo + + import Ecto + import Ecto.Changeset + import Ecto.Query + import LinkShortener.DataCase + end + end + + setup tags do + LinkShortener.DataCase.setup_sandbox(tags) + :ok + end + + @doc """ + Sets up the sandbox based on the test tags. + """ + def setup_sandbox(tags) do + pid = Ecto.Adapters.SQL.Sandbox.start_owner!(LinkShortener.Repo, shared: not tags[:async]) + on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end) + end + + @doc """ + A helper that transforms changeset errors into a map of messages. + + assert {:error, changeset} = Accounts.create_user(%{password: "short"}) + assert "password is too short" in errors_on(changeset).password + assert %{password: ["password is too short"]} = errors_on(changeset) + + """ + def errors_on(changeset) do + Ecto.Changeset.traverse_errors(changeset, fn {message, opts} -> + Regex.replace(~r"%{(\w+)}", message, fn _, key -> + opts |> Keyword.get(String.to_existing_atom(key), key) |> to_string() + end) + end) + end +end diff --git a/test/support/fixtures/links_fixtures.ex b/test/support/fixtures/links_fixtures.ex new file mode 100644 index 0000000..2d8cd99 --- /dev/null +++ b/test/support/fixtures/links_fixtures.ex @@ -0,0 +1,24 @@ +defmodule LinkShortener.LinksFixtures do + @moduledoc """ + This module defines test helpers for creating + entities via the `LinkShortener.Links` context. + """ + + alias LinkShortener.Links.Links + + @doc """ + Generate a link. + """ + def link_fixture(attrs \\ %{}) do + {:ok, link} = + attrs + |> Enum.into(%{ + name: "some name", + url: "https://gitlab.com/KKlochko/link_shortener", + shorten: "api-article", + }) + |> Links.create_one() + + link + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs new file mode 100644 index 0000000..fbe0342 --- /dev/null +++ b/test/test_helper.exs @@ -0,0 +1,2 @@ +ExUnit.start() +Ecto.Adapters.SQL.Sandbox.mode(LinkShortener.Repo, :manual)