【问题标题】:How to test for a redirect with Rspec and Capybara如何使用 Rspec 和 Capybara 测试重定向
【发布时间】:2012-06-12 21:42:05
【问题描述】:

我不知道自己做错了什么,但每次我尝试测试重定向时,都会收到以下错误:“@request must be an ActionDispatch::Request”

context "as non-signed in user" do
  it "should redirect to the login page" do
    expect { visit admin_account_url(account, host: get_host(account)) }.to redirect_to(signin_path)
  end
end
1) AdminAccountPages Admin::Accounts#show as non-signed in user should redirect to the login page
     Failure/Error: expect { visit admin_account_url(account, host: get_host(account)) }.to redirect_to(signin_path)
     ArgumentError:
       @request must be an ActionDispatch::Request
     # ./spec/requests/admin_account_pages_spec.rb:16:in `block (4 levels) in <top (required)>'

我将 RSpec-rails (2.9.0) 与 Capybara (1.1.2) 和 Rails 3.2 一起使用。如果有人也能解释为什么会发生这种情况,我将不胜感激;为什么我不能以这种方式使用期望?

【问题讨论】:

  • 也许我遗漏了什么,但assert_redirected_to 有什么问题?
  • @JosephWeissman,我遇到了同样的错误!

标签: ruby-on-rails ruby rspec capybara


【解决方案1】:

Rspec 3:

测试当前路径的最简单方法是:

expect(page).to have_current_path('/login?status=invalid_token')

have_current_path 比这种方法有优势:

expect(current_path).to eq('/login')

因为您可以包含查询参数。

【讨论】:

  • 和expect(current_path).to eq('/login?status=invalid_token')有什么区别?
  • @sekmo 如果你这样做(就像我们大多数人习惯的那样),它会使用当前值,它可能还没有稳定下来,你的测试中会出现竞争条件。当您使用 have_current_path 时,它会使用您熟悉的 dom 断言中的 capybara 重试逻辑来重试该值,直到它匹配或达到您的超时/重试限制并且测试失败。
【解决方案2】:

这是我找到的 hackish 解决方案

# spec/features/user_confirmation_feature.rb

feature 'User confirmation' do
  scenario 'provide confirmation and redirect' do
    visit "/users/123/confirm"

    expect(page).to have_content('Please enter the confirmation code')
    find("input[id$='confirmation_code']").set '1234'

    do_not_follow_redirect do
      click_button('Verify')
      expect(page.driver.status_code).to eq(302)
      expect(page.driver.browser.last_response['Location']).to match(/\/en\//[^\/]+\/edit$/)
    end
  end

  protected

  # Capybara won't follow redirects
  def do_not_follow_redirect &block
    begin
      options = page.driver.instance_variable_get(:@options)
      prev_value = options[:follow_redirects]
      options[:follow_redirects] = false

      yield
    ensure
      options[:follow_redirects] = prev_value
    end
  end
end

【讨论】:

  • 如果您的重定向碰巧是外部链接,这会有所帮助
  • 这适用于哪个驱动程序?
【解决方案3】:

你可以这样做:

expect(current_path).to eql(new_app_user_registration_path)

【讨论】:

    【解决方案4】:

    错误消息@request must be an ActionDispatch::Request 告诉您rspec-rails 匹配器redirect_to(它委托给Rails assert_redirected_to)希望它用于Rails 功能测试(应该混合在ActionController::TestCase 中)。您发布的代码看起来像 rspec-rails 请求规范。所以redirect_to 不可用。

    在 rspec-rails 请求规范中不支持检查重定向,但在 Rails 集成测试中支持。

    您是否应该明确检查重定向是如何进行的(它是 301 响应而不是 307 响应,而不是某些 javascript)完全取决于您。

    【讨论】:

      【解决方案5】:

      Capybara 不是特定于 Rails 的解决方案,因此它什么都不知道 关于rails的渲染逻辑。

      Capybara 专门用于集成测试,它本质上是从最终用户与浏览器交互的角度运行测试。在这些测试中,您不应该断言模板,因为最终用户无法深入了解您的应用程序。相反,您应该测试的是某个操作是否使您走上了正确的道路。

      current_path.should == new_user_path
      page.should have_selector('div#erro_div')
      

      【讨论】:

      • 对于较新版本的 Capybara,这不再有效。我有 2.10.1 并且有一个可以使用的新方法have_current_pathexpect(page).to have_current_path(new_user_path)
      • @bjnord 不正确。 current_path 即使在 3.13 中仍然有效。您使用最新 rspec 附带的新语法,与 capybara 无关。查看绿野仙踪的答案;)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-27
      相关资源
      最近更新 更多