如何在系统测试期间正确设置电子邮件链接中的端口?

How do I set the port correctly in email links during a system test?

我正在编写系统测试以确认整个注册流程在 Rails 7 应用程序中正常工作(使用 Clearance gem 和电子邮件确认 SignInGuard)。

在我“点击”电子邮件中的确认 link 之前,测试工作正常(在使用 Nokogiri 解析之后)。出于某种原因,电子邮件中的 URL 指向我的开发服务器(端口 3000)而不是指向测试服务器(端口 49736、49757、49991,等等)。

我可以查找测试服务器正在使用的当前端口(它每 运行 更改一次)并替换 URL 的端口部分,但这看起来很老套。我是不是漏掉了什么明显的东西或做错了什么?

URL 在邮件中:confirm_email_url(@user.email_confirmation_token)

rails routes出发的路线:

Prefix          Verb   URI Pattern                       Controller#Action
confirm_email   GET    /confirm_email/:token(.:format)   email_confirmations#update

目前系统测试:

require "application_system_test_case"
require "test_helper"
require "action_mailer/test_helper"

class UserSignUpFlowTest < ApplicationSystemTestCase
  include ActionMailer::TestHelper

  test "Sign up for a user account" do
    time = Time.now
    email = "test_user_#{time.to_s(:number)}@example.com"
    password = "Password#{time.to_s(:number)}!"

    # Sign up (sends confirmation email)
    visit sign_up_url
    fill_in "Email", with: email
    fill_in "Password", with: password
    assert_emails 1 do
      click_on "Sign up"
      sleep 1 # Not sure why this is required... Hotwire/Turbo glitch?
    end
    assert_selector "span", text: I18n.t("flashes.confirmation_pending")

    # Confirm
    last_email = ActionMailer::Base.deliveries.last
    parsed_email = Nokogiri::HTML(last_email.body.decoded)
    target_link = parsed_email.at("a:contains('#{I18n.t("clearance_mailer.confirm_email.link_text")}')")
    visit target_link["href"]
  # ^^^^^^^^^^^^^^^^^^^^^^^^^
  # This is the bit that fails... The link in the email points to my dev server (port 3000) rather than
  # the test server (port 49736, 49757, 49991, etc). I only figured this out when my dev server crashed
  # and Selenium started choking on a "net::ERR_CONNECTION_REFUSED" error
    assert_selector "span", text: I18n.t("flashes.email_confirmed")
  end
end

编辑

目前我已经通过将 visit target_link["href"] 替换为 visit hacky_way_to_fix_incorrect_port(target_link["href"]):

来解决这个问题
  private

  def hacky_way_to_fix_incorrect_port(url)
    uri = URI(url)
    return "#{root_url}#{uri.path}"
  end

邮件程序中使用的 URL 指定为:
Rails.application.configure.action_mailer.default_url_options

config/environments/test.rb 中,我在第一次安装 Clearance 时将端口设置为 3000:
config.action_mailer.default_url_options = {host: "localhost:3000"}

为了修复它,我首先尝试了 specifying the port dynamically,但建议的方法实际上并没有用,而且似乎没有必要。删除端口号足以让我的系统测试通过:
config.action_mailer.default_url_options = {host: "localhost"}

正如 Thomas Walpole 所提到的,之所以有效,是因为 Capybara.always_include_port 设置为 true。使用此设置,尝试访问 http://localhost/confirm_email/<token>(未指定端口)会自动重新路由到 http://localhost:<port>/confirm_email/<token>.

always_include_port设置defaults to false in the Capybara gem but it turns out Rails sets it to true when it starts up the System Test server