From 616de3c117a9ee242116d95018a10547318145c6 Mon Sep 17 00:00:00 2001 From: shibao Date: Fri, 25 Feb 2022 21:53:15 -0500 Subject: [PATCH] update tests --- test/lokal/accounts_test.exs | 63 ++++++++------ test/lokal/invites_text.exs | 76 +++++++++++++++++ .../controllers/home_controller_test.exs | 14 +++ test/lokal_web/controllers/user_auth_test.exs | 69 +++++++++------ .../user_confirmation_controller_test.exs | 52 +++++++++--- .../user_registration_controller_test.exs | 24 ++++-- .../user_reset_password_controller_test.exs | 48 ++++++++--- .../user_session_controller_test.exs | 52 ++++++------ .../user_settings_controller_test.exs | 75 ++++++++++------ test/lokal_web/live/invite_live_test.exs | 85 +++++++++++++++++++ test/lokal_web/views/error_view_test.exs | 13 ++- test/support/conn_case.ex | 15 +++- test/support/data_case.ex | 1 + test/support/fixtures.ex | 60 +++++++++++++ test/support/fixtures/accounts_fixtures.ex | 31 ------- 15 files changed, 506 insertions(+), 172 deletions(-) create mode 100644 test/lokal/invites_text.exs create mode 100644 test/lokal_web/controllers/home_controller_test.exs create mode 100644 test/lokal_web/live/invite_live_test.exs create mode 100644 test/support/fixtures.ex delete mode 100644 test/support/fixtures/accounts_fixtures.ex diff --git a/test/lokal/accounts_test.exs b/test/lokal/accounts_test.exs index 8e026b5..4e27583 100644 --- a/test/lokal/accounts_test.exs +++ b/test/lokal/accounts_test.exs @@ -1,9 +1,14 @@ defmodule Lokal.AccountsTest do - use Lokal.DataCase + @moduledoc """ + This tests the accounts module + """ + use Lokal.DataCase alias Lokal.Accounts - import Lokal.AccountsFixtures alias Lokal.Accounts.{User, UserToken} + alias Ecto.Changeset + + @moduletag :accounts_test describe "get_user_by_email/1" do test "does not return the user if the email does not exist" do @@ -58,7 +63,8 @@ defmodule Lokal.AccountsTest do end test "validates email and password when given" do - {:error, changeset} = Accounts.register_user(%{email: "not valid", password: "not valid"}) + {:error, changeset} = + Accounts.register_user(%{"email" => "not valid", "password" => "not valid"}) assert %{ email: ["must have the @ sign and no spaces"], @@ -68,24 +74,27 @@ defmodule Lokal.AccountsTest do test "validates maximum values for email and password for security" do too_long = String.duplicate("db", 100) - {:error, changeset} = Accounts.register_user(%{email: too_long, password: too_long}) + {:error, changeset} = Accounts.register_user(%{"email" => too_long, "password" => too_long}) assert "should be at most 160 character(s)" in errors_on(changeset).email assert "should be at most 80 character(s)" in errors_on(changeset).password end test "validates email uniqueness" do %{email: email} = user_fixture() - {:error, changeset} = Accounts.register_user(%{email: email}) + {:error, changeset} = Accounts.register_user(%{"email" => email}) assert "has already been taken" in errors_on(changeset).email # Now try with the upper cased email too, to check that email case is ignored. - {:error, changeset} = Accounts.register_user(%{email: String.upcase(email)}) + {:error, changeset} = Accounts.register_user(%{"email" => String.upcase(email)}) assert "has already been taken" in errors_on(changeset).email end test "registers users with a hashed password" do email = unique_user_email() - {:ok, user} = Accounts.register_user(%{email: email, password: valid_user_password()}) + + {:ok, user} = + Accounts.register_user(%{"email" => email, "password" => valid_user_password()}) + assert user.email == email assert is_binary(user.hashed_password) assert is_nil(user.confirmed_at) @@ -95,7 +104,7 @@ defmodule Lokal.AccountsTest do describe "change_user_registration/2" do test "returns a changeset" do - assert %Ecto.Changeset{} = changeset = Accounts.change_user_registration(%User{}) + assert %Changeset{} = changeset = Accounts.change_user_registration(%User{}) assert changeset.required == [:password, :email] end @@ -115,7 +124,7 @@ defmodule Lokal.AccountsTest do describe "change_user_email/2" do test "returns a user changeset" do - assert %Ecto.Changeset{} = changeset = Accounts.change_user_email(%User{}) + assert %Changeset{} = changeset = Accounts.change_user_email(%User{}) assert changeset.required == [:email] end end @@ -132,7 +141,7 @@ defmodule Lokal.AccountsTest do test "validates email", %{user: user} do {:error, changeset} = - Accounts.apply_user_email(user, valid_user_password(), %{email: "not valid"}) + Accounts.apply_user_email(user, valid_user_password(), %{"email" => "not valid"}) assert %{email: ["must have the @ sign and no spaces"]} = errors_on(changeset) end @@ -141,7 +150,7 @@ defmodule Lokal.AccountsTest do too_long = String.duplicate("db", 100) {:error, changeset} = - Accounts.apply_user_email(user, valid_user_password(), %{email: too_long}) + Accounts.apply_user_email(user, valid_user_password(), %{"email" => too_long}) assert "should be at most 160 character(s)" in errors_on(changeset).email end @@ -150,21 +159,21 @@ defmodule Lokal.AccountsTest do %{email: email} = user_fixture() {:error, changeset} = - Accounts.apply_user_email(user, valid_user_password(), %{email: email}) + Accounts.apply_user_email(user, valid_user_password(), %{"email" => email}) assert "has already been taken" in errors_on(changeset).email end test "validates current password", %{user: user} do {:error, changeset} = - Accounts.apply_user_email(user, "invalid", %{email: unique_user_email()}) + Accounts.apply_user_email(user, "invalid", %{"email" => unique_user_email()}) assert %{current_password: ["is not valid"]} = errors_on(changeset) end test "applies the email without persisting it", %{user: user} do email = unique_user_email() - {:ok, user} = Accounts.apply_user_email(user, valid_user_password(), %{email: email}) + {:ok, user} = Accounts.apply_user_email(user, valid_user_password(), %{"email" => email}) assert user.email == email assert Accounts.get_user!(user.id).email != email end @@ -234,7 +243,7 @@ defmodule Lokal.AccountsTest do describe "change_user_password/2" do test "returns a user changeset" do - assert %Ecto.Changeset{} = changeset = Accounts.change_user_password(%User{}) + assert %Changeset{} = changeset = Accounts.change_user_password(%User{}) assert changeset.required == [:password] end @@ -258,8 +267,8 @@ defmodule Lokal.AccountsTest do test "validates password", %{user: user} do {:error, changeset} = Accounts.update_user_password(user, valid_user_password(), %{ - password: "not valid", - password_confirmation: "another" + "password" => "not valid", + "password_confirmation" => "another" }) assert %{ @@ -272,14 +281,14 @@ defmodule Lokal.AccountsTest do too_long = String.duplicate("db", 100) {:error, changeset} = - Accounts.update_user_password(user, valid_user_password(), %{password: too_long}) + Accounts.update_user_password(user, valid_user_password(), %{"password" => too_long}) assert "should be at most 80 character(s)" in errors_on(changeset).password end test "validates current password", %{user: user} do {:error, changeset} = - Accounts.update_user_password(user, "invalid", %{password: valid_user_password()}) + Accounts.update_user_password(user, "invalid", %{"password" => valid_user_password()}) assert %{current_password: ["is not valid"]} = errors_on(changeset) end @@ -287,7 +296,7 @@ defmodule Lokal.AccountsTest do test "updates the password", %{user: user} do {:ok, user} = Accounts.update_user_password(user, valid_user_password(), %{ - password: "new valid password" + "password" => "new valid password" }) assert is_nil(user.password) @@ -299,7 +308,7 @@ defmodule Lokal.AccountsTest do {:ok, _} = Accounts.update_user_password(user, valid_user_password(), %{ - password: "new valid password" + "password" => "new valid password" }) refute Repo.get_by(UserToken, user_id: user.id) @@ -467,8 +476,8 @@ defmodule Lokal.AccountsTest do test "validates password", %{user: user} do {:error, changeset} = Accounts.reset_user_password(user, %{ - password: "not valid", - password_confirmation: "another" + "password" => "not valid", + "password_confirmation" => "another" }) assert %{ @@ -479,19 +488,21 @@ defmodule Lokal.AccountsTest do test "validates maximum values for password for security", %{user: user} do too_long = String.duplicate("db", 100) - {:error, changeset} = Accounts.reset_user_password(user, %{password: too_long}) + {:error, changeset} = Accounts.reset_user_password(user, %{"password" => too_long}) assert "should be at most 80 character(s)" in errors_on(changeset).password end test "updates the password", %{user: user} do - {:ok, updated_user} = Accounts.reset_user_password(user, %{password: "new valid password"}) + {:ok, updated_user} = + Accounts.reset_user_password(user, %{"password" => "new valid password"}) + assert is_nil(updated_user.password) assert Accounts.get_user_by_email_and_password(user.email, "new valid password") end test "deletes all tokens for the given user", %{user: user} do _ = Accounts.generate_user_session_token(user) - {:ok, _} = Accounts.reset_user_password(user, %{password: "new valid password"}) + {:ok, _} = Accounts.reset_user_password(user, %{"password" => "new valid password"}) refute Repo.get_by(UserToken, user_id: user.id) end end diff --git a/test/lokal/invites_text.exs b/test/lokal/invites_text.exs new file mode 100644 index 0000000..7d9425d --- /dev/null +++ b/test/lokal/invites_text.exs @@ -0,0 +1,76 @@ +defmodule Lokal.InvitesTest do + @moduledoc """ + This module tests the Invites context + """ + + use Lokal.DataCase + alias Lokal.{Invites, Invites.Invite} + alias Ecto.Changeset + + @moduletag :invites_test + + @valid_attrs %{ + "name" => "some name", + "token" => "some token" + } + @update_attrs %{ + "name" => "some updated name", + "token" => "some updated token" + } + @invalid_attrs %{ + "name" => nil, + "token" => nil + } + + describe "invites" do + setup do + current_user = admin_fixture() + {:ok, invite} = Invites.create_invite(current_user, @valid_attrs) + [invite: invite, current_user: current_user] + end + + test "list_invites/0 returns all invites", %{invite: invite, current_user: current_user} do + assert Invites.list_invites(current_user) == [invite] + end + + test "get_invite!/1 returns the invite with given id", + %{invite: invite, current_user: current_user} do + assert Invites.get_invite!(invite.id, current_user) == invite + end + + test "create_invite/1 with valid data creates a invite", + %{current_user: current_user} do + assert {:ok, %Invite{} = invite} = Invites.create_invite(current_user, @valid_attrs) + assert invite.name == "some name" + end + + test "create_invite/1 with invalid data returns error changeset", + %{current_user: current_user} do + assert {:error, %Changeset{}} = Invites.create_invite(current_user, @invalid_attrs) + end + + test "update_invite/2 with valid data updates the invite", + %{invite: invite, current_user: current_user} do + assert {:ok, %Invite{} = new_invite} = + Invites.update_invite(invite, @update_attrs, current_user) + + assert new_invite.name == "some updated name" + assert new_invite.token == new_invite.token + end + + test "update_invite/2 with invalid data returns error changeset", + %{invite: invite, current_user: current_user} do + assert {:error, %Changeset{}} = Invites.update_invite(invite, @invalid_attrs, current_user) + assert invite == Invites.get_invite!(invite.id, current_user) + end + + test "delete_invite/1 deletes the invite", %{invite: invite, current_user: current_user} do + assert {:ok, %Invite{}} = Invites.delete_invite(invite, current_user) + assert_raise Ecto.NoResultsError, fn -> Invites.get_invite!(invite.id, current_user) end + end + + test "change_invite/1 returns a invite changeset", %{invite: invite} do + assert %Changeset{} = Invites.change_invite(invite) + end + end +end diff --git a/test/lokal_web/controllers/home_controller_test.exs b/test/lokal_web/controllers/home_controller_test.exs new file mode 100644 index 0000000..20e4f6c --- /dev/null +++ b/test/lokal_web/controllers/home_controller_test.exs @@ -0,0 +1,14 @@ +defmodule LokalWeb.HomeControllerTest do + @moduledoc """ + Tests the home page + """ + + use LokalWeb.ConnCase + + @moduletag :home_controller_test + + test "GET /", %{conn: conn} do + conn = get(conn, "/") + assert html_response(conn, 200) =~ "Welcome to Lokal" + end +end diff --git a/test/lokal_web/controllers/user_auth_test.exs b/test/lokal_web/controllers/user_auth_test.exs index 7b0ef5f..ea41009 100644 --- a/test/lokal_web/controllers/user_auth_test.exs +++ b/test/lokal_web/controllers/user_auth_test.exs @@ -1,10 +1,14 @@ defmodule LokalWeb.UserAuthTest do - use LokalWeb.ConnCase, async: true + @moduledoc """ + Tests user auth + """ + use LokalWeb.ConnCase, async: true + import LokalWeb.Gettext alias Lokal.Accounts alias LokalWeb.UserAuth - import Lokal.AccountsFixtures + @moduletag :user_auth_test @remember_me_cookie "_lokal_web_user_remember_me" setup %{conn: conn} do @@ -13,30 +17,33 @@ defmodule LokalWeb.UserAuthTest do |> Map.replace!(:secret_key_base, LokalWeb.Endpoint.config(:secret_key_base)) |> init_test_session(%{}) - %{user: user_fixture(), conn: conn} + [current_user: user_fixture() |> confirm_user(), conn: conn] end describe "log_in_user/3" do - test "stores the user token in the session", %{conn: conn, user: user} do - conn = UserAuth.log_in_user(conn, user) + test "stores the user token in the session", %{conn: conn, current_user: current_user} do + conn = UserAuth.log_in_user(conn, current_user) assert token = get_session(conn, :user_token) assert get_session(conn, :live_socket_id) == "users_sessions:#{Base.url_encode64(token)}" assert redirected_to(conn) == "/" assert Accounts.get_user_by_session_token(token) end - test "clears everything previously stored in the session", %{conn: conn, user: user} do - conn = conn |> put_session(:to_be_removed, "value") |> UserAuth.log_in_user(user) + test "clears everything previously stored in the session", + %{conn: conn, current_user: current_user} do + conn = conn |> put_session(:to_be_removed, "value") |> UserAuth.log_in_user(current_user) refute get_session(conn, :to_be_removed) end - test "redirects to the configured path", %{conn: conn, user: user} do - conn = conn |> put_session(:user_return_to, "/hello") |> UserAuth.log_in_user(user) + test "redirects to the configured path", %{conn: conn, current_user: current_user} do + conn = conn |> put_session(:user_return_to, "/hello") |> UserAuth.log_in_user(current_user) assert redirected_to(conn) == "/hello" end - test "writes a cookie if remember_me is configured", %{conn: conn, user: user} do - conn = conn |> fetch_cookies() |> UserAuth.log_in_user(user, %{"remember_me" => "true"}) + test "writes a cookie if remember_me is configured", %{conn: conn, current_user: current_user} do + conn = + conn |> fetch_cookies() |> UserAuth.log_in_user(current_user, %{"remember_me" => "true"}) + assert get_session(conn, :user_token) == conn.cookies[@remember_me_cookie] assert %{value: signed_token, max_age: max_age} = conn.resp_cookies[@remember_me_cookie] @@ -46,8 +53,8 @@ defmodule LokalWeb.UserAuthTest do end describe "logout_user/1" do - test "erases session and cookies", %{conn: conn, user: user} do - user_token = Accounts.generate_user_session_token(user) + test "erases session and cookies", %{conn: conn, current_user: current_user} do + user_token = Accounts.generate_user_session_token(current_user) conn = conn @@ -86,15 +93,15 @@ defmodule LokalWeb.UserAuthTest do end describe "fetch_current_user/2" do - test "authenticates user from session", %{conn: conn, user: user} do - user_token = Accounts.generate_user_session_token(user) + test "authenticates user from session", %{conn: conn, current_user: current_user} do + user_token = Accounts.generate_user_session_token(current_user) conn = conn |> put_session(:user_token, user_token) |> UserAuth.fetch_current_user([]) - assert conn.assigns.current_user.id == user.id + assert conn.assigns.current_user.id == current_user.id end - test "authenticates user from cookies", %{conn: conn, user: user} do + test "authenticates user from cookies", %{conn: conn, current_user: current_user} do logged_in_conn = - conn |> fetch_cookies() |> UserAuth.log_in_user(user, %{"remember_me" => "true"}) + conn |> fetch_cookies() |> UserAuth.log_in_user(current_user, %{"remember_me" => "true"}) user_token = logged_in_conn.cookies[@remember_me_cookie] %{value: signed_token} = logged_in_conn.resp_cookies[@remember_me_cookie] @@ -105,11 +112,11 @@ defmodule LokalWeb.UserAuthTest do |> UserAuth.fetch_current_user([]) assert get_session(conn, :user_token) == user_token - assert conn.assigns.current_user.id == user.id + assert conn.assigns.current_user.id == current_user.id end - test "does not authenticate if data is missing", %{conn: conn, user: user} do - _ = Accounts.generate_user_session_token(user) + test "does not authenticate if data is missing", %{conn: conn, current_user: current_user} do + _ = Accounts.generate_user_session_token(current_user) conn = UserAuth.fetch_current_user(conn, []) refute get_session(conn, :user_token) refute conn.assigns.current_user @@ -117,8 +124,12 @@ defmodule LokalWeb.UserAuthTest do end describe "redirect_if_user_is_authenticated/2" do - test "redirects if user is authenticated", %{conn: conn, user: user} do - conn = conn |> assign(:current_user, user) |> UserAuth.redirect_if_user_is_authenticated([]) + test "redirects if user is authenticated", %{conn: conn, current_user: current_user} do + conn = + conn + |> assign(:current_user, current_user) + |> UserAuth.redirect_if_user_is_authenticated([]) + assert conn.halted assert redirected_to(conn) == "/" end @@ -135,7 +146,9 @@ defmodule LokalWeb.UserAuthTest do conn = conn |> fetch_flash() |> UserAuth.require_authenticated_user([]) assert conn.halted assert redirected_to(conn) == Routes.user_session_path(conn, :new) - assert get_flash(conn, :error) == "You must log in to access this page." + + assert get_flash(conn, :error) == + dgettext("errors", "You must confirm your account and log in to access this page.") end test "stores the path to redirect to on GET", %{conn: conn} do @@ -156,7 +169,7 @@ defmodule LokalWeb.UserAuthTest do assert get_session(halted_conn, :user_return_to) == "/foo?bar=baz" halted_conn = - %{conn | path_info: ["foo"], query_string: "bar", method: "POST"} + %{conn | path_info: ["/foo?bar"], method: "POST"} |> fetch_flash() |> UserAuth.require_authenticated_user([]) @@ -164,8 +177,10 @@ defmodule LokalWeb.UserAuthTest do refute get_session(halted_conn, :user_return_to) end - test "does not redirect if user is authenticated", %{conn: conn, user: user} do - conn = conn |> assign(:current_user, user) |> UserAuth.require_authenticated_user([]) + test "does not redirect if user is authenticated", %{conn: conn, current_user: current_user} do + conn = + conn |> assign(:current_user, current_user) |> UserAuth.require_authenticated_user([]) + refute conn.halted refute conn.status end diff --git a/test/lokal_web/controllers/user_confirmation_controller_test.exs b/test/lokal_web/controllers/user_confirmation_controller_test.exs index 5b5d164..a295b50 100644 --- a/test/lokal_web/controllers/user_confirmation_controller_test.exs +++ b/test/lokal_web/controllers/user_confirmation_controller_test.exs @@ -1,9 +1,14 @@ defmodule LokalWeb.UserConfirmationControllerTest do - use LokalWeb.ConnCase, async: true + @moduledoc """ + Tests user confirmation + """ + use LokalWeb.ConnCase, async: true + import LokalWeb.Gettext alias Lokal.Accounts alias Lokal.Repo - import Lokal.AccountsFixtures + + @moduletag :user_confirmation_controller_test setup do %{user: user_fixture()} @@ -13,7 +18,7 @@ defmodule LokalWeb.UserConfirmationControllerTest do test "renders the confirmation page", %{conn: conn} do conn = get(conn, Routes.user_confirmation_path(conn, :new)) response = html_response(conn, 200) - assert response =~ "Resend confirmation instructions" + assert response =~ dgettext("actions", "Resend confirmation instructions") end end @@ -26,7 +31,14 @@ defmodule LokalWeb.UserConfirmationControllerTest do }) assert redirected_to(conn) == "/" - assert get_flash(conn, :info) =~ "If your email is in our system" + + assert get_flash(conn, :info) =~ + dgettext( + "prompts", + "If your email is in our system and it has not been confirmed yet, " <> + "you will receive an email with instructions shortly." + ) + assert Repo.get_by!(Accounts.UserToken, user_id: user.id).context == "confirm" end @@ -39,8 +51,13 @@ defmodule LokalWeb.UserConfirmationControllerTest do }) assert redirected_to(conn) == "/" - assert get_flash(conn, :info) =~ "If your email is in our system" - refute Repo.get_by(Accounts.UserToken, user_id: user.id) + + assert get_flash(conn, :info) =~ + dgettext( + "prompts", + "If your email is in our system and it has not been confirmed yet, " <> + "you will receive an email with instructions shortly." + ) end test "does not send confirmation token if email is invalid", %{conn: conn} do @@ -50,7 +67,14 @@ defmodule LokalWeb.UserConfirmationControllerTest do }) assert redirected_to(conn) == "/" - assert get_flash(conn, :info) =~ "If your email is in our system" + + assert get_flash(conn, :info) =~ + dgettext( + "prompts", + "If your email is in our system and it has not been confirmed yet, " <> + "you will receive an email with instructions shortly." + ) + assert Repo.all(Accounts.UserToken) == [] end end @@ -64,7 +88,10 @@ defmodule LokalWeb.UserConfirmationControllerTest do conn = get(conn, Routes.user_confirmation_path(conn, :confirm, token)) assert redirected_to(conn) == "/" - assert get_flash(conn, :info) =~ "User confirmed successfully" + + assert get_flash(conn, :info) =~ + dgettext("prompts", "%{email} confirmed successfully", email: user.email) + assert Accounts.get_user!(user.id).confirmed_at refute get_session(conn, :user_token) assert Repo.all(Accounts.UserToken) == [] @@ -72,7 +99,9 @@ defmodule LokalWeb.UserConfirmationControllerTest do # When not logged in conn = get(conn, Routes.user_confirmation_path(conn, :confirm, token)) assert redirected_to(conn) == "/" - assert get_flash(conn, :error) =~ "User confirmation link is invalid or it has expired" + + assert get_flash(conn, :error) =~ + dgettext("errors", "User confirmation link is invalid or it has expired") # When logged in conn = @@ -87,7 +116,10 @@ defmodule LokalWeb.UserConfirmationControllerTest do test "does not confirm email with invalid token", %{conn: conn, user: user} do conn = get(conn, Routes.user_confirmation_path(conn, :confirm, "oops")) assert redirected_to(conn) == "/" - assert get_flash(conn, :error) =~ "User confirmation link is invalid or it has expired" + + assert get_flash(conn, :error) =~ + dgettext("errors", "User confirmation link is invalid or it has expired") + refute Accounts.get_user!(user.id).confirmed_at end end diff --git a/test/lokal_web/controllers/user_registration_controller_test.exs b/test/lokal_web/controllers/user_registration_controller_test.exs index 2cfeec4..43b6350 100644 --- a/test/lokal_web/controllers/user_registration_controller_test.exs +++ b/test/lokal_web/controllers/user_registration_controller_test.exs @@ -1,15 +1,19 @@ defmodule LokalWeb.UserRegistrationControllerTest do - use LokalWeb.ConnCase, async: true + @moduledoc """ + Tests user registration + """ - import Lokal.AccountsFixtures + use LokalWeb.ConnCase, async: true + import LokalWeb.Gettext + + @moduletag :user_registration_controller_test describe "GET /users/register" do test "renders registration page", %{conn: conn} do conn = get(conn, Routes.user_registration_path(conn, :new)) response = html_response(conn, 200) - assert response =~ "Register" - assert response =~ "Log in" - assert response =~ "Register" + assert response =~ dgettext("actions", "Register") + assert response =~ dgettext("actions", "Log in") end test "redirects if already logged in", %{conn: conn} do @@ -28,15 +32,17 @@ defmodule LokalWeb.UserRegistrationControllerTest do "user" => valid_user_attributes(email: email) }) - assert get_session(conn, :user_token) + assert get_session(conn, :phoenix_flash) == %{ + "info" => dgettext("prompts", "Please check your email to verify your account") + } + assert redirected_to(conn) =~ "/" # Now do a logged in request and assert on the menu conn = get(conn, "/") response = html_response(conn, 200) + # user's email is recorded as admin assert response =~ email - assert response =~ "Settings" - assert response =~ "Log out" end test "render errors for invalid data", %{conn: conn} do @@ -46,7 +52,7 @@ defmodule LokalWeb.UserRegistrationControllerTest do }) response = html_response(conn, 200) - assert response =~ "Register" + assert response =~ gettext("Register") assert response =~ "must have the @ sign and no spaces" assert response =~ "should be at least 12 character" end diff --git a/test/lokal_web/controllers/user_reset_password_controller_test.exs b/test/lokal_web/controllers/user_reset_password_controller_test.exs index 3f2733b..d22eaf1 100644 --- a/test/lokal_web/controllers/user_reset_password_controller_test.exs +++ b/test/lokal_web/controllers/user_reset_password_controller_test.exs @@ -1,9 +1,13 @@ defmodule LokalWeb.UserResetPasswordControllerTest do - use LokalWeb.ConnCase, async: true + @moduledoc """ + Tests the user reset password controller + """ - alias Lokal.Accounts - alias Lokal.Repo - import Lokal.AccountsFixtures + use LokalWeb.ConnCase, async: true + import LokalWeb.Gettext + alias Lokal.{Accounts, Repo} + + @moduletag :user_reset_password_controller_test setup do %{user: user_fixture()} @@ -13,7 +17,7 @@ defmodule LokalWeb.UserResetPasswordControllerTest do test "renders the reset password page", %{conn: conn} do conn = get(conn, Routes.user_reset_password_path(conn, :new)) response = html_response(conn, 200) - assert response =~ "Forgot your password?" + assert response =~ dgettext("actions", "Forgot your password?") end end @@ -26,7 +30,13 @@ defmodule LokalWeb.UserResetPasswordControllerTest do }) assert redirected_to(conn) == "/" - assert get_flash(conn, :info) =~ "If your email is in our system" + + assert get_flash(conn, :info) =~ + dgettext( + "prompts", + "If your email is in our system, you will receive instructions to reset your password shortly." + ) + assert Repo.get_by!(Accounts.UserToken, user_id: user.id).context == "reset_password" end @@ -37,7 +47,13 @@ defmodule LokalWeb.UserResetPasswordControllerTest do }) assert redirected_to(conn) == "/" - assert get_flash(conn, :info) =~ "If your email is in our system" + + assert get_flash(conn, :info) =~ + dgettext( + "prompts", + "If your email is in our system, you will receive instructions to reset your password shortly." + ) + assert Repo.all(Accounts.UserToken) == [] end end @@ -54,13 +70,15 @@ defmodule LokalWeb.UserResetPasswordControllerTest do test "renders reset password", %{conn: conn, token: token} do conn = get(conn, Routes.user_reset_password_path(conn, :edit, token)) - assert html_response(conn, 200) =~ "Reset password" + assert html_response(conn, 200) =~ dgettext("actions", "Reset password") end test "does not render reset password with invalid token", %{conn: conn} do conn = get(conn, Routes.user_reset_password_path(conn, :edit, "oops")) assert redirected_to(conn) == "/" - assert get_flash(conn, :error) =~ "Reset password link is invalid or it has expired" + + assert get_flash(conn, :error) =~ + dgettext("errors", "Reset password link is invalid or it has expired") end end @@ -85,7 +103,7 @@ defmodule LokalWeb.UserResetPasswordControllerTest do assert redirected_to(conn) == Routes.user_session_path(conn, :new) refute get_session(conn, :user_token) - assert get_flash(conn, :info) =~ "Password reset successfully" + assert get_flash(conn, :info) =~ dgettext("prompts", "Password reset successfully") assert Accounts.get_user_by_email_and_password(user.email, "new valid password") end @@ -99,15 +117,17 @@ defmodule LokalWeb.UserResetPasswordControllerTest do }) response = html_response(conn, 200) - assert response =~ "Reset password" - assert response =~ "should be at least 12 character(s)" - assert response =~ "does not match password" + assert response =~ gettext("Reset password") + assert response =~ dgettext("errors", "should be at least 12 character(s)") + assert response =~ dgettext("errors", "does not match password") end test "does not reset password with invalid token", %{conn: conn} do conn = put(conn, Routes.user_reset_password_path(conn, :update, "oops")) assert redirected_to(conn) == "/" - assert get_flash(conn, :error) =~ "Reset password link is invalid or it has expired" + + assert get_flash(conn, :error) =~ + dgettext("errors", "Reset password link is invalid or it has expired") end end end diff --git a/test/lokal_web/controllers/user_session_controller_test.exs b/test/lokal_web/controllers/user_session_controller_test.exs index 9851f8a..744fe31 100644 --- a/test/lokal_web/controllers/user_session_controller_test.exs +++ b/test/lokal_web/controllers/user_session_controller_test.exs @@ -1,31 +1,35 @@ defmodule LokalWeb.UserSessionControllerTest do + @moduledoc """ + Tests the user session controller + """ + use LokalWeb.ConnCase, async: true + import LokalWeb.Gettext - import Lokal.AccountsFixtures + @moduletag :user_session_controller_test - setup do - %{user: user_fixture()} + setup %{conn: conn} do + [current_user: user_fixture() |> confirm_user(), conn: conn] end describe "GET /users/log_in" do test "renders log in page", %{conn: conn} do conn = get(conn, Routes.user_session_path(conn, :new)) response = html_response(conn, 200) - assert response =~ "Log in" - assert response =~ "Register" + assert response =~ dgettext("actions", "Log in") end - test "redirects if already logged in", %{conn: conn, user: user} do - conn = conn |> log_in_user(user) |> get(Routes.user_session_path(conn, :new)) + test "redirects if already logged in", %{conn: conn, current_user: current_user} do + conn = conn |> log_in_user(current_user) |> get(Routes.user_session_path(conn, :new)) assert redirected_to(conn) == "/" end end describe "POST /users/log_in" do - test "logs the user in", %{conn: conn, user: user} do + test "logs the user in", %{conn: conn, current_user: current_user} do conn = post(conn, Routes.user_session_path(conn, :create), %{ - "user" => %{"email" => user.email, "password" => valid_user_password()} + "user" => %{"email" => current_user.email, "password" => valid_user_password()} }) assert get_session(conn, :user_token) @@ -34,16 +38,15 @@ defmodule LokalWeb.UserSessionControllerTest do # Now do a logged in request and assert on the menu conn = get(conn, "/") response = html_response(conn, 200) - assert response =~ user.email - assert response =~ "Settings" - assert response =~ "Log out" + assert response =~ current_user.email + assert response =~ dgettext("prompts", "Are you sure you want to log out?") end - test "logs the user in with remember me", %{conn: conn, user: user} do + test "logs the user in with remember me", %{conn: conn, current_user: current_user} do conn = post(conn, Routes.user_session_path(conn, :create), %{ "user" => %{ - "email" => user.email, + "email" => current_user.email, "password" => valid_user_password(), "remember_me" => "true" } @@ -53,13 +56,13 @@ defmodule LokalWeb.UserSessionControllerTest do assert redirected_to(conn) =~ "/" end - test "logs the user in with return to", %{conn: conn, user: user} do + test "logs the user in with return to", %{conn: conn, current_user: current_user} do conn = conn |> init_test_session(user_return_to: "/foo/bar") |> post(Routes.user_session_path(conn, :create), %{ "user" => %{ - "email" => user.email, + "email" => current_user.email, "password" => valid_user_password() } }) @@ -67,31 +70,32 @@ defmodule LokalWeb.UserSessionControllerTest do assert redirected_to(conn) == "/foo/bar" end - test "emits error message with invalid credentials", %{conn: conn, user: user} do + test "emits error message with invalid credentials", + %{conn: conn, current_user: current_user} do conn = post(conn, Routes.user_session_path(conn, :create), %{ - "user" => %{"email" => user.email, "password" => "invalid_password"} + "user" => %{"email" => current_user.email, "password" => "bad"} }) response = html_response(conn, 200) - assert response =~ "Log in" - assert response =~ "Invalid email or password" + assert response =~ dgettext("actions", "Log in") + assert response =~ dgettext("errors", "Invalid email or password") end end describe "DELETE /users/log_out" do - test "logs the user out", %{conn: conn, user: user} do - conn = conn |> log_in_user(user) |> delete(Routes.user_session_path(conn, :delete)) + test "logs the user out", %{conn: conn, current_user: current_user} do + conn = conn |> log_in_user(current_user) |> delete(Routes.user_session_path(conn, :delete)) assert redirected_to(conn) == "/" refute get_session(conn, :user_token) - assert get_flash(conn, :info) =~ "Logged out successfully" + assert get_flash(conn, :info) =~ gettext("Logged out successfully") end test "succeeds even if the user is not logged in", %{conn: conn} do conn = delete(conn, Routes.user_session_path(conn, :delete)) assert redirected_to(conn) == "/" refute get_session(conn, :user_token) - assert get_flash(conn, :info) =~ "Logged out successfully" + assert get_flash(conn, :info) =~ gettext("Logged out successfully") end end end diff --git a/test/lokal_web/controllers/user_settings_controller_test.exs b/test/lokal_web/controllers/user_settings_controller_test.exs index 14ca4c8..0b89584 100644 --- a/test/lokal_web/controllers/user_settings_controller_test.exs +++ b/test/lokal_web/controllers/user_settings_controller_test.exs @@ -1,8 +1,13 @@ defmodule LokalWeb.UserSettingsControllerTest do - use LokalWeb.ConnCase, async: true + @moduledoc """ + Tests the user settings controller + """ + use LokalWeb.ConnCase, async: true + import LokalWeb.Gettext alias Lokal.Accounts - import Lokal.AccountsFixtures + + @moduletag :user_settings_controller_test setup :register_and_log_in_user @@ -10,7 +15,7 @@ defmodule LokalWeb.UserSettingsControllerTest do test "renders settings page", %{conn: conn} do conn = get(conn, Routes.user_settings_path(conn, :edit)) response = html_response(conn, 200) - assert response =~ "Settings" + assert response =~ gettext("Settings") end test "redirects if user is not logged in" do @@ -21,7 +26,8 @@ defmodule LokalWeb.UserSettingsControllerTest do end describe "PUT /users/settings (change password form)" do - test "updates the user password and resets tokens", %{conn: conn, user: user} do + test "updates the user password and resets tokens", + %{conn: conn, current_user: current_user} do new_password_conn = put(conn, Routes.user_settings_path(conn, :update), %{ "action" => "update_password", @@ -34,8 +40,11 @@ defmodule LokalWeb.UserSettingsControllerTest do assert redirected_to(new_password_conn) == Routes.user_settings_path(conn, :edit) assert get_session(new_password_conn, :user_token) != get_session(conn, :user_token) - assert get_flash(new_password_conn, :info) =~ "Password updated successfully" - assert Accounts.get_user_by_email_and_password(user.email, "new valid password") + + assert get_flash(new_password_conn, :info) =~ + dgettext("actions", "Password updated successfully") + + assert Accounts.get_user_by_email_and_password(current_user.email, "new valid password") end test "does not update password on invalid data", %{conn: conn} do @@ -50,10 +59,10 @@ defmodule LokalWeb.UserSettingsControllerTest do }) response = html_response(old_password_conn, 200) - assert response =~ "Settings" - assert response =~ "should be at least 12 character(s)" - assert response =~ "does not match password" - assert response =~ "is not valid" + assert response =~ gettext("Settings") + assert response =~ dgettext("errors", "should be at least 12 character(s)") + assert response =~ dgettext("errors", "does not match password") + assert response =~ dgettext("errors", "is not valid") assert get_session(old_password_conn, :user_token) == get_session(conn, :user_token) end @@ -61,7 +70,7 @@ defmodule LokalWeb.UserSettingsControllerTest do describe "PUT /users/settings (change email form)" do @tag :capture_log - test "updates the user email", %{conn: conn, user: user} do + test "updates the user email", %{conn: conn, current_user: current_user} do conn = put(conn, Routes.user_settings_path(conn, :update), %{ "action" => "update_email", @@ -70,8 +79,14 @@ defmodule LokalWeb.UserSettingsControllerTest do }) assert redirected_to(conn) == Routes.user_settings_path(conn, :edit) - assert get_flash(conn, :info) =~ "A link to confirm your email" - assert Accounts.get_user_by_email(user.email) + + assert get_flash(conn, :info) =~ + dgettext( + "prompts", + "A link to confirm your email change has been sent to the new address." + ) + + assert Accounts.get_user_by_email(current_user.email) end test "does not update email on invalid data", %{conn: conn} do @@ -83,41 +98,51 @@ defmodule LokalWeb.UserSettingsControllerTest do }) response = html_response(conn, 200) - assert response =~ "Settings" - assert response =~ "must have the @ sign and no spaces" - assert response =~ "is not valid" + assert response =~ gettext("Settings") + assert response =~ dgettext("errors", "must have the @ sign and no spaces") + assert response =~ dgettext("errors", "is not valid") end end describe "GET /users/settings/confirm_email/:token" do - setup %{user: user} do + setup %{current_user: current_user} do email = unique_user_email() token = extract_user_token(fn url -> - Accounts.deliver_update_email_instructions(%{user | email: email}, user.email, url) + Accounts.deliver_update_email_instructions( + %{current_user | email: email}, + current_user.email, + url + ) end) %{token: token, email: email} end - test "updates the user email once", %{conn: conn, user: user, token: token, email: email} do + test "updates the user email once", + %{conn: conn, current_user: current_user, token: token, email: email} do conn = get(conn, Routes.user_settings_path(conn, :confirm_email, token)) assert redirected_to(conn) == Routes.user_settings_path(conn, :edit) - assert get_flash(conn, :info) =~ "Email changed successfully" - refute Accounts.get_user_by_email(user.email) + assert get_flash(conn, :info) =~ dgettext("prompts", "Email changed successfully") + refute Accounts.get_user_by_email(current_user.email) assert Accounts.get_user_by_email(email) conn = get(conn, Routes.user_settings_path(conn, :confirm_email, token)) assert redirected_to(conn) == Routes.user_settings_path(conn, :edit) - assert get_flash(conn, :error) =~ "Email change link is invalid or it has expired" + + assert get_flash(conn, :error) =~ + dgettext("errors", "Email change link is invalid or it has expired") end - test "does not update email with invalid token", %{conn: conn, user: user} do + test "does not update email with invalid token", %{conn: conn, current_user: current_user} do conn = get(conn, Routes.user_settings_path(conn, :confirm_email, "oops")) assert redirected_to(conn) == Routes.user_settings_path(conn, :edit) - assert get_flash(conn, :error) =~ "Email change link is invalid or it has expired" - assert Accounts.get_user_by_email(user.email) + + assert get_flash(conn, :error) =~ + dgettext("errors", "Email change link is invalid or it has expired") + + assert Accounts.get_user_by_email(current_user.email) end test "redirects if user is not logged in", %{token: token} do diff --git a/test/lokal_web/live/invite_live_test.exs b/test/lokal_web/live/invite_live_test.exs new file mode 100644 index 0000000..1e13405 --- /dev/null +++ b/test/lokal_web/live/invite_live_test.exs @@ -0,0 +1,85 @@ +defmodule LokalWeb.InviteLiveTest do + @moduledoc """ + Tests the invite liveview + """ + + use LokalWeb.ConnCase + import Phoenix.LiveViewTest + import LokalWeb.Gettext + alias Lokal.Invites + + @moduletag :invite_live_test + @create_attrs %{"name" => "some name"} + @update_attrs %{"name" => "some updated name"} + # @invalid_attrs %{"name" => nil} + + describe "Index" do + setup [:register_and_log_in_user] + + setup %{current_user: current_user} do + {:ok, invite} = Invites.create_invite(current_user, @create_attrs) + %{invite: invite, current_user: current_user} + end + + test "lists all invites", %{conn: conn, invite: invite} do + {:ok, _index_live, html} = live(conn, Routes.invite_index_path(conn, :index)) + + assert html =~ gettext("Invites") + assert html =~ invite.name + end + + test "saves new invite", %{conn: conn} do + {:ok, index_live, _html} = live(conn, Routes.invite_index_path(conn, :index)) + + assert index_live |> element("a", dgettext("actions", "Create Invite")) |> render_click() =~ + gettext("New Invite") + + assert_patch(index_live, Routes.invite_index_path(conn, :new)) + + # assert index_live + # |> form("#invite-form", invite: @invalid_attrs) + # |> render_change() =~ dgettext("errors", "can't be blank") + + {:ok, _, html} = + index_live + |> form("#invite-form", invite: @create_attrs) + |> render_submit() + |> follow_redirect(conn, Routes.invite_index_path(conn, :index)) + + assert html =~ dgettext("prompts", "%{name} created successfully", name: "some name") + + assert html =~ "some name" + end + + test "updates invite in listing", %{conn: conn, invite: invite} do + {:ok, index_live, _html} = live(conn, Routes.invite_index_path(conn, :index)) + + assert index_live |> element("[data-qa=\"edit-#{invite.id}\"]") |> render_click() =~ + gettext("Edit Invite") + + assert_patch(index_live, Routes.invite_index_path(conn, :edit, invite)) + + # assert index_live + # |> form("#invite-form", invite: @invalid_attrs) + # |> render_change() =~ dgettext("errors", "can't be blank") + + {:ok, _, html} = + index_live + |> form("#invite-form", invite: @update_attrs) + |> render_submit() + |> follow_redirect(conn, Routes.invite_index_path(conn, :index)) + + assert html =~ + dgettext("prompts", "%{name} updated successfully", name: "some updated name") + + assert html =~ "some updated name" + end + + test "deletes invite in listing", %{conn: conn, invite: invite} do + {:ok, index_live, _html} = live(conn, Routes.invite_index_path(conn, :index)) + + assert index_live |> element("[data-qa=\"delete-#{invite.id}\"]") |> render_click() + refute has_element?(index_live, "#invite-#{invite.id}") + end + end +end diff --git a/test/lokal_web/views/error_view_test.exs b/test/lokal_web/views/error_view_test.exs index ce9c1c1..e6c7416 100644 --- a/test/lokal_web/views/error_view_test.exs +++ b/test/lokal_web/views/error_view_test.exs @@ -1,14 +1,23 @@ defmodule LokalWeb.ErrorViewTest do + @moduledoc """ + Tests the error view + """ + use LokalWeb.ConnCase, async: true + import LokalWeb.Gettext + + @moduletag :error_view_test # Bring render/3 and render_to_string/3 for testing custom views import Phoenix.View test "renders 404.html" do - assert render_to_string(LokalWeb.ErrorView, "404.html", []) == "Not Found" + assert render_to_string(LokalWeb.ErrorView, "404.html", []) =~ + dgettext("errors", "Not found") end test "renders 500.html" do - assert render_to_string(LokalWeb.ErrorView, "500.html", []) == "Internal Server Error" + assert render_to_string(LokalWeb.ErrorView, "500.html", []) =~ + dgettext("errors", "Internal Server Error") end end diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index 10d8b7b..8fe466a 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -16,14 +16,16 @@ defmodule LokalWeb.ConnCase do """ use ExUnit.CaseTemplate + import Lokal.Fixtures + alias Lokal.{Accounts, Accounts.User, Repo} alias Ecto.Adapters.SQL.Sandbox - alias Lokal.{Accounts, Repo} using do quote do # Import conveniences for testing with connections import Plug.Conn import Phoenix.ConnTest + import Lokal.Fixtures import LokalWeb.ConnCase alias LokalWeb.Router.Helpers, as: Routes @@ -47,12 +49,17 @@ defmodule LokalWeb.ConnCase do It stores an updated connection and a registered user in the test context. """ + @spec register_and_log_in_user(%{conn: Plug.Conn.t()}) :: + %{conn: Plug.Conn.t(), current_user: User.t()} def register_and_log_in_user(%{conn: conn}) do - user = Lokal.AccountsFixtures.user_fixture() + current_user = user_fixture() |> confirm_user() + %{conn: log_in_user(conn, current_user), current_user: current_user} + end + @spec confirm_user(User.t()) :: User.t() + def confirm_user(user) do {:ok, %{user: user}} = user |> Accounts.confirm_user_multi() |> Repo.transaction() - - %{conn: log_in_user(conn, user), user: user} + user end @doc """ diff --git a/test/support/data_case.ex b/test/support/data_case.ex index 6230fc5..c2a2b21 100644 --- a/test/support/data_case.ex +++ b/test/support/data_case.ex @@ -25,6 +25,7 @@ defmodule Lokal.DataCase do import Ecto.Changeset import Ecto.Query import Lokal.DataCase + import Lokal.Fixtures end end diff --git a/test/support/fixtures.ex b/test/support/fixtures.ex new file mode 100644 index 0000000..7f46534 --- /dev/null +++ b/test/support/fixtures.ex @@ -0,0 +1,60 @@ +defmodule Lokal.Fixtures do + @moduledoc """ + This module defines test helpers for creating entities + """ + + alias Lokal.{Accounts, Accounts.User, Email} + + def unique_user_email, do: "user#{System.unique_integer()}@example.com" + def valid_user_password, do: "hello world!" + + @spec user_fixture() :: Accounts.User.t() + @spec user_fixture(attrs :: map()) :: Accounts.User.t() + def user_fixture(attrs \\ %{}) do + attrs + |> Enum.into(%{ + "email" => unique_user_email(), + "password" => valid_user_password() + }) + |> Accounts.register_user() + |> unwrap_ok_tuple() + end + + @spec admin_fixture() :: Accounts.User.t() + @spec admin_fixture(attrs :: map()) :: Accounts.User.t() + def admin_fixture(attrs \\ %{}) do + attrs + |> Enum.into(%{ + "email" => unique_user_email(), + "password" => valid_user_password(), + "role" => "admin" + }) + |> Accounts.register_user() + |> unwrap_ok_tuple() + end + + def extract_user_token(fun) do + %{args: %{attrs: attrs, email: email_key, user_id: user_id}} = fun.(&"[TOKEN]#{&1}[TOKEN]") + + # convert atoms to string keys + attrs = attrs |> Map.new(fn {atom_key, value} -> {atom_key |> Atom.to_string(), value} end) + + email = + email_key + |> Atom.to_string() + |> Email.generate_email(Accounts.get_user!(user_id), attrs) + + [_, html_token | _] = email.html_body |> String.split("[TOKEN]") + [_, text_token | _] = email.text_body |> String.split("[TOKEN]") + ^text_token = html_token + end + + def valid_user_attributes(attrs \\ %{}) do + Enum.into(attrs, %{ + email: unique_user_email(), + password: valid_user_password() + }) + end + + defp unwrap_ok_tuple({:ok, value}), do: value +end diff --git a/test/support/fixtures/accounts_fixtures.ex b/test/support/fixtures/accounts_fixtures.ex deleted file mode 100644 index 9378e74..0000000 --- a/test/support/fixtures/accounts_fixtures.ex +++ /dev/null @@ -1,31 +0,0 @@ -defmodule Lokal.AccountsFixtures do - @moduledoc """ - This module defines test helpers for creating - entities via the `Lokal.Accounts` context. - """ - - def unique_user_email, do: "user#{System.unique_integer()}@example.com" - def valid_user_password, do: "hello world!" - - def valid_user_attributes(attrs \\ %{}) do - Enum.into(attrs, %{ - email: unique_user_email(), - password: valid_user_password() - }) - end - - def user_fixture(attrs \\ %{}) do - {:ok, user} = - attrs - |> valid_user_attributes() - |> Lokal.Accounts.register_user() - - user - end - - def extract_user_token(fun) do - {:ok, captured} = fun.(&"[TOKEN]#{&1}[TOKEN]") - [_, token, _] = String.split(captured.body, "[TOKEN]") - token - end -end