197 lines
5.6 KiB
Ruby
197 lines
5.6 KiB
Ruby
require "test_helper"
|
|
|
|
class PasswordResetsControllerTest < ActionDispatch::IntegrationTest
|
|
setup do
|
|
@user = users(:admin_user)
|
|
@user.update!(invitation_accepted_at: Time.current)
|
|
end
|
|
|
|
# NEW tests
|
|
test "should get new" do
|
|
get new_password_reset_url
|
|
assert_response :success
|
|
end
|
|
|
|
test "should show password reset form" do
|
|
get new_password_reset_url
|
|
assert_select "form"
|
|
assert_select "input[type=email]"
|
|
end
|
|
|
|
# CREATE tests
|
|
test "should send reset email for existing user" do
|
|
assert_enqueued_emails 1 do
|
|
post password_resets_url, params: { email: @user.email }
|
|
end
|
|
assert_redirected_to login_url
|
|
assert_match /password reset instructions/i, flash[:notice]
|
|
end
|
|
|
|
test "should generate reset token for existing user" do
|
|
post password_resets_url, params: { email: @user.email }
|
|
@user.reload
|
|
assert_not_nil @user.reset_password_token
|
|
assert_not_nil @user.reset_password_sent_at
|
|
end
|
|
|
|
test "should handle non-existent email gracefully" do
|
|
post password_resets_url, params: { email: "nonexistent@example.com" }
|
|
assert_redirected_to login_url
|
|
assert_match /if that email address is in our system/i, flash[:notice]
|
|
end
|
|
|
|
test "should send invitation for user without accepted invitation" do
|
|
pending_user = users(:pending_invitation)
|
|
assert_nil pending_user.invitation_accepted_at
|
|
|
|
assert_enqueued_emails 1 do
|
|
post password_resets_url, params: { email: pending_user.email }
|
|
end
|
|
assert_redirected_to login_url
|
|
end
|
|
|
|
test "should handle blank email" do
|
|
post password_resets_url, params: { email: "" }
|
|
assert_redirected_to login_url
|
|
end
|
|
|
|
test "should handle email with whitespace" do
|
|
post password_resets_url, params: { email: " #{@user.email} " }
|
|
@user.reload
|
|
assert_not_nil @user.reset_password_token
|
|
end
|
|
|
|
# EDIT tests
|
|
test "should show reset password form with valid token" do
|
|
@user.update!(
|
|
reset_password_token: SecureRandom.urlsafe_base64(32),
|
|
reset_password_sent_at: Time.current
|
|
)
|
|
get edit_password_reset_url(@user.reset_password_token)
|
|
assert_response :success
|
|
assert_select "form"
|
|
assert_select "input[type=password]", count: 2
|
|
end
|
|
|
|
test "should reject invalid token" do
|
|
get edit_password_reset_url("invalid_token")
|
|
assert_redirected_to login_url
|
|
assert_match /invalid/i, flash[:alert]
|
|
end
|
|
|
|
test "should reject expired token" do
|
|
@user.update!(
|
|
reset_password_token: SecureRandom.urlsafe_base64(32),
|
|
reset_password_sent_at: 2.hours.ago
|
|
)
|
|
get edit_password_reset_url(@user.reset_password_token)
|
|
assert_redirected_to new_password_reset_url
|
|
assert_match /expired/i, flash[:alert]
|
|
end
|
|
|
|
# UPDATE tests
|
|
test "should reset password with valid token" do
|
|
@user.update!(
|
|
reset_password_token: SecureRandom.urlsafe_base64(32),
|
|
reset_password_sent_at: Time.current
|
|
)
|
|
|
|
patch password_reset_url(@user.reset_password_token), params: {
|
|
password: "newpassword12345",
|
|
password_confirmation: "newpassword12345"
|
|
}
|
|
|
|
assert_redirected_to root_url
|
|
assert_match /password has been reset/i, flash[:notice]
|
|
|
|
@user.reload
|
|
assert_nil @user.reset_password_token
|
|
assert_nil @user.reset_password_sent_at
|
|
assert @user.authenticate("newpassword12345")
|
|
end
|
|
|
|
test "should auto-login after successful password reset" do
|
|
@user.update!(
|
|
reset_password_token: SecureRandom.urlsafe_base64(32),
|
|
reset_password_sent_at: Time.current
|
|
)
|
|
|
|
patch password_reset_url(@user.reset_password_token), params: {
|
|
password: "newpassword12345",
|
|
password_confirmation: "newpassword12345"
|
|
}
|
|
|
|
assert_equal @user.id, session[:user_id]
|
|
end
|
|
|
|
test "should reject mismatched passwords" do
|
|
@user.update!(
|
|
reset_password_token: SecureRandom.urlsafe_base64(32),
|
|
reset_password_sent_at: Time.current
|
|
)
|
|
|
|
patch password_reset_url(@user.reset_password_token), params: {
|
|
password: "newpassword12345",
|
|
password_confirmation: "differentpassword"
|
|
}
|
|
|
|
assert_response :unprocessable_entity
|
|
assert_match /doesn't match/i, flash[:alert]
|
|
end
|
|
|
|
test "should reject blank password" do
|
|
@user.update!(
|
|
reset_password_token: SecureRandom.urlsafe_base64(32),
|
|
reset_password_sent_at: Time.current
|
|
)
|
|
|
|
patch password_reset_url(@user.reset_password_token), params: {
|
|
password: "",
|
|
password_confirmation: ""
|
|
}
|
|
|
|
assert_response :unprocessable_entity
|
|
assert_match /cannot be blank/i, flash[:alert]
|
|
end
|
|
|
|
test "should reject expired token on update" do
|
|
@user.update!(
|
|
reset_password_token: SecureRandom.urlsafe_base64(32),
|
|
reset_password_sent_at: 2.hours.ago
|
|
)
|
|
|
|
patch password_reset_url(@user.reset_password_token), params: {
|
|
password: "newpassword12345",
|
|
password_confirmation: "newpassword12345"
|
|
}
|
|
|
|
assert_redirected_to new_password_reset_url
|
|
assert_match /expired/i, flash[:alert]
|
|
end
|
|
|
|
test "should reject invalid token on update" do
|
|
patch password_reset_url("invalid_token"), params: {
|
|
password: "newpassword12345",
|
|
password_confirmation: "newpassword12345"
|
|
}
|
|
|
|
assert_redirected_to login_url
|
|
assert_match /invalid/i, flash[:alert]
|
|
end
|
|
|
|
test "should enforce password validations" do
|
|
@user.update!(
|
|
reset_password_token: SecureRandom.urlsafe_base64(32),
|
|
reset_password_sent_at: Time.current
|
|
)
|
|
|
|
# Password too short (less than 12 characters)
|
|
patch password_reset_url(@user.reset_password_token), params: {
|
|
password: "short",
|
|
password_confirmation: "short"
|
|
}
|
|
|
|
assert_response :unprocessable_entity
|
|
end
|
|
end
|