I would like to test controllers in Rails 5 for which Basic Authentication is activated. The way explained in the current official instruction (as of 2018-10-14) does not work for some reason. The Q&A "Testing HTTP Basic Auth in Rails 2.2+" seems too old for Rails 5 (at least for the default).
Here is a simplified example to reproduce the case.
I made an Article model and related resources by scaffold from a fresh install of Rails (latest stable version 5.2.1):
bin/rails g scaffold Article title:string content:text
and added the basic auth function to the controller, following the official guide; then the ArticlesController is like this, which certainly works:
# /app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
http_basic_authenticate_with name: "user1", password: "pass"
before_action :set_article, only: [:show, :edit, :update, :destroy]
def index
@articles = Article.all
end
end
The official instruction explains the way to test basic authentication; you add
request.headers['Authorization']
in the setup
block in the test file of the controller, which I did:
# /test/controllers/articles_controller_test.rb
require 'test_helper'
class ArticlesControllerTest < ActionDispatch::IntegrationTest
setup do
request.headers['Authorization'] =
ActionController::HttpAuthentication::Basic.encode_credentials("user1", "pass")
@article = articles(:one)
end
test "should get index" do
get articles_url
assert_response :success
end
end
However, bin/rails test
fails as follows:
# Running:
E
Error:
ArticlesControllerTest#test_should_get_index:
NoMethodError: undefined method `headers' for nil:NilClass
test/controllers/articles_controller_test.rb:5:in `block in <class:ArticlesControllerTest>'
bin/rails test test/controllers/articles_controller_test.rb:10
Clearly, request
method returns nil, and hence request.headers['Authorization']
fails. It is the same if the statement is placed at the top of 'testing-index' block instead.
I have found request
returns a proper value after get articles_url
is run, but it is too late by that time; I mean, Authentication has already failed by that time (obviously). With some googling, it seems some people use @request
and @response
for the purpose instead, but I have also found the they are exactly in the same situation as request
(expectedly?), that is, they are nil before get
.
What is the way to bypass or test Basic Auth in testing of controllers or integration tests in Rails 5?
EDIT:
"The current official instruction (as of 2018-10-14)" is apparently wrong. See the answer.
get
, theparams
option is optional and so this works:get articles_url, headers: { Authorization: ActionController::HttpAuthentication::Basic.encode_credentials('dhh', 'secret') }
– Agosto