Files
discourse/spec/system/email_change_spec.rb
Alan Guo Xiang Tan 0724b03fb8 DEV: Bump Capybara.default_max_wait_time to 20 on CI (#32143)
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.
2025-04-04 12:50:28 +08:00

204 lines
6.1 KiB
Ruby

# frozen_string_literal: true
describe "Changing email", type: :system do
fab!(:password) { "mysupersecurepassword" }
fab!(:user) { Fabricate(:user, active: true, password: password) }
let(:new_email) { "newemail@example.com" }
let(:user_preferences_security_page) { PageObjects::Pages::UserPreferencesSecurity.new }
let(:user_preferences_page) { PageObjects::Pages::UserPreferences.new }
before { Jobs.run_immediately! }
def generate_confirm_link
visit "/my/preferences/account"
email_dropdown = PageObjects::Components::SelectKit.new(".email-dropdown")
expect(email_dropdown.visible?).to eq(true)
email_dropdown.select_row_by_value("updateEmail")
find("#change-email").fill_in with: "newemail@example.com"
find(".save-button button").click
wait_for(timeout: Capybara.default_max_wait_time * 2) do
ActionMailer::Base.deliveries.count === 1
end
if user.admin?
get_link_from_email(:old)
else
get_link_from_email(:new)
end
end
def get_link_from_email(type)
mail = ActionMailer::Base.deliveries.last
expect(mail.to).to contain_exactly(type == :new ? new_email : user.email)
mail.body.to_s[%r{/u/confirm-#{type}-email/\S+}, 0]
end
it "allows regular user to change their email" do
sign_in user
visit generate_confirm_link
find(".confirm-new-email .btn-primary").click
expect(page).to have_css(".dialog-body", text: I18n.t("js.user.change_email.confirm_success"))
find(".dialog-footer .btn-primary").click
try_until_success(timeout: Capybara.default_max_wait_time * 2) do
expect(user.reload.primary_email.email).to eq(new_email)
end
end
it "works when user has totp 2fa", dump_threads_on_failure: true do
SiteSetting.hide_email_address_taken = false
second_factor = Fabricate(:user_second_factor_totp, user: user)
sign_in user
visit generate_confirm_link
find(".confirm-new-email .btn-primary").click
find(".second-factor-token-input").fill_in with: second_factor.totp_object.now
find("button[type=submit]").click
try_until_success(timeout: Capybara.default_max_wait_time * 2) do
expect(user.reload.primary_email.email).to eq(new_email)
end
end
it "works when user has webauthn 2fa" do
begin
# enforced 2FA flow needs a user created > 5 minutes ago
user.created_at = 6.minutes.ago
user.save!
sign_in user
DiscourseWebauthn.stubs(:origin).returns(current_host + ":" + Capybara.server_port.to_s)
options =
::Selenium::WebDriver::VirtualAuthenticatorOptions.new(
user_verification: true,
user_verified: true,
resident_key: true,
)
authenticator = page.driver.browser.add_virtual_authenticator(options)
user_preferences_security_page.visit(user)
user_preferences_security_page.visit_second_factor(user, password)
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")
visit generate_confirm_link
find(".confirm-new-email .btn-primary").click
find("#security-key-authenticate-button").click
try_until_success(timeout: Capybara.default_max_wait_time * 2) do
expect(user.reload.primary_email.email).to eq(new_email)
end
ensure
authenticator&.remove!
end
end
it "does not require login to confirm email change" do
SiteSetting.full_page_login = false
second_factor = Fabricate(:user_second_factor_totp, user: user)
sign_in user
confirm_link = generate_confirm_link
Capybara.reset_sessions! # log out
visit confirm_link
find(".confirm-new-email .btn-primary").click
find(".second-factor-token-input").fill_in with: second_factor.totp_object.now
find("button[type=submit]:not([disabled])").click
try_until_success(timeout: Capybara.default_max_wait_time * 2) do
expect(user.reload.primary_email.email).to eq(new_email)
end
end
it "makes admins verify old email" do
user.update!(admin: true)
sign_in user
confirm_old_link = generate_confirm_link
# Confirm old email
visit confirm_old_link
find(".confirm-old-email .btn-primary").click
expect(page).to have_css(
".dialog-body",
text: I18n.t("js.user.change_email.authorizing_old.confirm_success"),
)
find(".dialog-footer .btn-primary").click
# Confirm new email
wait_for(timeout: Capybara.default_max_wait_time * 2) do
ActionMailer::Base.deliveries.count === 2
end
confirm_new_link = get_link_from_email(:new)
visit confirm_new_link
find(".confirm-new-email .btn-primary").click
expect(page).to have_css(".dialog-body", text: I18n.t("js.user.change_email.confirm_success"))
find(".dialog-footer .btn-primary").click
try_until_success(timeout: Capybara.default_max_wait_time * 2) do
expect(user.reload.primary_email.email).to eq(new_email)
end
end
it "allows admin to verify old email while logged out" do
user.update!(admin: true)
sign_in user
confirm_old_link = generate_confirm_link
Capybara.reset_sessions! # log out
# Confirm old email
visit confirm_old_link
find(".confirm-old-email .btn-primary").click
expect(page).to have_css(
".dialog-body",
text: I18n.t("js.user.change_email.authorizing_old.confirm_success"),
)
find(".dialog-footer .btn-primary").click
# Confirm new email
wait_for(timeout: Capybara.default_max_wait_time * 2) do
ActionMailer::Base.deliveries.count === 2
end
confirm_new_link = get_link_from_email(:new)
visit confirm_new_link
find(".confirm-new-email .btn-primary").click
expect(page).to have_css(".dialog-body", text: I18n.t("js.user.change_email.confirm_success"))
find(".dialog-footer .btn-primary").click
try_until_success(timeout: Capybara.default_max_wait_time * 2) do
expect(user.reload.primary_email.email).to eq(new_email)
end
end
end