Test to verify unique constraint no longer working

Hello!

I’m trying to create a test to verify unique emails, I’ve already asked for it here but, today I wanted to implement it in another application and it doesn’t work.

My test

test "email has been taken" do
    user = User.registration_changeset(%User{}, @valid_attrs)
    assert {:ok, _user } = Repo.insert(user)
    
    imposter = User.registration_changeset(%User{}, @valid_attrs)
    
    assert {:error, changeset} = Repo.insert(imposter)
    assert changeset.errors[:email] == {"Email is already taken", []}
end

The changesets

def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:username, :email, :github, :twitter, :website])
    |> validate_required([:username, :email])
    |> unique_constraint(:username)
    |> unique_constraint(:email, message: "Email is already taken")
    |> validate_length(:username, min: 3, max: 40)
    |> validate_format(:username, ~r/^[A-Za-z0-9]+$/, message: "Username must only contain letters and numbers")
    |> validate_length(:email, min: 6, max: 40)
    |> validate_format(:email, ~r/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/)
    |> validate_length(:github, min: 3, max: 40)
    |> validate_format(:github, ~r/^[A-Za-z0-9]+$/, message: "Include only your username")
    |> validate_length(:twitter, min: 3, max: 40)
    |> validate_format(:twitter, ~r/^[A-Za-z0-9._+-]+$/, message: "Invalid Twitter username format")
end
  
def registration_changeset(struct, params \\ %{}) do
    struct
    |> changeset(params)
    |> cast(params, [:password])
    |> validate_required([:password])
    |> validate_length(:password, min: 6)
    |> encrypt_password
end

However, I keep getting

  1. test email has been taken (LogMe.UserTest)
    test/models/user_test.exs:30
    Assertion with == failed
    code: changeset.errors()[:email] == {“Email is already taken”, []}
    left: nil
    right: {“Email is already taken”, []}
    stacktrace:
    test/models/user_test.exs:37: (test)

I have an unique index on my table for the emails

defmodule LogMe.Repo.Migrations.CreateUser do
  use Ecto.Migration

  def change do
    create table(:users) do
      add :username, :string, null: false
      add :email, :string, null: false
      add :encrypted_password, :string, null: false
      add :github, :string
      add :twitter, :string
      add :website, :string

      timestamps()
    end

    create unique_index(:users, [:username])
    create unique_index(:users, [:email])

  end
end

It did the trick on the other application, however, I can’t find out what is going on here.

Thanks for the help!

Might not exactly solve the issue but for me I was running into something similar when my test DB and dev db got out of sync. It might be worth running:

MIX_ENV=test mix ecto.dump
MIX_ENV=dev mix ecto.dump

and check they are the same.

If they aren’t, I fixed it by doing:

MIX_ENV=test mix ecto.drop
MIX_ENV=test mix ecto.create
MIX_ENV=test mix ecto.migrate

Didn’t work, I still get

  1. test email has been taken (LogMe.UserTest)
    test/models/user_test.exs:30
    Assertion with == failed
    code: changeset.errors()[:email] == {“Email is already taken”, []}
    left: nil
    right: {“Email is already taken”, []}
    stacktrace:
    test/models/user_test.exs:37: (test)

The insert is failing because the previous assertion is passing so are you able to inspect it?

assert {:error, changeset} = Repo.insert(imposter) |> IO.inspect

And paste the result?