mirror of
https://github.com/discourse/discourse.git
synced 2025-06-04 23:36:11 +08:00

There are flaky system tests that have been exhausting the 10 seconds default max wait time which we have set previously on CI. However, I have yet to be able to figure out why and lack the tools to be able to figure out why. The hope here is that the upcoming playwright driver will provide us with better tooling to debug such problems. I've attempted to use `Capybara::Session#using_wait_time` by there is some race condition going on where the session's default max wait time is sometimes not set properly. I can't figure out why and have spent too much time trying to figure out why. Instead, I will just bump up the `default_max_wait_time` to `20`. This may the build take longer when there are test failures but it is a trade-off we will make right now.
212 lines
6.8 KiB
Ruby
212 lines
6.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "rotp"
|
|
|
|
shared_examples "forgot password scenarios" do
|
|
let(:user_preferences_security_page) { PageObjects::Pages::UserPreferencesSecurity.new }
|
|
fab!(:user) { Fabricate(:user, username: "john", password: "supersecurepassword") }
|
|
fab!(:password_reset_token) do
|
|
Fabricate(
|
|
:email_token,
|
|
user:,
|
|
scope: EmailToken.scopes[:password_reset],
|
|
email: user.email,
|
|
).token
|
|
end
|
|
let(:user_menu) { PageObjects::Components::UserMenu.new }
|
|
let(:user_reset_password_page) { PageObjects::Pages::UserResetPassword.new }
|
|
|
|
def visit_reset_password_link
|
|
visit("/u/password-reset/#{password_reset_token}")
|
|
end
|
|
|
|
def create_user_security_key(user)
|
|
# testing the 2FA flow requires a user that was created > 5 minutes ago
|
|
user.update!(created_at: 6.minutes.ago)
|
|
|
|
sign_in(user)
|
|
|
|
user_preferences_security_page.visit(user)
|
|
user_preferences_security_page.visit_second_factor(user, "supersecurepassword")
|
|
|
|
find(".security-key .new-security-key").click
|
|
expect(user_preferences_security_page).to have_css("input#security-key-name")
|
|
|
|
find(".d-modal__body input#security-key-name").fill_in(with: "First Key")
|
|
find(".add-security-key").click
|
|
|
|
expect(user_preferences_security_page).to have_css(".security-key .second-factor-item")
|
|
|
|
user_menu.sign_out
|
|
end
|
|
|
|
context "when user does not have any multi-factor authentication configured" do
|
|
it "should allow a user to reset their password" do
|
|
visit_reset_password_link
|
|
|
|
user_reset_password_page.fill_in_new_password("newsuperpassword").submit_new_password
|
|
|
|
expect(user_reset_password_page).to have_logged_in_user
|
|
end
|
|
end
|
|
|
|
context "when user has multi-factor authentication configured" do
|
|
context "when user only has TOTP configured" do
|
|
fab!(:user_second_factor_totp) { Fabricate(:user_second_factor_totp, user:) }
|
|
|
|
it "should allow a user to reset password with TOTP" do
|
|
visit_reset_password_link
|
|
|
|
expect(user_reset_password_page).to have_no_toggle_button_to_second_factor_form
|
|
|
|
user_reset_password_page
|
|
.fill_in_totp(ROTP::TOTP.new(user_second_factor_totp.data).now)
|
|
.submit_totp
|
|
.fill_in_new_password("newsuperpassword")
|
|
.submit_new_password
|
|
|
|
expect(user_reset_password_page).to have_logged_in_user
|
|
end
|
|
end
|
|
|
|
context "when user only has security key configured" do
|
|
it "should allow a user to reset password with a security key" do
|
|
authenticator =
|
|
page.driver.browser.add_virtual_authenticator(
|
|
Selenium::WebDriver::VirtualAuthenticatorOptions.new,
|
|
)
|
|
|
|
create_user_security_key(user)
|
|
|
|
visit_reset_password_link
|
|
|
|
expect(user_reset_password_page).to have_no_toggle_button_to_second_factor_form
|
|
|
|
user_reset_password_page.submit_security_key
|
|
|
|
user_reset_password_page.fill_in_new_password("newsuperpassword").submit_new_password
|
|
|
|
expect(user_reset_password_page).to have_logged_in_user
|
|
ensure
|
|
authenticator.remove!
|
|
end
|
|
end
|
|
|
|
context "when user has TOTP and backup codes configured" do
|
|
fab!(:user_second_factor_backup) { Fabricate(:user_second_factor_backup, user:) }
|
|
fab!(:user_second_factor_totp) { Fabricate(:user_second_factor_totp, user:) }
|
|
|
|
it "should allow a user to reset password with backup code" do
|
|
visit_reset_password_link
|
|
|
|
user_reset_password_page
|
|
.use_backup_codes
|
|
.fill_in_backup_code("iAmValidBackupCode")
|
|
.submit_backup_code
|
|
.fill_in_new_password("newsuperpassword")
|
|
.submit_new_password
|
|
|
|
expect(user_reset_password_page).to have_logged_in_user
|
|
end
|
|
end
|
|
|
|
context "when user has security key and backup codes configured" do
|
|
fab!(:user_second_factor_backup) { Fabricate(:user_second_factor_backup, user:) }
|
|
|
|
it "should allow a user to reset password with backup code instead of security key" do
|
|
authenticator =
|
|
page.driver.browser.add_virtual_authenticator(
|
|
Selenium::WebDriver::VirtualAuthenticatorOptions.new,
|
|
)
|
|
|
|
create_user_security_key(user)
|
|
|
|
visit_reset_password_link
|
|
|
|
user_reset_password_page.try_another_way
|
|
|
|
expect(user_reset_password_page).to have_no_toggle_button_in_second_factor_form
|
|
|
|
user_reset_password_page
|
|
.fill_in_backup_code("iAmValidBackupCode")
|
|
.submit_backup_code
|
|
.fill_in_new_password("newsuperpassword")
|
|
.submit_new_password
|
|
|
|
expect(user_reset_password_page).to have_logged_in_user
|
|
ensure
|
|
authenticator.remove!
|
|
end
|
|
end
|
|
|
|
context "when user has TOTP, security key and backup codes configured" do
|
|
fab!(:user_second_factor_totp) { Fabricate(:user_second_factor_totp, user:) }
|
|
fab!(:user_second_factor_backup) { Fabricate(:user_second_factor_backup, user:) }
|
|
|
|
it "should allow a user to toggle from security key to TOTP and between TOTP and backup codes" do
|
|
authenticator =
|
|
page.driver.browser.add_virtual_authenticator(
|
|
Selenium::WebDriver::VirtualAuthenticatorOptions.new,
|
|
)
|
|
|
|
create_user_security_key(user)
|
|
|
|
visit_reset_password_link
|
|
|
|
user_reset_password_page.try_another_way
|
|
|
|
expect(user_reset_password_page).to have_totp_description
|
|
|
|
user_reset_password_page.use_backup_codes
|
|
|
|
expect(user_reset_password_page).to have_backup_codes_description
|
|
|
|
user_reset_password_page.use_totp
|
|
|
|
expect(user_reset_password_page).to have_totp_description
|
|
ensure
|
|
authenticator.remove!
|
|
end
|
|
end
|
|
|
|
context "when user has TOTP and security key configured but no backup codes" do
|
|
fab!(:user_second_factor_totp) { Fabricate(:user_second_factor_totp, user:) }
|
|
|
|
it "should allow a user to reset password with TOTP instead of security key" do
|
|
authenticator =
|
|
page.driver.browser.add_virtual_authenticator(
|
|
Selenium::WebDriver::VirtualAuthenticatorOptions.new,
|
|
)
|
|
|
|
create_user_security_key(user)
|
|
|
|
visit_reset_password_link
|
|
|
|
user_reset_password_page.try_another_way
|
|
|
|
expect(user_reset_password_page).to have_no_toggle_button_in_second_factor_form
|
|
|
|
user_reset_password_page
|
|
.fill_in_totp(ROTP::TOTP.new(user_second_factor_totp.data).now)
|
|
.submit_totp
|
|
.fill_in_new_password("newsuperpassword")
|
|
.submit_new_password
|
|
|
|
expect(user_reset_password_page).to have_logged_in_user
|
|
ensure
|
|
authenticator.remove!
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "User resetting password", type: :system, dump_threads_on_failure: true do
|
|
describe "when desktop" do
|
|
include_examples "forgot password scenarios"
|
|
end
|
|
|
|
describe "when mobile", mobile: true do
|
|
include_examples "forgot password scenarios"
|
|
end
|
|
end
|