diff --git a/config/test.exs b/config/test.exs index 95b1d2d6..6ccf0dfc 100644 --- a/config/test.exs +++ b/config/test.exs @@ -9,17 +9,16 @@ config :bcrypt_elixir, :log_rounds, 1 # to provide built-in test partitioning in CI environment. # Run `mix help test` for more information. config :cannery, Cannery.Repo, - username: "postgres", - password: "postgres", - hostname: "localhost", - database: "cannery_test#{System.get_env("MIX_TEST_PARTITION")}", + url: + System.get_env("DATABASE_URL") || + "ecto://postgres:postgres@localhost/cannery_test#{System.get_env("MIX_TEST_PARTITION")}", pool: Ecto.Adapters.SQL.Sandbox, pool_size: 10 # We don't run a server during test. If one is required, # you can enable the server option below. config :cannery, CanneryWeb.Endpoint, - http: [ip: {127, 0, 0, 1}, port: 4002], + http: [ip: {0, 0, 0, 0}, port: 4002], secret_key_base: "S3qq9QtUdsFtlYej+HTjAVN95uP5i5tf2sPYINWSQfCKJghFj2B1+wTAoljZyHOK", server: false diff --git a/lib/cannery/invites.ex b/lib/cannery/invites.ex index 92fe810a..9e95aae1 100644 --- a/lib/cannery/invites.ex +++ b/lib/cannery/invites.ex @@ -96,7 +96,8 @@ defmodule Cannery.Invites do {:error, %Ecto.Changeset{}} """ - @spec create_invite(Accounts.User.t() | Ecto.UUID.t(), map()) :: Invite.t() + @spec create_invite(user_or_user_id :: Accounts.User.t() | Ecto.UUID.t(), attrs :: map()) :: + Invite.t() def create_invite(%{id: user_id}, attrs) do create_invite(user_id, attrs) end diff --git a/test/cannery/accounts_test.exs b/test/cannery/accounts_test.exs index 85e85573..d3bf01a3 100644 --- a/test/cannery/accounts_test.exs +++ b/test/cannery/accounts_test.exs @@ -501,1069 +501,4 @@ defmodule Cannery.AccountsTest do refute inspect(%User{password: "123456"}) =~ "password: \"123456\"" end end - import Cannery.AccountsFixtures - alias Cannery.Accounts.{User, UserToken} - - describe "get_user_by_email/1" do - test "does not return the user if the email does not exist" do - refute Accounts.get_user_by_email("unknown@example.com") - end - - test "returns the user if the email exists" do - %{id: id} = user = user_fixture() - assert %User{id: ^id} = Accounts.get_user_by_email(user.email) - end - end - - describe "get_user_by_email_and_password/2" do - test "does not return the user if the email does not exist" do - refute Accounts.get_user_by_email_and_password("unknown@example.com", "hello world!") - end - - test "does not return the user if the password is not valid" do - user = user_fixture() - refute Accounts.get_user_by_email_and_password(user.email, "invalid") - end - - test "returns the user if the email and password are valid" do - %{id: id} = user = user_fixture() - - assert %User{id: ^id} = - Accounts.get_user_by_email_and_password(user.email, valid_user_password()) - end - end - - describe "get_user!/1" do - test "raises if id is invalid" do - assert_raise Ecto.NoResultsError, fn -> - Accounts.get_user!(-1) - end - end - - test "returns the user with the given id" do - %{id: id} = user = user_fixture() - assert %User{id: ^id} = Accounts.get_user!(user.id) - end - end - - describe "register_user/1" do - test "requires email and password to be set" do - {:error, changeset} = Accounts.register_user(%{}) - - assert %{ - password: ["can't be blank"], - email: ["can't be blank"] - } = errors_on(changeset) - end - - test "validates email and password when given" do - {:error, changeset} = Accounts.register_user(%{email: "not valid", password: "not valid"}) - - assert %{ - email: ["must have the @ sign and no spaces"], - password: ["should be at least 12 character(s)"] - } = errors_on(changeset) - end - - 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}) - 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}) - 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)}) - 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(valid_user_attributes(email: email)) - assert user.email == email - assert is_binary(user.hashed_password) - assert is_nil(user.confirmed_at) - assert is_nil(user.password) - end - end - - describe "change_user_registration/2" do - test "returns a changeset" do - assert %Ecto.Changeset{} = changeset = Accounts.change_user_registration(%User{}) - assert changeset.required == [:password, :email] - end - - test "allows fields to be set" do - email = unique_user_email() - password = valid_user_password() - - changeset = - Accounts.change_user_registration( - %User{}, - valid_user_attributes(email: email, password: password) - ) - - assert changeset.valid? - assert get_change(changeset, :email) == email - assert get_change(changeset, :password) == password - assert is_nil(get_change(changeset, :hashed_password)) - end - end - - describe "change_user_email/2" do - test "returns a user changeset" do - assert %Ecto.Changeset{} = changeset = Accounts.change_user_email(%User{}) - assert changeset.required == [:email] - end - end - - describe "apply_user_email/3" do - setup do - %{user: user_fixture()} - end - - test "requires email to change", %{user: user} do - {:error, changeset} = Accounts.apply_user_email(user, valid_user_password(), %{}) - assert %{email: ["did not change"]} = errors_on(changeset) - end - - test "validates email", %{user: user} do - {:error, changeset} = - Accounts.apply_user_email(user, valid_user_password(), %{email: "not valid"}) - - assert %{email: ["must have the @ sign and no spaces"]} = errors_on(changeset) - end - - test "validates maximum value for email for security", %{user: user} do - too_long = String.duplicate("db", 100) - - {:error, changeset} = - 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 - - test "validates email uniqueness", %{user: user} do - %{email: email} = user_fixture() - - {:error, changeset} = - 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()}) - - 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}) - assert user.email == email - assert Accounts.get_user!(user.id).email != email - end - end - - describe "deliver_update_email_instructions/3" do - setup do - %{user: user_fixture()} - end - - test "sends token through notification", %{user: user} do - token = - extract_user_token(fn url -> - Accounts.deliver_update_email_instructions(user, "current@example.com", url) - end) - - {:ok, token} = Base.url_decode64(token, padding: false) - assert user_token = Repo.get_by(UserToken, token: :crypto.hash(:sha256, token)) - assert user_token.user_id == user.id - assert user_token.sent_to == user.email - assert user_token.context == "change:current@example.com" - end - end - - describe "update_user_email/2" do - setup do - user = user_fixture() - email = unique_user_email() - - token = - extract_user_token(fn url -> - Accounts.deliver_update_email_instructions(%{user | email: email}, user.email, url) - end) - - %{user: user, token: token, email: email} - end - - test "updates the email with a valid token", %{user: user, token: token, email: email} do - assert Accounts.update_user_email(user, token) == :ok - changed_user = Repo.get!(User, user.id) - assert changed_user.email != user.email - assert changed_user.email == email - assert changed_user.confirmed_at - assert changed_user.confirmed_at != user.confirmed_at - refute Repo.get_by(UserToken, user_id: user.id) - end - - test "does not update email with invalid token", %{user: user} do - assert Accounts.update_user_email(user, "oops") == :error - assert Repo.get!(User, user.id).email == user.email - assert Repo.get_by(UserToken, user_id: user.id) - end - - test "does not update email if user email changed", %{user: user, token: token} do - assert Accounts.update_user_email(%{user | email: "current@example.com"}, token) == :error - assert Repo.get!(User, user.id).email == user.email - assert Repo.get_by(UserToken, user_id: user.id) - end - - test "does not update email if token expired", %{user: user, token: token} do - {1, nil} = Repo.update_all(UserToken, set: [inserted_at: ~N[2020-01-01 00:00:00]]) - assert Accounts.update_user_email(user, token) == :error - assert Repo.get!(User, user.id).email == user.email - assert Repo.get_by(UserToken, user_id: user.id) - end - end - - describe "change_user_password/2" do - test "returns a user changeset" do - assert %Ecto.Changeset{} = changeset = Accounts.change_user_password(%User{}) - assert changeset.required == [:password] - end - - test "allows fields to be set" do - changeset = - Accounts.change_user_password(%User{}, %{ - "password" => "new valid password" - }) - - assert changeset.valid? - assert get_change(changeset, :password) == "new valid password" - assert is_nil(get_change(changeset, :hashed_password)) - end - end - - describe "update_user_password/3" do - setup do - %{user: user_fixture()} - end - - test "validates password", %{user: user} do - {:error, changeset} = - Accounts.update_user_password(user, valid_user_password(), %{ - password: "not valid", - password_confirmation: "another" - }) - - assert %{ - password: ["should be at least 12 character(s)"], - password_confirmation: ["does not match password"] - } = errors_on(changeset) - end - - test "validates maximum values for password for security", %{user: user} do - too_long = String.duplicate("db", 100) - - {:error, changeset} = - 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()}) - - assert %{current_password: ["is not valid"]} = errors_on(changeset) - end - - test "updates the password", %{user: user} do - {:ok, user} = - Accounts.update_user_password(user, valid_user_password(), %{ - password: "new valid password" - }) - - assert is_nil(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.update_user_password(user, valid_user_password(), %{ - password: "new valid password" - }) - - refute Repo.get_by(UserToken, user_id: user.id) - end - end - - describe "generate_user_session_token/1" do - setup do - %{user: user_fixture()} - end - - test "generates a token", %{user: user} do - token = Accounts.generate_user_session_token(user) - assert user_token = Repo.get_by(UserToken, token: token) - assert user_token.context == "session" - - # Creating the same token for another user should fail - assert_raise Ecto.ConstraintError, fn -> - Repo.insert!(%UserToken{ - token: user_token.token, - user_id: user_fixture().id, - context: "session" - }) - end - end - end - - describe "get_user_by_session_token/1" do - setup do - user = user_fixture() - token = Accounts.generate_user_session_token(user) - %{user: user, token: token} - end - - test "returns user by token", %{user: user, token: token} do - assert session_user = Accounts.get_user_by_session_token(token) - assert session_user.id == user.id - end - - test "does not return user for invalid token" do - refute Accounts.get_user_by_session_token("oops") - end - - test "does not return user for expired token", %{token: token} do - {1, nil} = Repo.update_all(UserToken, set: [inserted_at: ~N[2020-01-01 00:00:00]]) - refute Accounts.get_user_by_session_token(token) - end - end - - describe "delete_session_token/1" do - test "deletes the token" do - user = user_fixture() - token = Accounts.generate_user_session_token(user) - assert Accounts.delete_session_token(token) == :ok - refute Accounts.get_user_by_session_token(token) - end - end - - describe "deliver_user_confirmation_instructions/2" do - setup do - %{user: user_fixture()} - end - - test "sends token through notification", %{user: user} do - token = - extract_user_token(fn url -> - Accounts.deliver_user_confirmation_instructions(user, url) - end) - - {:ok, token} = Base.url_decode64(token, padding: false) - assert user_token = Repo.get_by(UserToken, token: :crypto.hash(:sha256, token)) - assert user_token.user_id == user.id - assert user_token.sent_to == user.email - assert user_token.context == "confirm" - end - end - - describe "confirm_user/1" do - setup do - user = user_fixture() - - token = - extract_user_token(fn url -> - Accounts.deliver_user_confirmation_instructions(user, url) - end) - - %{user: user, token: token} - end - - test "confirms the email with a valid token", %{user: user, token: token} do - assert {:ok, confirmed_user} = Accounts.confirm_user(token) - assert confirmed_user.confirmed_at - assert confirmed_user.confirmed_at != user.confirmed_at - assert Repo.get!(User, user.id).confirmed_at - refute Repo.get_by(UserToken, user_id: user.id) - end - - test "does not confirm with invalid token", %{user: user} do - assert Accounts.confirm_user("oops") == :error - refute Repo.get!(User, user.id).confirmed_at - assert Repo.get_by(UserToken, user_id: user.id) - end - - test "does not confirm email if token expired", %{user: user, token: token} do - {1, nil} = Repo.update_all(UserToken, set: [inserted_at: ~N[2020-01-01 00:00:00]]) - assert Accounts.confirm_user(token) == :error - refute Repo.get!(User, user.id).confirmed_at - assert Repo.get_by(UserToken, user_id: user.id) - end - end - - describe "deliver_user_reset_password_instructions/2" do - setup do - %{user: user_fixture()} - end - - test "sends token through notification", %{user: user} do - token = - extract_user_token(fn url -> - Accounts.deliver_user_reset_password_instructions(user, url) - end) - - {:ok, token} = Base.url_decode64(token, padding: false) - assert user_token = Repo.get_by(UserToken, token: :crypto.hash(:sha256, token)) - assert user_token.user_id == user.id - assert user_token.sent_to == user.email - assert user_token.context == "reset_password" - end - end - - describe "get_user_by_reset_password_token/1" do - setup do - user = user_fixture() - - token = - extract_user_token(fn url -> - Accounts.deliver_user_reset_password_instructions(user, url) - end) - - %{user: user, token: token} - end - - test "returns the user with valid token", %{user: %{id: id}, token: token} do - assert %User{id: ^id} = Accounts.get_user_by_reset_password_token(token) - assert Repo.get_by(UserToken, user_id: id) - end - - test "does not return the user with invalid token", %{user: user} do - refute Accounts.get_user_by_reset_password_token("oops") - assert Repo.get_by(UserToken, user_id: user.id) - end - - test "does not return the user if token expired", %{user: user, token: token} do - {1, nil} = Repo.update_all(UserToken, set: [inserted_at: ~N[2020-01-01 00:00:00]]) - refute Accounts.get_user_by_reset_password_token(token) - assert Repo.get_by(UserToken, user_id: user.id) - end - end - - describe "reset_user_password/2" do - setup do - %{user: user_fixture()} - end - - test "validates password", %{user: user} do - {:error, changeset} = - Accounts.reset_user_password(user, %{ - password: "not valid", - password_confirmation: "another" - }) - - assert %{ - password: ["should be at least 12 character(s)"], - password_confirmation: ["does not match password"] - } = errors_on(changeset) - end - - 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}) - 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"}) - 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"}) - refute Repo.get_by(UserToken, user_id: user.id) - end - end - - describe "inspect/2" do - test "does not include password" do - refute inspect(%User{password: "123456"}) =~ "password: \"123456\"" - end - end - import Cannery.AccountsFixtures - alias Cannery.Accounts.{User, UserToken} - - describe "get_user_by_email/1" do - test "does not return the user if the email does not exist" do - refute Accounts.get_user_by_email("unknown@example.com") - end - - test "returns the user if the email exists" do - %{id: id} = user = user_fixture() - assert %User{id: ^id} = Accounts.get_user_by_email(user.email) - end - end - - describe "get_user_by_email_and_password/2" do - test "does not return the user if the email does not exist" do - refute Accounts.get_user_by_email_and_password("unknown@example.com", "hello world!") - end - - test "does not return the user if the password is not valid" do - user = user_fixture() - refute Accounts.get_user_by_email_and_password(user.email, "invalid") - end - - test "returns the user if the email and password are valid" do - %{id: id} = user = user_fixture() - - assert %User{id: ^id} = - Accounts.get_user_by_email_and_password(user.email, valid_user_password()) - end - end - - describe "get_user!/1" do - test "raises if id is invalid" do - assert_raise Ecto.NoResultsError, fn -> - Accounts.get_user!("11111111-1111-1111-1111-111111111111") - end - end - - test "returns the user with the given id" do - %{id: id} = user = user_fixture() - assert %User{id: ^id} = Accounts.get_user!(user.id) - end - end - - describe "register_user/1" do - test "requires email and password to be set" do - {:error, changeset} = Accounts.register_user(%{}) - - assert %{ - password: ["can't be blank"], - email: ["can't be blank"] - } = errors_on(changeset) - end - - test "validates email and password when given" do - {:error, changeset} = Accounts.register_user(%{email: "not valid", password: "not valid"}) - - assert %{ - email: ["must have the @ sign and no spaces"], - password: ["should be at least 12 character(s)"] - } = errors_on(changeset) - end - - 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}) - 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}) - 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)}) - 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(valid_user_attributes(email: email)) - assert user.email == email - assert is_binary(user.hashed_password) - assert is_nil(user.confirmed_at) - assert is_nil(user.password) - end - end - - describe "change_user_registration/2" do - test "returns a changeset" do - assert %Ecto.Changeset{} = changeset = Accounts.change_user_registration(%User{}) - assert changeset.required == [:password, :email] - end - - test "allows fields to be set" do - email = unique_user_email() - password = valid_user_password() - - changeset = - Accounts.change_user_registration( - %User{}, - valid_user_attributes(email: email, password: password) - ) - - assert changeset.valid? - assert get_change(changeset, :email) == email - assert get_change(changeset, :password) == password - assert is_nil(get_change(changeset, :hashed_password)) - end - end - - describe "change_user_email/2" do - test "returns a user changeset" do - assert %Ecto.Changeset{} = changeset = Accounts.change_user_email(%User{}) - assert changeset.required == [:email] - end - end - - describe "apply_user_email/3" do - setup do - %{user: user_fixture()} - end - - test "requires email to change", %{user: user} do - {:error, changeset} = Accounts.apply_user_email(user, valid_user_password(), %{}) - assert %{email: ["did not change"]} = errors_on(changeset) - end - - test "validates email", %{user: user} do - {:error, changeset} = - Accounts.apply_user_email(user, valid_user_password(), %{email: "not valid"}) - - assert %{email: ["must have the @ sign and no spaces"]} = errors_on(changeset) - end - - test "validates maximum value for email for security", %{user: user} do - too_long = String.duplicate("db", 100) - - {:error, changeset} = - 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 - - test "validates email uniqueness", %{user: user} do - %{email: email} = user_fixture() - - {:error, changeset} = - 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()}) - - 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}) - assert user.email == email - assert Accounts.get_user!(user.id).email != email - end - end - - describe "deliver_update_email_instructions/3" do - setup do - %{user: user_fixture()} - end - - test "sends token through notification", %{user: user} do - token = - extract_user_token(fn url -> - Accounts.deliver_update_email_instructions(user, "current@example.com", url) - end) - - {:ok, token} = Base.url_decode64(token, padding: false) - assert user_token = Repo.get_by(UserToken, token: :crypto.hash(:sha256, token)) - assert user_token.user_id == user.id - assert user_token.sent_to == user.email - assert user_token.context == "change:current@example.com" - end - end - - describe "update_user_email/2" do - setup do - user = user_fixture() - email = unique_user_email() - - token = - extract_user_token(fn url -> - Accounts.deliver_update_email_instructions(%{user | email: email}, user.email, url) - end) - - %{user: user, token: token, email: email} - end - - test "updates the email with a valid token", %{user: user, token: token, email: email} do - assert Accounts.update_user_email(user, token) == :ok - changed_user = Repo.get!(User, user.id) - assert changed_user.email != user.email - assert changed_user.email == email - assert changed_user.confirmed_at - assert changed_user.confirmed_at != user.confirmed_at - refute Repo.get_by(UserToken, user_id: user.id) - end - - test "does not update email with invalid token", %{user: user} do - assert Accounts.update_user_email(user, "oops") == :error - assert Repo.get!(User, user.id).email == user.email - assert Repo.get_by(UserToken, user_id: user.id) - end - - test "does not update email if user email changed", %{user: user, token: token} do - assert Accounts.update_user_email(%{user | email: "current@example.com"}, token) == :error - assert Repo.get!(User, user.id).email == user.email - assert Repo.get_by(UserToken, user_id: user.id) - end - - test "does not update email if token expired", %{user: user, token: token} do - {1, nil} = Repo.update_all(UserToken, set: [inserted_at: ~N[2020-01-01 00:00:00]]) - assert Accounts.update_user_email(user, token) == :error - assert Repo.get!(User, user.id).email == user.email - assert Repo.get_by(UserToken, user_id: user.id) - end - end - - describe "change_user_password/2" do - test "returns a user changeset" do - assert %Ecto.Changeset{} = changeset = Accounts.change_user_password(%User{}) - assert changeset.required == [:password] - end - - test "allows fields to be set" do - changeset = - Accounts.change_user_password(%User{}, %{ - "password" => "new valid password" - }) - - assert changeset.valid? - assert get_change(changeset, :password) == "new valid password" - assert is_nil(get_change(changeset, :hashed_password)) - end - end - - describe "update_user_password/3" do - setup do - %{user: user_fixture()} - end - - test "validates password", %{user: user} do - {:error, changeset} = - Accounts.update_user_password(user, valid_user_password(), %{ - password: "not valid", - password_confirmation: "another" - }) - - assert %{ - password: ["should be at least 12 character(s)"], - password_confirmation: ["does not match password"] - } = errors_on(changeset) - end - - test "validates maximum values for password for security", %{user: user} do - too_long = String.duplicate("db", 100) - - {:error, changeset} = - 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()}) - - assert %{current_password: ["is not valid"]} = errors_on(changeset) - end - - test "updates the password", %{user: user} do - {:ok, user} = - Accounts.update_user_password(user, valid_user_password(), %{ - password: "new valid password" - }) - - assert is_nil(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.update_user_password(user, valid_user_password(), %{ - password: "new valid password" - }) - - refute Repo.get_by(UserToken, user_id: user.id) - end - end - - describe "generate_user_session_token/1" do - setup do - %{user: user_fixture()} - end - - test "generates a token", %{user: user} do - token = Accounts.generate_user_session_token(user) - assert user_token = Repo.get_by(UserToken, token: token) - assert user_token.context == "session" - - # Creating the same token for another user should fail - assert_raise Ecto.ConstraintError, fn -> - Repo.insert!(%UserToken{ - token: user_token.token, - user_id: user_fixture().id, - context: "session" - }) - end - end - end - - describe "get_user_by_session_token/1" do - setup do - user = user_fixture() - token = Accounts.generate_user_session_token(user) - %{user: user, token: token} - end - - test "returns user by token", %{user: user, token: token} do - assert session_user = Accounts.get_user_by_session_token(token) - assert session_user.id == user.id - end - - test "does not return user for invalid token" do - refute Accounts.get_user_by_session_token("oops") - end - - test "does not return user for expired token", %{token: token} do - {1, nil} = Repo.update_all(UserToken, set: [inserted_at: ~N[2020-01-01 00:00:00]]) - refute Accounts.get_user_by_session_token(token) - end - end - - describe "delete_session_token/1" do - test "deletes the token" do - user = user_fixture() - token = Accounts.generate_user_session_token(user) - assert Accounts.delete_session_token(token) == :ok - refute Accounts.get_user_by_session_token(token) - end - end - - describe "deliver_user_confirmation_instructions/2" do - setup do - %{user: user_fixture()} - end - - test "sends token through notification", %{user: user} do - token = - extract_user_token(fn url -> - Accounts.deliver_user_confirmation_instructions(user, url) - end) - - {:ok, token} = Base.url_decode64(token, padding: false) - assert user_token = Repo.get_by(UserToken, token: :crypto.hash(:sha256, token)) - assert user_token.user_id == user.id - assert user_token.sent_to == user.email - assert user_token.context == "confirm" - end - end - - describe "confirm_user/1" do - setup do - user = user_fixture() - - token = - extract_user_token(fn url -> - Accounts.deliver_user_confirmation_instructions(user, url) - end) - - %{user: user, token: token} - end - - test "confirms the email with a valid token", %{user: user, token: token} do - assert {:ok, confirmed_user} = Accounts.confirm_user(token) - assert confirmed_user.confirmed_at - assert confirmed_user.confirmed_at != user.confirmed_at - assert Repo.get!(User, user.id).confirmed_at - refute Repo.get_by(UserToken, user_id: user.id) - end - - test "does not confirm with invalid token", %{user: user} do - assert Accounts.confirm_user("oops") == :error - refute Repo.get!(User, user.id).confirmed_at - assert Repo.get_by(UserToken, user_id: user.id) - end - - test "does not confirm email if token expired", %{user: user, token: token} do - {1, nil} = Repo.update_all(UserToken, set: [inserted_at: ~N[2020-01-01 00:00:00]]) - assert Accounts.confirm_user(token) == :error - refute Repo.get!(User, user.id).confirmed_at - assert Repo.get_by(UserToken, user_id: user.id) - end - end - - describe "deliver_user_reset_password_instructions/2" do - setup do - %{user: user_fixture()} - end - - test "sends token through notification", %{user: user} do - token = - extract_user_token(fn url -> - Accounts.deliver_user_reset_password_instructions(user, url) - end) - - {:ok, token} = Base.url_decode64(token, padding: false) - assert user_token = Repo.get_by(UserToken, token: :crypto.hash(:sha256, token)) - assert user_token.user_id == user.id - assert user_token.sent_to == user.email - assert user_token.context == "reset_password" - end - end - - describe "get_user_by_reset_password_token/1" do - setup do - user = user_fixture() - - token = - extract_user_token(fn url -> - Accounts.deliver_user_reset_password_instructions(user, url) - end) - - %{user: user, token: token} - end - - test "returns the user with valid token", %{user: %{id: id}, token: token} do - assert %User{id: ^id} = Accounts.get_user_by_reset_password_token(token) - assert Repo.get_by(UserToken, user_id: id) - end - - test "does not return the user with invalid token", %{user: user} do - refute Accounts.get_user_by_reset_password_token("oops") - assert Repo.get_by(UserToken, user_id: user.id) - end - - test "does not return the user if token expired", %{user: user, token: token} do - {1, nil} = Repo.update_all(UserToken, set: [inserted_at: ~N[2020-01-01 00:00:00]]) - refute Accounts.get_user_by_reset_password_token(token) - assert Repo.get_by(UserToken, user_id: user.id) - end - end - - describe "reset_user_password/2" do - setup do - %{user: user_fixture()} - end - - test "validates password", %{user: user} do - {:error, changeset} = - Accounts.reset_user_password(user, %{ - password: "not valid", - password_confirmation: "another" - }) - - assert %{ - password: ["should be at least 12 character(s)"], - password_confirmation: ["does not match password"] - } = errors_on(changeset) - end - - 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}) - 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"}) - 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"}) - refute Repo.get_by(UserToken, user_id: user.id) - end - end - - describe "inspect/2" do - test "does not include password" do - refute inspect(%User{password: "123456"}) =~ "password: \"123456\"" - end - end - - describe "invites" do - alias Cannery.Accounts.Invite - - @valid_attrs %{name: "some name", token: "some token"} - @update_attrs %{name: "some updated name", token: "some updated token"} - @invalid_attrs %{name: nil, token: nil} - - def invite_fixture(attrs \\ %{}) do - {:ok, invite} = - attrs - |> Enum.into(@valid_attrs) - |> Accounts.create_invite() - - invite - end - - test "list_invites/0 returns all invites" do - invite = invite_fixture() - assert Accounts.list_invites() == [invite] - end - - test "get_invite!/1 returns the invite with given id" do - invite = invite_fixture() - assert Accounts.get_invite!(invite.id) == invite - end - - test "create_invite/1 with valid data creates a invite" do - assert {:ok, %Invite{} = invite} = Accounts.create_invite(@valid_attrs) - assert invite.name == "some name" - assert invite.token == "some token" - end - - test "create_invite/1 with invalid data returns error changeset" do - assert {:error, %Ecto.Changeset{}} = Accounts.create_invite(@invalid_attrs) - end - - test "update_invite/2 with valid data updates the invite" do - invite = invite_fixture() - assert {:ok, %Invite{} = invite} = Accounts.update_invite(invite, @update_attrs) - assert invite.name == "some updated name" - assert invite.token == "some updated token" - end - - test "update_invite/2 with invalid data returns error changeset" do - invite = invite_fixture() - assert {:error, %Ecto.Changeset{}} = Accounts.update_invite(invite, @invalid_attrs) - assert invite == Accounts.get_invite!(invite.id) - end - - test "delete_invite/1 deletes the invite" do - invite = invite_fixture() - assert {:ok, %Invite{}} = Accounts.delete_invite(invite) - assert_raise Ecto.NoResultsError, fn -> Accounts.get_invite!(invite.id) end - end - - test "change_invite/1 returns a invite changeset" do - invite = invite_fixture() - assert %Ecto.Changeset{} = Accounts.change_invite(invite) - end - end end diff --git a/test/cannery/ammo_test.exs b/test/cannery/ammo_test.exs index d9f07981..e0d6ed70 100644 --- a/test/cannery/ammo_test.exs +++ b/test/cannery/ammo_test.exs @@ -6,9 +6,30 @@ defmodule Cannery.AmmoTest do describe "ammo_types" do alias Cannery.Ammo.AmmoType - @valid_attrs %{bullet_type: "some bullet_type", case_material: "some case_material", desc: "some desc", manufacturer: "some manufacturer", name: "some name", weight: 120.5} - @update_attrs %{bullet_type: "some updated bullet_type", case_material: "some updated case_material", desc: "some updated desc", manufacturer: "some updated manufacturer", name: "some updated name", weight: 456.7} - @invalid_attrs %{bullet_type: nil, case_material: nil, desc: nil, manufacturer: nil, name: nil, weight: nil} + @valid_attrs %{ + "bullet_type" => "some bullet_type", + "case_material" => "some case_material", + "desc" => "some desc", + "manufacturer" => "some manufacturer", + "name" => "some name", + "weight" => 120.5 + } + @update_attrs %{ + "bullet_type" => "some updated bullet_type", + "case_material" => "some updated case_material", + "desc" => "some updated desc", + "manufacturer" => "some updated manufacturer", + "name" => "some updated name", + "weight" => 456.7 + } + @invalid_attrs %{ + "bullet_type" => nil, + "case_material" => nil, + "desc" => nil, + "manufacturer" => nil, + "name" => nil, + "weight" => nil + } def ammo_type_fixture(attrs \\ %{}) do {:ok, ammo_type} = diff --git a/test/cannery/containers_test.exs b/test/cannery/containers_test.exs index e8e6c74d..63f14e63 100644 --- a/test/cannery/containers_test.exs +++ b/test/cannery/containers_test.exs @@ -6,8 +6,18 @@ defmodule Cannery.ContainersTest do describe "containers" do alias Cannery.Containers.Container - @valid_attrs %{desc: "some desc", location: "some location", name: "some name", type: "some type"} - @update_attrs %{desc: "some updated desc", location: "some updated location", name: "some updated name", type: "some updated type"} + @valid_attrs %{ + "desc" => "some desc", + "location" => "some location", + "name" => "some name", + "type" => "some type" + } + @update_attrs %{ + "desc" => "some updated desc", + "location" => "some updated location", + "name" => "some updated name", + "type" => "some updated type" + } @invalid_attrs %{desc: nil, location: nil, name: nil, type: nil} def container_fixture(attrs \\ %{}) do @@ -43,7 +53,10 @@ defmodule Cannery.ContainersTest do test "update_container/2 with valid data updates the container" do container = container_fixture() - assert {:ok, %Container{} = container} = Containers.update_container(container, @update_attrs) + + assert {:ok, %Container{} = container} = + Containers.update_container(container, @update_attrs) + assert container.desc == "some updated desc" assert container.location == "some updated location" assert container.name == "some updated name" diff --git a/test/cannery/invites_test.exs b/test/cannery/invites_test.exs index 4d90b0ca..41bbcf8c 100644 --- a/test/cannery/invites_test.exs +++ b/test/cannery/invites_test.exs @@ -1,20 +1,28 @@ defmodule Cannery.InvitesTest do use Cannery.DataCase - alias Cannery.Invites + alias Cannery.{AccountsFixtures, Invites} describe "invites" do alias Cannery.Invites.Invite - @valid_attrs %{name: "some name", token: "some token"} - @update_attrs %{name: "some updated name", token: "some updated token"} - @invalid_attrs %{name: nil, token: nil} + @valid_attrs %{ + "name" => "some name", + "token" => "some token" + } + @update_attrs %{ + "name" => "some updated name", + "token" => "some updated token" + } + @invalid_attrs %{ + "name" => nil, + "token" => nil + } def invite_fixture(attrs \\ %{}) do {:ok, invite} = - attrs - |> Enum.into(@valid_attrs) - |> Invites.create_invite() + AccountsFixtures.user_fixture() + |> Invites.create_invite(attrs |> Enum.into(@valid_attrs)) invite end diff --git a/test/cannery/tags_test.exs b/test/cannery/tags_test.exs index 1dac60a9..0066a9c9 100644 --- a/test/cannery/tags_test.exs +++ b/test/cannery/tags_test.exs @@ -1,18 +1,33 @@ defmodule Cannery.TagsTest do use Cannery.DataCase - alias Cannery.Tags + alias Cannery.{AccountsFixtures, Tags} describe "tags" do alias Cannery.Tags.Tag - @valid_attrs %{bg_color: "some bg-color", name: "some name", text_color: "some text-color"} - @update_attrs %{bg_color: "some updated bg-color", name: "some updated name", text_color: "some updated text-color"} - @invalid_attrs %{bg_color: nil, name: nil, text_color: nil} + @valid_attrs %{ + "bg_color" => "some bg-color", + "name" => "some name", + "text_color" => "some text-color" + } + @update_attrs %{ + "bg_color" => "some updated bg-color", + "name" => "some updated name", + "text_color" => "some updated text-color" + } + @invalid_attrs %{ + "bg_color" => nil, + "name" => nil, + "text_color" => nil + } def tag_fixture(attrs \\ %{}) do + %{id: user_id} = AccountsFixtures.user_fixture() + {:ok, tag} = attrs + |> Map.put("user_id", user_id) |> Enum.into(@valid_attrs) |> Tags.create_tag() @@ -31,9 +46,9 @@ defmodule Cannery.TagsTest do test "create_tag/1 with valid data creates a tag" do assert {:ok, %Tag{} = tag} = Tags.create_tag(@valid_attrs) - assert tag.bg-color == "some bg-color" + assert tag.bg_color == "some bg-color" assert tag.name == "some name" - assert tag.text-color == "some text-color" + assert tag.text_color == "some text-color" end test "create_tag/1 with invalid data returns error changeset" do @@ -43,9 +58,9 @@ defmodule Cannery.TagsTest do test "update_tag/2 with valid data updates the tag" do tag = tag_fixture() assert {:ok, %Tag{} = tag} = Tags.update_tag(tag, @update_attrs) - assert tag.bg-color == "some updated bg-color" + assert tag.bg_color == "some updated bg-color" assert tag.name == "some updated name" - assert tag.text-color == "some updated text-color" + assert tag.text_color == "some updated text-color" end test "update_tag/2 with invalid data returns error changeset" do diff --git a/test/cannery_web/live/ammo_type_live_test.exs b/test/cannery_web/live/ammo_type_live_test.exs index 14b4eb06..51eb0277 100644 --- a/test/cannery_web/live/ammo_type_live_test.exs +++ b/test/cannery_web/live/ammo_type_live_test.exs @@ -5,9 +5,30 @@ defmodule CanneryWeb.AmmoTypeLiveTest do alias Cannery.Ammo - @create_attrs %{bullet_type: "some bullet_type", case_material: "some case_material", desc: "some desc", manufacturer: "some manufacturer", name: "some name", weight: 120.5} - @update_attrs %{bullet_type: "some updated bullet_type", case_material: "some updated case_material", desc: "some updated desc", manufacturer: "some updated manufacturer", name: "some updated name", weight: 456.7} - @invalid_attrs %{bullet_type: nil, case_material: nil, desc: nil, manufacturer: nil, name: nil, weight: nil} + @create_attrs %{ + "bullet_type" => "some bullet_type", + "case_material" => "some case_material", + "desc" => "some desc", + "manufacturer" => "some manufacturer", + "name" => "some name", + "weight" => 120.5 + } + @update_attrs %{ + "bullet_type" => "some updated bullet_type", + "case_material" => "some updated case_material", + "desc" => "some updated desc", + "manufacturer" => "some updated manufacturer", + "name" => "some updated name", + "weight" => 456.7 + } + @invalid_attrs %{ + "bullet_type" => nil, + "case_material" => nil, + "desc" => nil, + "manufacturer" => nil, + "name" => nil, + "weight" => nil + } defp fixture(:ammo_type) do {:ok, ammo_type} = Ammo.create_ammo_type(@create_attrs) diff --git a/test/cannery_web/live/container_live_test.exs b/test/cannery_web/live/container_live_test.exs index 75e2ac0a..7a514999 100644 --- a/test/cannery_web/live/container_live_test.exs +++ b/test/cannery_web/live/container_live_test.exs @@ -5,8 +5,18 @@ defmodule CanneryWeb.ContainerLiveTest do alias Cannery.Containers - @create_attrs %{desc: "some desc", location: "some location", name: "some name", type: "some type"} - @update_attrs %{desc: "some updated desc", location: "some updated location", name: "some updated name", type: "some updated type"} + @create_attrs %{ + "desc" => "some desc", + "location" => "some location", + "name" => "some name", + "type" => "some type" + } + @update_attrs %{ + "desc" => "some updated desc", + "location" => "some updated location", + "name" => "some updated name", + "type" => "some updated type" + } @invalid_attrs %{desc: nil, location: nil, name: nil, type: nil} defp fixture(:container) do diff --git a/test/cannery_web/live/tag_live_test.exs b/test/cannery_web/live/tag_live_test.exs index 4a4e7f2a..63e5a5c4 100644 --- a/test/cannery_web/live/tag_live_test.exs +++ b/test/cannery_web/live/tag_live_test.exs @@ -5,9 +5,21 @@ defmodule CanneryWeb.TagLiveTest do alias Cannery.Tags - @create_attrs %{bg_color: "some bg-color", name: "some name", text_color: "some text-color"} - @update_attrs %{bg_color: "some updated bg-color", name: "some updated name", text_color: "some updated text-color"} - @invalid_attrs %{bg_color: nil, name: nil, text_color: nil} + @create_attrs %{ + "bg_color" => "some bg-color", + "name" => "some name", + "text_color" => "some text-color" + } + @update_attrs %{ + "bg_color" => "some updated bg-color", + "name" => "some updated name", + "text_color" => "some updated text-color" + } + @invalid_attrs %{ + "bg_color" => nil, + "name" => nil, + "text_color" => nil + } defp fixture(:tag) do {:ok, tag} = Tags.create_tag(@create_attrs) @@ -26,7 +38,7 @@ defmodule CanneryWeb.TagLiveTest do {:ok, _index_live, html} = live(conn, Routes.tag_index_path(conn, :index)) assert html =~ "Listing Tags" - assert html =~ tag.bg-color + assert html =~ tag.bg_color end test "saves new tag", %{conn: conn} do @@ -88,7 +100,7 @@ defmodule CanneryWeb.TagLiveTest do {:ok, _show_live, html} = live(conn, Routes.tag_show_path(conn, :show, tag)) assert html =~ "Show Tag" - assert html =~ tag.bg-color + assert html =~ tag.bg_color end test "updates tag within modal", %{conn: conn, tag: tag} do diff --git a/test/support/fixtures/accounts_fixtures.ex b/test/support/fixtures/accounts_fixtures.ex index d777d964..b0135ebc 100644 --- a/test/support/fixtures/accounts_fixtures.ex +++ b/test/support/fixtures/accounts_fixtures.ex @@ -4,9 +4,13 @@ defmodule Cannery.AccountsFixtures do entities via the `Cannery.Accounts` context. """ + alias Cannery.{Accounts} + 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 {:ok, user} = attrs @@ -14,7 +18,7 @@ defmodule Cannery.AccountsFixtures do email: unique_user_email(), password: valid_user_password() }) - |> Cannery.Accounts.register_user() + |> Accounts.register_user() user end