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 m
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
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
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
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
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