1
votes

I feel like this should be a simple question, yet I've struggled to find the answer. I have set up devise for authentication in my Rails project, and it's working great. I've also customized the password validation and the login requirements. Specifically, one should be able to login with either their username or email, and the email should not be case sensitive.

How to I test this in my model specs? Specifically testing:

  1. Login with email (all lower) and password is valid
  2. Login with email (all upper) and password is valid
  3. Login with username and password is valid
  4. Login with username (jumbled case) and password is invalid

Basically, I just need one function that takes in the login details and tell me whether or not devise will authenticate it. But I can't find such a function in any examples or any way to construct such a function in the devise documentation.

I am confident that it is actually working, and CAN test it in my request specs, but as it is defined in the model it feels like their ought to be a model test as well.

The only devise testing I've regularly found is in the controller, which doesn't help as it just automatically signs in the user without requiring the login details.

1
Why do you want to test something that Devise itself should've already tested? Do you have any custom code around it that could be interfering? - Ryan Bigg
That's exactly why I WANT to test it. I love using other gems rather than rewriting stuff myself, but there's a non-zero chance that functionality in them could break with future changes (or even be broken now). I don't feel that redundant testing is a bad thing. - Bryce

1 Answers

3
votes

Well, there are two distinct components here:

1) Finding a user
2) Validating the password for the user

Finding a user is handled by find_for_database_authentication (info on having username and email handled by "login")

The validating of a password is handled by the valid_password? method (info)

So, you'd want to break this test up into:

context "finding a user" do
  let(:user) { FactoryGirl.create(:user) }

  it "can find by lower email" do
    User.find_for_database_authentication( {login: user.email.downcase} ).should eq(user)
  end

  it "can find by upper email" do
    User.find_for_database_authentication( {login: user.email.upcase} ).should eq(user)
  end

  it "can find by jumbled username" do
    scrambled_username = user.username.downcase.chars.map{|c| rand() > 0.5 ? c.capitalize : c}.join
    User.find_for_database_authentication( {login: username} ).should eq(user)
  end
end

context "authenticating a user" do
  let(:user) { FactoryGirl.create(:user, password: "password123", password_confirmation: "password123") }

  it "will validate a correct password" do
    user.valid_password?("password123").should be_true
  end
  it "will not validate an incorrect password" do
    user.valid_password?("bad-password").should be_false
  end
end