Jez Caudle
Jez Caudle

Reputation: 351

Functional testing with Rails and Devise. What to put in my fixtures?

Hi I'm wanting to do some functional testing of my Rails 3 app that uses Devise and CanCan.

In my User model I have the users age, I want to test that a user can only visit a certain page if they are:

  1. Logged in
  2. Over 35

I have seen in the Devise document that I can use: *sign_in* and I have put it in my tests and it appears to work - the test doesn't error because I have:

include Devise::TestHelpers

in my *test_helper.rb*

When I take it out my test does error because *sign_in* is not defined. So it is not a helper problem.

When I run the test and check to see if span#loggedin has one occurrence the test fails because there is 0 occurrences. span#loggedin only appears *if user_signed_in?*

What do I need to put in my fixtures or tests to create a test user who is also a fully signed up user (confirmed etc)?

View Code:

<% if user_signed_in? %>
     <span id="loggedin">User is signed in</span>
     User age is <span id="age"><%= current_user.age.to_s %></span>
<% end %>

Test Code:

test "should get index" do
    sign_in :one
    get :index
    assert_response :success
    assert_select 'span#loggedin', :count => 1
end

Fixture:

one:
 email: [email protected]
 age: 36

It works okay in development when I manually login but I'm hoping to automate it all - the point of testing really!!

Upvotes: 27

Views: 10574

Answers (4)

ReggieB
ReggieB

Reputation: 8212

Solution for Devise pre 3.2.0

I think this might be what you are looking for:

User.new.send(:password_digest, 'password')

It works when the salt is nil.

And therefore in your fixture you can do this:

one:
  email: '[email protected]'
  encrypted_password: <%= User.new.send(:password_digest, 'password') %>

Solution for Devise versions 3.2.0 to 3.5.0

At Devise 3.2.0, a method was created precisely for this purpose (@Inkling update). For these versions the encrypted_password should be defined like this:

encrypted_password: <%= Devise.bcrypt(User, 'password') %>

where User is the class of your user model.

Note that this only applies if you're using the default encryption algorithm (bcrypt).


Solution for Devise versions 3.5.1 and above

As Katarzyna has pointed out: Device.bcrypt has been deprecated in version 3.5.1. From that version on, the encrypted_password should be defined like this:

encrypted_password: <%= Devise::Encryptor.digest(User, 'password') %>

Upvotes: 66

maurymmarques
maurymmarques

Reputation: 329

It's working for me.

I didn't change anything on my user fixture, it's like this:

one:
  id: 1
  name: MyString
  email: [email protected]
  group_id: 2
  encrypted_password: <%= Devise.bcrypt(User, 'password') %>

But I changed my test_helper.rb and I added this to the class ActionController (this will work for all controllers tests):

class ActionController::TestCase
    include Devise::TestHelpers

    setup do
        sign_in users(:one)
    end
end

Upvotes: 1

pablo
pablo

Reputation: 404

Just one more hint. This worked great for me:

http://brandonhilkert.com/blog/managing-login-passwords-for-capybara-with-minitest-and-rails-fixtures/

And it seems to be DRY and nice solution.

Upvotes: 2

Jez Caudle
Jez Caudle

Reputation: 351

I have sorted out the problem - I was logging in the user incorrectly.

My test should hare read:

test "should get index" do
    @user = users(:one)
    sign_in @user
    get :index
    assert_response :success
    assert_select 'span#loggedin', :count => 1
 end

This also works and eliminates a line of code:

test "should get index" do
    sign_in users(:one)
    get :index
    assert_response :success
    assert_select 'span#loggedin', :count => 1
end

My understanding of Fixtures was lacking ...

But back to the question - what to put in fixtures:

one:
 email: [email protected]
 encrypted_password: $2a$10$PoBe1MvkoGJsjMVTEjKqgeBUp.xdfzWoiDjBzQhtLAj16NqIa2fOy
 password_salt: $2a$10$PoBe1MvkoGJsjMVTEjKqge
 reset_password_token: nil
 remember_token: nil
 remember_created_at: nil
 sign_in_count: 1
 current_sign_in_at: 2011-01-02 08:31:23
 last_sign_in_at: 2011-01-02 08:31:23
 current_sign_in_ip: 127.0.0.1
 last_sign_in_ip: 127.0.0.1
 confirmation_token: nil
 confirmed_at: 2011-01-02 08:31:23
 confirmation_sent_at: 2011-01-02 08:30:59
 failed_attempts: 0
 unlock_token: nil
 locked_at: nil
 authentication_token: nil
 created_at: 2011-01-02 08:30:59
 updated_at: 2011-01-02 08:31:23
 age: 36

Now it works. If there is an easier that generating a user in dev and pasting the data into a fixture please do post.

Upvotes: 8

Related Questions