2014-11-10 24 views
8

Per ragioni al di fuori del mio controllo, non posso usare RSpec per testare il mio progetto attuale. Sto provando a testare Devise Reset Password, e non riesco a trovare qualcosa che funzioni.Rails 4 + Devise: come scrivere un test per Devise Reset Password senza RSpec?

Ecco quello che ho finora:

require 'test_helper' 

class ResetPasswordTest < ActionDispatch::IntegrationTest 
    setup do 
    @user = users(:example) 
    end 

    test "reset user's password" do 
    old_password = @user.encrypted_password 

    puts @user.inspect 

    # This assertion works 
    assert_difference('ActionMailer::Base.deliveries.count', 1) do 
     post user_password_path, user: {email: @user.email} 
    end 

    # puts @user.reset_password_token => nil 
    # Not sure why this doesn't assign a reset password token to @user 

    patch "https://stackoverflow.com/users/password", user: { 
     reset_password_token: @user.reset_password_token, 
     password: "new-password", 
     password_confirmation: "new-password", 
    } 

    # I get a success here, but I'm not sure why, since reset password token is nil. 
    assert_response :success 

    # This assertion doesn't work. 
    assert_not_equal(@user.encrypted_password, old_password) 
    end 

end 

ho aggiunto alcuni commenti di cui sopra al punto in cui le cose non sembrano funzionare. Qualcuno ha un'idea o un'idea su come meglio testare questo?

risposta

6

Ho capito che è necessario ricaricare l'utente dopo aver inviato l'e-mail di reimpostazione della password e quando put si trova nel percorso /user/password. È inoltre necessario ottenere il token della password dall'e-mail poiché è diverso da quello memorizzato nel database.

require 'test_helper' 

class ResetPasswordTest < ActionDispatch::IntegrationTest 
    setup do 
    @user = users(:example) 
    end 

    test "reset user's password" do 
    # store old encrypted password 
    old_password = @user.encrypted_password 

    # check to ensure mailer sends reset password email 
    assert_difference('ActionMailer::Base.deliveries.count', 1) do 
     post user_password_path, user: {email: @user.email} 
     assert_redirected_to new_user_session_path 
    end 

    # Get the email, and get the reset password token from it 
    message = ActionMailer::Base.deliveries[0].to_s 
    rpt_index = message.index("reset_password_token")+"reset_password_token".length+1 
    reset_password_token = message[rpt_index...message.index("\"", rpt_index)] 

    # reload the user and ensure user.reset_password_token is present 
    # NOTE: user.reset_password_token and the token pulled from the email 
    # are DIFFERENT 
    @user.reload 
    assert_not_nil @user.reset_password_token 

    # Ensure that a bad token won't reset the password 
    put "https://stackoverflow.com/users/password", user: { 
     reset_password_token: "bad reset token", 
     password: "new-password", 
     password_confirmation: "new-password", 
    } 

    assert_match "error", response.body 
    assert_equal @user.encrypted_password, old_password 

    # Valid password update 
    put "https://stackoverflow.com/users/password", user: { 
     reset_password_token: reset_password_token, 
     password: "new-password", 
     password_confirmation: "new-password", 
    } 

    # After password update, signed in and redirected to root path 
    assert_redirected_to root_path 

    # Reload user and ensure that the password is updated. 
    @user.reload 
    assert_not_equal(@user.encrypted_password, old_password) 
    end 

end 
+0

Come si esegue questo test? e in quale directory si posiziona il file di test? –

+0

@MinaZaki Ho inserito questo test in '/ test/integration /' e funziona con la normale suite di test con 'rake test'. – justindao

+0

... o eseguendo 'rake test: integration' – cseelus

11

Devise esegue il test dello PasswordsController internamente. Volevo testare il mio PasswordsController con funzionalità extra e sono andato a Devise's controller tests per aiuto nella costruzione di test per la funzionalità predefinita di Devise, quindi aggiungendo asserzioni per la mia nuova funzionalità nel caso di test.

Come indicato in altre risposte, è necessario ottenere reset_password_token. Invece di analisi di un e-mail fornito come in un'altra soluzione qui, si potrebbe ottenere il token nello stesso modo come Devise:

setup do 
    request.env["devise.mapping"] = Devise.mappings[:user] 
    @user = users(:user_that_is_defined_in_fixture) 
    @reset_password_token = @user.send_reset_password_instructions 
end 

Partenza soluzione Devise per la PasswordControllerTest:

https://github.com/plataformatec/devise/blob/master/test/controllers/passwords_controller_test.rb.

+0

@Bryan Ash Grazie per la modifica! Ho dimenticato che le risposte potrebbero essere ordinate! – sealocal

+1

Questa risposta dovrebbe essere accettata, perché è meglio ottenere direttamente il token anziché l'analisi email. – yeasayer

3
require 'rails_helper' 

feature 'User' do 
    let(:user) { create(:user) } 
    let(:new_password) { 'Passw0rd!' } 

    it 'reset password' do 
    visit '/' 

    click_link 'Forgot password?' 
    fill_in 'E-mail', with: user.email 

    expect do 
     click_button 'Send me reset password instructions' 
    end.to change(ActionMailer::Base.deliveries, :count).by(1) 

    expect(unread_emails_for(user.email)).to be_present 
    open_email(user.email, with_subject: 'Reset password instructions') 
    click_first_link_in_email 
    fill_in 'New password', with: new_password 
    fill_in 'Confirm new password', with: new_password 
    click_button 'Change password' 

    expect(page).to have_notice 'Your password has changed' 
    click_link 'Logout' 

    fill_in 'E-mail', with: user.email 
    fill_in 'Password', with: new_password 

    click_button 'Sign in' 
    expect(page).to have_notice 'Wellcome!' 
    end 
end 

Questo codice richiede le gemme email_spec e FactoryGirl.