开发者

HTTP basic auth for Capybara

开发者 https://www.devze.com 2023-01-28 02:27 出处:网络
I\'m writing some RSpec tests for my Rails 3 application and trying to switch from Webrat to Capybara. So far so good but the application uses HTTP basic auth to authorize my admin user, any idea how

I'm writing some RSpec tests for my Rails 3 application and trying to switch from Webrat to Capybara. So far so good but the application uses HTTP basic auth to authorize my admin user, any idea how I can test that with Capybara?

Here is my current Webrat step:

it 'should authenticate for admin' do
  basic_auth('user', 'secret')
  visit '/admin'
  response.status.should eql 200
  开发者_如何学Cresponse.status.should_not eql 401
end

How do I do this with Capybara? Thanks!


I got it to work using page.driver.basic_authorize(name, password) instead

Update:

At the moment, after a Capybara upgrade, I'm using this pile of workarounds:

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


The default Capybara driver, rack-test, has a basic_authorize method (with alias authorize) for Basic HTTP Auth, and digest_authorize for Digest HTTP Auth, here you can find them: https://github.com/brynary/rack-test/blob/master/lib/rack/test.rb

So you can do:

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

Or you can write a simple helper for Basic HTTP Auth:

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


None of the page.driver.* solutions worked for me. I'm using Poltergeist, not Selenium, so that might have something to do with it. Here's what did work:

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

Then, in your spec:

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

  # Your test code here...
end


This has changed in recent versions of cucumber-rails (I am using 1.0.2).

cucumber-rails uses the Rack/Test driver by default, so if you have not changed that, the following instructions will work.

Create features/step_definitions/authorize.rb:

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

Now you can use this in your features:

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


I had to do this horrible hack to get it work worth headless and with 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


Man, none of these solutions worked for me.

Pistos' solution came close and worked for feature specs with js: true but failed when headless.

This below solution works for me for both headless and js: true specs.

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

Then, in your spec:

feature 'User does something' do
  include_context 'When authenticated'

  # test examples
end
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号