【问题标题】:HTTP basic auth for CapybaraCapybara 的 HTTP 基本身份验证
【发布时间】:2018-02-15 01:45:03
【问题描述】:

我正在为我的 Rails 3 应用程序编写一些 RSpec 测试并尝试从 Webrat 切换到 Capybara。到目前为止一切顺利,但应用程序使用 HTTP 基本身份验证来授权我的管理员用户,知道如何使用 Capybara 进行测试吗?

这是我当前的 Webrat 步骤:

it 'should authenticate for admin' do
  basic_auth('user', 'secret')
  visit '/admin'
  response.status.should eql 200
  response.status.should_not eql 401
end

如何使用 Capybara 进行此操作?谢谢!

【问题讨论】:

  • 在您已经明确确定 response.status 是什么之后,为什么还需要测试它不是什么?

标签: ruby-on-rails testing authentication webrat capybara


【解决方案1】:

我改用page.driver.basic_authorize(name, password) 让它工作

更新

目前,在 Capybara 升级后,我正在使用这一堆解决方法:

if page.driver.respond_to?(:basic_auth)
  page.driver.basic_auth(name, password)
elsif page.driver.respond_to?(:basic_authorize)
  page.driver.basic_authorize(name, password)
elsif page.driver.respond_to?(:browser) && page.driver.browser.respond_to?(:basic_authorize)
  page.driver.browser.basic_authorize(name, password)
else
  raise "I don't know how to log in!"
end

【讨论】:

  • 酷,这行得通!供将来参考:我发现 Capybara 的创建者 Jonas Nicklas 的评论,建议不要使用该驱动程序,因为并非所有可能的 Capybara 驱动程序都支持 HTTP 标头 (github.com/jnicklas/capybara/issues/issue/17)...如果有人需要这个。就我而言,这是我需要的解决方案。谢谢安德斯!
  • 你摇滚! page.driver.browser.basic_authorize 为我工作
【解决方案2】:

默认的 Capybara 驱动程序 rack-test 有一个 basic_authorize 方法(别名 authorize)用于基本 HTTP 身份验证,digest_authorize 用于摘要 HTTP 身份验证,您可以在此处找到它们:https://github.com/brynary/rack-test/blob/master/lib/rack/test.rb

所以你可以这样做:

page.driver.browser.authorize 'login', 'password'

或者您可以为 Basic HTTP Auth 编写一个简单的帮助程序:

def basic_auth(user, password)
  encoded_login = ["#{user}:#{password}"].pack("m*")
  page.driver.header 'Authorization', "Basic #{encoded_login}"
end

【讨论】:

  • 你的第一行 {page.driver.browser.authorize 'login', 'password'} 很有效,可惜它不能在 before :each 块中进行 rspec 2 测试,但它在致电访问之前直接工作正常。感谢您的回答
  • 值得注意的是,此方法通过将Authorization 标头添加到请求中来工作,因此您需要在visit 之前调用此方法。
  • 当我尝试使用第一个选项时,我得到一个错误:undefined method `authorize' for #<:poltergeist::browser:0x007fae7c592540> (NoMethodError) 有人见过类似的吗?
【解决方案3】:

page.driver.* 解决方案都不适合我。我使用的是 Poltergeist,而不是 Selenium,所以这可能与它有关。以下是有效的方法:

RSpec.shared_context "When authenticated" do
  before do
    username = 'yourusername'
    password = 'yourpassword'
    visit "http://#{username}:#{password}@#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}/"
  end
end

然后,在您的规范中:

feature "Your feature", js: true do
  include_context "When authenticated"

  # Your test code here...
end

【讨论】:

  • 这既简单又干净。我放入 config.before(:each) do 块而不是 shared_context。
【解决方案4】:

这在最近版本的 cucumber-rails 中发生了变化(我使用的是 1.0.2)。

cucumber-rails 默认使用 Rack/Test 驱动程序,所以如果您没有更改它,以下说明将起作用。

创建特征/step_definitions/authorize.rb:

Given /^I am logged in as "([^\"]*)" with "([^\"]*)"$/ do |username, password|
  authorize username, password
end

现在您可以在您的功能中使用它:

Given I am logged in as "admin" with "password"

【讨论】:

  • 感谢 Joost,但问题没有提到 Cucumber。这是水豚唯一的问题。很高兴知道 Cucumber 中有一种简单的方法可以做到这一点。
  • 无论您是否使用 RSpec 而不是 Cucumber 来运行这些功能,如果您在 Capybara 中保留了默认驱动程序 Rack::Test,则答案同样有效。
【解决方案5】:

我不得不做这个可怕的 hack 才能让它在无头和 javascript 下工作

Given /^I am logged in$/ do
 if page.driver.respond_to?(:basic_authorize)
   page.driver.basic_authorize('admin', 'password')
 else
   # FIXME for this to work you need to add pref("network.http.phishy-userpass-length", 255); to /Applications/Firefox.app/Contents/MacOS/defaults/pref/firefox.js
   page.driver.visit('/')
   page.driver.visit("http://admin:password@#{page.driver.current_url.gsub(/^http\:\/\//, '')}")
 end
end

【讨论】:

    【解决方案6】:

    伙计,这些解决方案都不适合我。

    Pistos 的解决方案接近并适用于 js: true 的功能规格,但在无头时失败。

    以下解决方案适用于 无头和 js: true 规格。

    spec/support/when_authenticated.rb

    RSpec.shared_context 'When authenticated' do
      background do
        authenticate
      end
    
      def authenticate
        if page.driver.browser.respond_to?(:authorize)
          # When headless
          page.driver.browser.authorize(username, password)
        else
          # When javascript test
          visit "http://#{username}:#{password}@#{host}:#{port}/"     
         end
      end
    
      def username
        # Your value here. Replace with string or config location
        Rails.application.secrets.http_auth_username
      end
    
      def password
        # Your value here. Replace with string or config location
        Rails.application.secrets.http_auth_password
      end
    
      def host
        Capybara.current_session.server.host
      end
    
      def port
        Capybara.current_session.server.port
      end
    end
    

    然后,在您的规范中:

    feature 'User does something' do
      include_context 'When authenticated'
    
      # test examples
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-21
      • 2011-11-12
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多