I'm trying to add an authorization token to an RSpec get JSON API test in Rails. But everything tried so far results in an error. The issue seems that the token is not being properly passed in the request.
expected the response to have a success status code (2xx) but it was 401
Current code:
Project_spec.rb (tests)
before do
#project = create(:project, :key => "123")
get '/api/v1/projects/1', {:Authorization => "Token 123"}, format: :json
end
it "returns correct status" do
expect( response ).to have_http_status(:success)
end
ProjectsController.rb
before_filter :restrict_access, :except => :create
def show
#project = Project.find(params[:id])
render json: #project
end
def restrict_access
authenticate_or_request_with_http_token do |token, options|
Project.exists?(key: token)
end
end
Based on a few recommended solution found online, I've tried
get '/api/v1/projects/1', format: :json, token: "123"
get '/api/v1/projects/1', { 'HTTP-AUTHORIZATION' => 'Token "123"' }, format: :json
get '/api/v1/projects/1', {:Authorization => "Token 123"}, format: :json
But nothing seems to successfully pass the authorization token.
Note: Style in #3 works when posting from an external application, but not in the RSpec test itself.
Does anyone have experience with this and can share some direction?
Use it like:
get '/api/v1/projects/1', {}, { Authorization: "Token 123"}
get is the http method, {} an empty params, { :Authorization => "Token 123"} headers
get(path, parameters = nil, headers_or_env = nil)
Documentation
Other way:
before do
# some code here
#request.env['Authorization'] = "Token 123"
get '/api/v1/projects/1', format: :json
end
It worked when I just tried like this
get '/api/v1/projects/1', as: :json, headers: {:Authorization => "Token 123"}
Related
require 'rails_helper'
RSpec.describe "User management", :type => :request do
describe "Example::V2::Users" do
describe "GET /api/v2/users/" do
it 'returns status 200, authorized' do
#token = "Bearer 123"
#url = "https://api.example-v2.com/v2/users/me"
#headers = { "AUTHORIZATION" => #token}
get #url, as: :json, headers: {:Authorization => #token}
expect(response.status).to eq 200
end
end
end
end
I am trying to pass the #token but I am getting this error
Failure/Error: get #url, as: :json, headers: {:Authorization => #token}
TypeError: no implicit conversion of nil into String
I can make a get request without the params and headers and it works but as soon as I add params or headers I get the error, I even tried writing it like so
1 - get #url, {}, { Authorization: #token}
ArgumentError: wrong number of arguments (given 2, expected 1)
2 - get #url, params: {}, headers: { Authorization: #token}
TypeError: no implicit conversion of nil into String
Some smart people please point me in the right direction =).
Gems:
gem 'rspec-rails', '~> 3.8'
gem 'rails', '~> 6.0.2.2'
get #url, as: :json, headers: { Authorization: #token }
this works in my environment when type: reuqst.
I suggest you can use byebug just before the GET request
and check the #token and the #url.
If everything looks good.
Check the get if it can make request to root url?
Check the rails_helper if it requires any suspicious file?
Please check this its working for me.
require 'rails_helper'
RSpec.describe "User management", :type => :request do
describe "PeopleGoal::V2::Users" do
describe "GET /api/v2/users/" do
it 'returns status 200, authorized' do
request.headers["AUTHORIZATION"] = "Basic #{user.id}"
#url = "https://api.peoplegoal-v2.com/v2/users/me"
get #url, format: :json
expect(response.status).to eq 200
end
end
end
end
I have a rails API app using devise_token_auth and in my tests (minitest) I need to send POST requests and signed in users so I used the sign_in method but it doesn't seem to be doing anything.
This is my test file
require 'test_helper'
class ActivityControllerTest < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
test "post activity" do
sign_in users('one')
post '/activity/', params: {
original_activity_log_file: fixture_file_upload('files/test_gpx.gpx', 'application/gpx'),
title: 'test activity',
description: 'test description'
}
assert_response 200
end
end
And this is the result when run
Expected response to be a <200: OK>, but was a <401: Unauthorized>
Response body: {"errors":["You need to sign in or sign up before continuing."]}.
Expected: 200
Actual: 401
What could be going on here to cause the test to fail?
You're using devise_token_auth in that case plain devise helpers doesn't work, you need perform plain authorization with post request. Here is an example:
# make a request in order to get tokens
post(
api_user_session_path,
params: {
email: "foo#bar.com",
password: "password"
}.to_json,
headers: {
'Content-Type' => 'application/json',
'Accept' => 'application/json'
}
)
# fetch data from response
client = response.headers['client']
token = response.headers['access-token']
expiry = response.headers['expiry']
token_type = response.headers['token-type']
uid = response.headers['uid']
auth_params = {
'access-token' => token,
'client' => client,
'uid' => uid,
'expiry' => expiry,
'token_type' => token_type
}
new_client = users('one')
get(
api_find_client_by_name_path(new_client.name),
headers: auth_params
)
assert_response :ok
Controller: payments_controller.rb
class PaymentsController < ApplicationController
# This is needed to have Postman work
skip_before_action :verify_authenticity_token
rescue_from ActiveRecord::RecordNotFound do |exception|
render json: 'not_found', status: :not_found
def create
new_payment = Payment.new(new_params)
current_loan = Loan.find(new_params[:loan_id])
if Payment.valid?(new_payment, current_loan)
Payment.received(new_payment, current_loan)
current_loan.save
new_payment.save
redirect_to '/loans'
else
raise 'Amount entered is above the remaining balance'
end
end
end
This method works when I test it in Postman. However, I can't seem to write a test for it that passes. I currently have:
payments_controller_spec.rb
require 'rails_helper'
RSpec.describe PaymentsController, type: :controller do
describe "#create", :type => :request do
let!(:loan) {Loan.create!(id: 1, funded_amount: 500.0)}
params = '{"payment":{"amount":400, "loan_id":2}}'
it 'creates and saves a payment while saving the associated fund_amount of the loan' do
post "/payments", params.to_json, {'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json'}
expect(loan.funded_amount).to eql(600.0)
end
end
end
The error is:
Failure/Error: post "/payments", params.to_json, {'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json'}
ActionController::ParameterMissing:
param is missing or the value is empty: payment
Valid parameters (that work with Postman) are:
{"payment":{"amount":400,"loan_id":2}}
Any help would be appreciated!
*** UPDATE ****
After messing around with this for a while, I finally got it to work with this:
describe "#create", :type => :request do
let!(:loan) {Loan.create!(id: 1, funded_amount: 500.0)}
it 'creates and saves a payment while saving the associated fund_amount of the loan' do
json = { :format => 'json', :payment => { :amount => 200.0, :loan_id => 1 } }
post '/payments', json
loan.reload
expect(loan.funded_amount).to eql(300.0)
end
end
You can pass in your params like this.
it 'creates and saves a payment while saving the associated fund_amount of the loan' do
post "/payments", payment: { amount: 400, loan_id: 1 }, {'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json'}
expect(loan.funded_amount).to eql(600.0)
end
I am putting together a Restful JSON API using rails-api.
I am in the processing of testing my DELETE api/v1/users/:id using rspec. I cannot get it to pass when I use an HTTP token as authentication (for the delete action). I have tested via the terminal and it works but the test wont pass.
Here is the test spec/requests/api/v1/users_spec.rb
describe "DELETE api/v1/users/:id" do
it "deletes the requested user" do
user = FactoryGirl.create(:user)
request_headers = {
'Authorization' => 'Token token="foobar"'
}
delete "api/v1/users/#{user.id}", request_headers
expect(response.status).to eq 204
end
end
The error I get is expect 204 got 401.
In my users_controller.rb I am using this to get the token
before_action :authenticate, only: [ :destroy ]
TOKEN = "foobar"
def destroy
#user = find_user
#user.destroy
head 204
end
private
def authenticate
authenticate_or_request_with_http_token do |token, options|
token == TOKEN
end
end
I have also tried the following for setting the authorisation token in the request_headers
request_headers = {
'HTTP_AUTHORIZATION' => 'Token token="foobar"'
}
Can anyone point out where I am going wrong or point me in the right direction?
This is now solved via this approach:
describe "DELETE api/v1/users/:id" do
let(:auth_headers) {
{ 'AUTHORIZATION' => 'Token token="foobar"' }
}
let(:user) { FactoryGirl.create(:user) }
it "deletes the requested user" do
delete "api/v1/users/#{user.id}", {}, auth_headers
expect(response.status).to eq 204
end
end
Basically the http headers need to be set in the third parameter. The solution above as passing it as the second so it wasnt getting recognised.
I am trying to write a test using rspec 2.12.2, to test an api written in rails 3.2.6.
However the authorization token is not being passed, have no issue calling this from curl.
get '/API/V1/voucher/XXXXXXXXXXXXXXX/redeem.json', {}, { 'Authorization' => 'Token token=XXXXXXXXXXXXXXX'}
the response back from the request from a overwritten method to return the error in json below.
def request_http_token_authentication(realm = "Application")
self.headers["WWW-Authenticate"] = %(Token realm="#{realm.gsub(/"/, "")}")
self.__send__ :render, :json => { :error => "HTTP Token: Access denied. You did not provide an valid API key." }.to_json, :status => :unauthorized
end
setting the header to this worked.
get '/API/V1/voucher/XXXXXXXXXXXXXXX/redeem.json', {}, { 'HTTP_AUTHORIZATION' => 'Token token=XXXXXXXXXXXXXXX'}