wolfiton

wolfiton OP

Hi everyone,

I don’t understand why this test is failing instead of going to the changeset and give an error and pass the test. Because that error was expected in that test.

Expected result:

To append an error to the changeset and pass the tests for username to long and password to short

Test parts that fail because the password and users don’t match

test "does not accept long usernames" do
      attrs = Map.put(@valid_attrs, :username, String.duplicate("a", 30))
      {:error, changeset} = Accounts.register_user(attrs)

      assert %{username: ["should be at most 20 character(s)"]} = errors_on(changeset)
      assert Accounts.list_users() == []
    end

    test "requires password to be at least 6 chars long" do
      attrs = Map.put(@valid_attrs, :password, "12345")
      {:error, changeset} = Accounts.register_user(attrs)

      assert %{password: ["should be at least 6 character(s)"]} = errors_on(changeset)
      assert Accounts.list_users() == []
    end

Error trace:

rumbl mix test test/rumbl/accounts_test.exs

.

  1) test register_user/1 does not accept long usernames (Rumbl.AccountsTest)
     test/rumbl/accounts_test.exs:36
     ** (MatchError) no match of right hand side value: {:ok, %Rumbl.Accounts.User{__meta__: 
#Ecto.Schema.Metadata<:loaded, "users">, id: 18, inserted_at: ~N[2020-01-19 15:34:04], 
name: "User", password: "secret", password_hash: "$pbkdf2-sha512$160000$iahAZDIoM/oP/PA9AlAIXQ$mxd9aqd.QhF9MPPjhSOyu.QiMFIAdZkLUUXoRTbwpyoqB0V5af6FpfE/USCoAxMvC.HW1i1m.0B7o1JYHDAyDQ", updated_at: ~N[2020-01-19 15:34:04], username: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}}
     code: {:error, changeset} = Accounts.register_user(attrs)
     stacktrace:
       test/rumbl/accounts_test.exs:38: (test)



  2) test register_user/1 requires password to be at least 6 chars long (Rumbl.AccountsTest)
     test/rumbl/accounts_test.exs:44
     ** (MatchError) no match of right hand side value: {:ok, %Rumbl.Accounts.User{__meta__:
 #Ecto.Schema.Metadata<:loaded, "users">, id: 19, inserted_at: ~N[2020-01-19 15:34:05], 
name: "User", password: "12345", 
password_hash: 
"$pbkdf2-sha512$160000$g5239LoShgVmsdO7qvYzVQ$cJnOY1lKgDjsAYT7Svi2P58qZly0khxmhEwOMfYk6mELoOtxlKUe4YMC0AE8vf1.m7J0M8EdlQOsCly0hyGy7g", 
updated_at: ~N[2020-01-19 15:34:05], username: "eva"}}
     code: {:error, changeset} = Accounts.register_user(attrs)
     stacktrace:
       test/rumbl/accounts_test.exs:46: (test)

..

Finished in 5.5 seconds
5 tests, 2 failures

Randomized with seed 829346

Also the full test can be seen here

http://media.pragprog.com/titles/phoenix14/code/testing_mvc/listings/rumbl/test/rumbl/accounts_test.exs

Thanks in advance

First 10 of 10 Posts Switch mode

NobbZ

NobbZ

You have told us how the test looks like, but not the function under test, perhaps even the validations mihgt be of special interest here.

Also, if that book does it in a TDD manor, have you peeked at the next couple of pages if they do make the tests pass on the next couple of pages?

wolfiton

wolfiton OP

The book doesn’t do the tests in TDD so the accounts context and user changeset can be of interest here?

NobbZ

NobbZ

The tests are testing if names of certain lengths are invalid.

As the tests are currently failing because of a MatchError where you call the Accounts.register_user/1 with {:error, _} not matching some {:ok, _}, it is very likely that the length validations for the username are currently either implemented wrong or missing at all.

wolfiton

wolfiton OP

Here is the registration_changeset

def registration_changeset(user, params) do
    user
    |> changeset(params)
    |> cast(params, [:password])
    |> validate_required([:password])
    |> validate_length(:password, min: 5, max: 100)
    |> put_pass_hash()
  end
NobbZ

NobbZ

Okay, take a look at your changeset. It does not care for the name at all.

Also somewhere inbetween, there seems to happen something else, as the resulting struct has name: "User" in both cases, while you pass in your wrong name as :username.

wolfiton

wolfiton OP

Let me share the whole schema because the schema has also name and username in it one sec.

defmodule Rumbl.Accounts.User do
  use Ecto.Schema
  import Ecto.Changeset

  schema "users" do
    field :name, :string
    field :username, :string
    field :password, :string, virtual: true
    field :password_hash, :string

    timestamps()
  end

  def changeset(user, attrs) do
    user
    |> cast(attrs, [:name, :username])
    |> validate_required([:name, :username])
    |> validate_length(:username, min: 1, max: 75)
    |> unique_constraint(:username)
  end

  def registration_changeset(user, params) do
    user
    |> changeset(params)
    |> cast(params, [:password])
    |> validate_required([:password])
    |> validate_length(:password, min: 5, max: 100)
    |> put_pass_hash()
  end

  defp put_pass_hash(changeset) do
    case changeset do
      %Ecto.Changeset{valid?: true, changes: %{password: pass}} ->
        put_change(changeset, :password_hash, Pbkdf2.hash_pwd_salt(pass))

      _ ->
        changeset
    end
  end
end

Also the also the attrs are:

@valid_attrs %{
      name: "User",
      username: "eva",
      password: "secret"
    }
    @invalid_attrs %{}
NobbZ

NobbZ

Yes, now I see it. In both cases :username is set in the result. I just didn’t realize it in the mobile…

In the registration_changeset/1 you do not have any verification for the :username, its only in the changeset. Which one is called in the register_user/1?

wolfiton

wolfiton OP

Like this:

file: Account context

def create_user(attrs \\ %{}) do
    %User{}
    |> User.changeset(attrs)
    |> Repo.insert()
  end

  def change_registration(%User{} = user, params) do
    User.registration_changeset(user, params)
  end

  def register_user(attrs \\ %{}) do
    %User{}
    |> User.registration_changeset(attrs)
    |> Repo.insert()
  end

I think that the registration changeset gets all the changeset values form the default chnageset and adds only passoword and password_hash to register_changeset.

Also you are right I had a validate_length of 75 for username, changed it to 20.

Solved one error the username now passes the test

archdragon

archdragon

I think the problem here is much simpler.

In the test you write

but in the actual validation only 5 characters are required.

This is why password: "12345" returns {:ok, _} instead of an error.

Changing the validation to min: 6 should solve the problem :slight_smile:

wolfiton

wolfiton OP

Thanks @archdragon.

That was it I haven’t verified the changeset validation so my assertion couldn’t match.

These lines were the problems
Replace this

|> validate_length(:username, min: 1, max: 75)

with this

|> validate_length(:username, min: 1, max: 20)`

and this

|> validate_length(:password, min: 5, max: 100)

with this

|> validate_length(:password, min: 6, max: 20)

Now all tests are green and pass.

Thanks everyone for helping out

— All posts loaded —

Where Next? Top

Trending in Chat/Questions Top

krisleech
Hey folks, I’ve been using Elixir for over a couple of years (phx, ecto, broadway, oban). For this kind of work you do not tend, in my e...
New
mhindujadheerajsudan
Hi, I’m Dheeraj Sudan from the UK. I’m a software developer and also run a business with my wife Meenu Hinduja. I’m interested in getting...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New

We're in Beta

About us Mission Statement