如何使用Rspec和Capybara测试重定向

27

我不知道自己做错了什么,但每次我尝试测试重定向时,都会出现这个错误:“@request必须是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。如果有人能解释一下为什么会发生这种情况,为什么我不能以这种方式使用expect,我将不胜感激。


也许我错过了什么,但是 assert_redirected_to 有什么问题吗? - Joseph Weissman
@JosephWeissman,我遇到了同样的错误! - Mohamad
5个回答

42

Capybara并非针对Rails特定解决方案,因此不了解Rails的渲染逻辑。

Capybara专门用于集成测试,也就是从终端用户与浏览器交互的角度运行测试。在这些测试中,您不应该断言模板,因为终端用户无法看到应用程序的深层结构。相反,您应该测试一个操作是否将您置于正确的路径上。

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

2
随着较新版本的Capybara问世,此方法已不再适用。我使用的是2.10.1版本,现在可以使用新的方法 have_current_pathexpect(page).to have_current_path(new_user_path) - bjnord
@bjnord 不正确。current_path 在3.13中仍然有效。您可以使用最新的rspec,它具有与capybara无关的新语法。请参见The Whiz of Oz的答案 ;) - randmin

22

你可以这样做:

expect(current_path).to eql(new_app_user_registration_path)

15

Rspec 3:

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

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

have_current_path 相较于以下方法有其优越性:

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

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


1
与 expect(current_path).to eq('/login?status=invalid_token') 有何不同? - sekmo
@sekmo 如果你这样做(像我们大多数人以前一样),它会使用当前值,这个值可能还没有稳定下来,因此你的测试中会出现竞态条件。当你使用have_current_path时,它会使用Capybara重试逻辑来重试该值,直到它匹配或达到您的超时/重试限制并失败测试为止,这是您从DOM断言熟悉的逻辑。 - nruth

11

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

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

您是否应明确检查重定向方式(是301响应而不是307响应或某些Javascript)完全取决于您。


8
这是我发现的一种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

2
如果您的重定向恰好是一个外部链接,那么这很有帮助。 - Rennan Oliveira
这是为哪个驱动程序? - nruth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接