96.99% test coverage
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
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
|
||||
Reference in New Issue
Block a user