Rails 测试环境中的确认 link 呈现:禁止访问此服务器上的 /users/confirmation

confirmation link in Rails test environment renders: Forbidden You don't have permission to access /users/confirmation on this server

我有一个使用 devise :confirmableUser class,它在创建用户时触发发送包含确认 link 的电子邮件。这在 developmentproduction 中完美运行,但在 test 环境(Minitest / Capybara)中失败。具体来说,单击确认 link 会导致 **Forbidden** You don't have permission to access /users/confirmation on this server

截图:

Forbidden You don't have permission to access /users/confirmation on this server

奇怪的是,当我从 rails console 创建用户时,就像我在集成测试中所做的那样,它起作用了。那么,为什么在test环境下会失败呢?

测试:

u = FactoryBot.create(:user)
email = ActionMailer::Base.deliveries.last
plain_part = email.multipart? ? (email.text_part ? email.text_part.body.decoded : nil) : email.body.decoded
confirmation_link = plain_part[/<a href="(http:\/\/.*)">Confirm my account<\/a>/,1]
puts "--- #{confirmation_link} ---" # visual check of extracted URL
visit confirmation_link # Forbidden You don't have permission...
save_and_open_screenshot # saves to tmp/capybara/capybara-*.png

在控制台:

require 'factory_bot'
# factory creation code omitted from here
u = FactoryBot.create(:user)
# produces and renders link

此类确认 link 在除 test 以外的所有环境中看起来都是这样:

http://localhost:3000/users/confirmation?confirmation_token=TxYdRmVzcuPE7PAx7yJh

...在 test 中它们看起来像这样:

http://localhost/users/confirmation?confirmation_token=NqyaVL5EKEnz46zMzDQs

test 中未指定端口。)

我在这些 集成 测试中使用 Rails 5.2.0 和 Capybara 驱动程序 selenium_chrome_headless

这是因为电子邮件中生成的 URL 没有指向 Capybara 服务器。有几种方法可以解决这个问题。两个最简单的解决方案是

  1. 修复端口 Capybara 运行 的测试服务器并设置电子邮件生成参数

    Capybara.server_port = 1111 # any fixed port number
    
    # in config/environments/test.rb
    config.action_mailer.default_url_options = {:host => 'localhost', port: '1111'} # match whatever server host and port Capybara is running on
    
  2. 继续允许 Capybara 运行 在一个随机端口上,配置 url 一代不包括端口,并设置 Capybara 在没有其他端口时始终包括服务器端口明确指定端口

    Capybara.always_include_port = true
    
    # in config/environments/test.rb
    config.action_mailer.default_url_options = {:host => 'localhost'} # match the host Capybara is running the test server on