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.
Testing Basic Auth with httpbinThe endpoint for Basic Auth is /basic-auth/{user}/{passwd} . For example, if you go to http://httpbin.org/basic-auth/foo/bar you'll see a prompt and you can authenticate using the username foo and the password bar .
Or we can run a single test file by passing the bin/rails test command the filename containing the test cases. This will run all test methods from the test case. You can also run a particular test method from the test case by providing the -n or --name flag and the test's method name.
To run a Minitest test, the only setup you really need is to require the autorun file at the beginning of a test file: require 'minitest/autorun' . This is good if you'd like to keep the code small. A better way to get started with Minitest is to have Bundler create a template project for you.
Integration. Don't try to test all the combinations in integration tests. That's what unit tests are for. Just test happy-paths or most common cases.
The testing docs were incorrect and have been updated but not yet released. The updated docs read:
NOTE: If you followed the steps in the Basic Authentication section, you'll need to add authorization to every request header to get all the tests passing:
post articles_url, params: { article: { body: 'Rails is awesome!', title: 'Hello Rails' } }, headers: { Authorization: ActionController::HttpAuthentication::Basic.encode_credentials('dhh', 'secret') }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With