Я использую Rails 6 и minitest со встроенными системными тестами (которые используют Capybara, я думаю) и также использую FactoryBot для генерации моих тестовых записей.
У меня довольно стандартная функция восстановления пароля Я пытаюсь реализовать.
Я проверил, что когда я go на страницы в браузере и заполняю информацию, это действительно меняет пароль пользователя, но по какой-то причине пароль никогда не бывает изменен в тесте.
Это похоже на то, что объект @user
кэшируется в тестах и не будет reload
в тесте, но я понятия не имею, почему это будет.
Кто-нибудь знает, почему этот тест не пройден, но функциональность работает в «реальной жизни», когда я вручную изменяю пароль?
# test/system/password_resets_test.rb
require "application_system_test_case"
class PasswordResetsTest < ApplicationSystemTestCase
test "change password" do
original_password = "password"
new_password = "new-password"
@user = create(:user, password: original_password, password_reset_token_sent_at: Time.current)
visit password_reset_path(@user.password_reset_token)
fill_in "user[password]", with: new_password
click_on "Update Password"
assert_equal(@user.reload.password, new_password)
end
end
# app/views/password_resets/show.html.erb
<%= form_with model: @user, url: password_reset_path(@user.password_reset_token), method: :put do |form| %>
<div class="field">
<%= form.label :password, "Password" %><br />
<%= form.password_field :password, autofocus: true, required: true %>
</div>
<div class="field">
<%= form.submit "Update Password" %>
</div>
<% end %>
# app/controllers/password_resets_controller.rb
class PasswordResetsController < ApplicationController
def show
if @user = User.find_by(password_reset_token: params[:id])
if @user.password_reset_token_expired?
flash[:error] = "Your password reset has expired"
redirect_to new_password_reset_path
end
else
flash[:error] = "Invalid password reset token"
redirect_to new_password_reset_path
end
end
def update
@user = User.find_by(password_reset_token: params[:id])
new_password = password_reset_params[:password]
# Automatically set `#password_confirmation` so user does not have
# to enter in password twice on reset page.
if @user&.update(password: new_password, password_confirmation: new_password)
let_user_in(@user)
else
render :show
end
end
private
def password_reset_params
params.require(:user).permit(:password)
end
# app/models/user.rb
class User < ApplicationRecord
PASSWORD_RESET_TIME_LIMIT_IN_HOURS = 4.freeze
has_secure_password
has_secure_token :password_reset_token
validates :password,
presence: true,
length: { minimum: 8 },
allow_nil: true
def password_reset_token_expired?
return true if password_reset_token_sent_at.blank?
password_reset_token_sent_at < PASSWORD_RESET_TIME_LIMIT_IN_HOURS.hours.ago
end
end