I have a controller in rails such that when i go to the url :
/my-path
it outputs json text.
There is no authorization involved.
When I open the URL in browser or postman i get the expected json data.
I can't test it in rspec as i get a no authorization error.
before do
get base_url , params: {} #, headers: { 'Content-Type' => 'application/x-www-form-urlencoded', Authorization: 'Token: sdaf' }
end
it 'returns 200' do
puts response
expect(response.code).to eq '200'
end
When i do the above, i get the following error :
Failure/Error: expect(response.code).to eq '200'
expected: "200"
got: "401"
Authorization header missing.
I am new to rails, so i have little idea on what i am missing out here.
Hope you are writing your rspec test in the controller test file, in that case if your writing test for say example home_controller, index action explictly specify controller action like below, hope it helps :)
before do
get :index, params: {} #, headers: { 'Content-Type' => 'application/x-www-
form-urlencoded', Authorization: 'Token: sdaf' }
end
Related
rails 5.0.0.1
rspec 3.5
I have inherited a code base. I am busy writing integration tests to tie down the app functionality before I consider refactoring.
I have the following lines in a controller concern before_action. It seems to read the request body. The json value here is used to extract an identifier used to authenticate the request.
request.body.rewind
body = request.body.read
json = JSON.parse(body) unless body.empty?
I need to test that the authentication happens correctly.
How can I set the request.body for a GET request spec?
I think you should be able to do this via the request env RAW_POST_DATA
get root_path, {}, 'RAW_POST_DATA' => 'raw json string'
request.raw_post # "raw json string"
See:
How to send raw post data in a Rails functional test?
https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec
#rails_post_5
require "rails_helper"
RSpec.describe "Widget management", :type => :request do
it "creates a Widget and redirects to the Widget's page" do
headers = { "CONTENT_TYPE" => "application/json" }
post "/widgets", :params => '{ "widget": { "name":"My Widget" } }', :headers => headers
expect(response).to redirect_to(assigns(:widget))
end
end
or just
post "/widgets", params: '{ "widget": { "name":"My Widget" } }'
I got JSON Web Token login going but am in the process of fixing my Rails 5 Controller tests.
I am trying to pass my JWT auth token to my GET request header.
So far, in my User Controller test, I have this test:
test "users should return list of users" do
User.create(#bob)
auth_token = log_in_as(#bob)
request.headers['Authorization'] = "JWT #{auth_token}"
get users_path
assert_response :success
assert_not response.body.empty?
end
So far that doesn't work, I get response not authenticated.
If I change it to like so:
test "users should return list of users" do
User.create(#bob)
auth_token = log_in_as(#bob)
get users_path, nil, { HTTP_AUTHORIZATION: "JWT #{auth_token}" }
puts "response = #{response.body}"
assert_response :success
assert_not response.body.empty?
end
I get this expected response:
response = {"users":[{"id":298486374,"name":"MyString","email":"MyString","cats":[]},{"id":980190962,"name":"MyString","email":"MyString","cats":[]},{"id":980190963,"name":"Bob","email":"bob#gmail.com","cats":[]}]}
but I also get a DEPRECATED WARNING:
DEPRECATION WARNING: ActionDispatch::IntegrationTest HTTP request
methods will accept only the following keyword arguments in future
Rails versions: params, headers, env, xhr
Examples:
get '/profile', params: { id: 1 }, headers: { 'X-Extra-Header' =>
'123' }, env: { 'action_dispatch.custom' => 'custom' }, xhr: true
So what is the recommended way to set HTTP Authorization header in Rails 5 ?
You need to include the params and headers key in the arguments see here.
get users_path, params: {}, headers: { HTTP_AUTHORIZATION: "JWT #{auth_token}" }
You first example probably isn't working because you are setting the JWT on Authorization and not HTTP_AUTHORIZATION.
request.headers['HTTP_AUTHORIZATION'] = "JWT #{auth_token}"
I am trying to write a failing spec for passing a invalid json when making a request to a rails api endpoint.
In a full rail api I would have used capybara and curl to make the actual request.
How do I pass a invalid json via a rspec request spec?
I ended up finding a solution to this, you need to use request specs, something along this lines:
require 'rails_helper'
RSpec.describe 'JSON formatting', :type => :request do
context 'with bad json' do
it 'returns 400 on bad json' do
headers = {
'ACCEPT' => 'application/json',
'CONTENT_TYPE' => 'application/json'
}
post '/some/path', "{", headers
expect(response.content_type).to eq("application/json")
end
end
end
I'm trying to write tests for an API which requires an hmac signature on each request.
describe Api::V2::HmacController, :type => :controller do
render_views
it 'GET' do
get :index, timestamp: Time.now.to_i, format: :json
expect(response.status).to eq(200)
end
end
I would like to add
request.env['x-api-key'] = API_KEY
request.env['x-api-hmac'] = "Encode"(API_SECRET, "parameters of the request")
to each request.
I'm open to any type of solution.
Question: How can I wedge a hook after the request has been formed, but hasn't sent?
I'm thinking of overwriting rspec get / post method, but I'm not sure how.
You can do it from in the block
request.headers['x-api-key'] = API_KEY
You shouldn't set access the request headers through the env.
See here
I'm trying to write out tests for a controller of mine that takes in requests from external services. So far this is my test:
describe ApplyController do
context 'when valid' do
let(:parameters) do
file = File.join File.dirname(__FILE__), '..', 'samples', 'Indeed.json'
JSON.parse(File.read file)
end
let(:signature) { 'GC02UVj0d4bqa5peNFHdPQAZ2BI=' }
subject(:response) { post :indeed, parameters, 'X-Indeed-Signature' => signature }
it 'returns 200 ok if Request is valid' do
expect(response.status).to eq 200
end
end
end
This should work according to the documentation I could find.
My controller right now looks something like this:
class ApplyController < Application Controller
def indeed
binding.pry
end
end
When I get into Pry in my test and try to check the value of request.headers['X-Indeed-Signature'] I always just get nil
Is there something that I am missing? I am using Rails 3.2 and Rspec 3
I think you want (straight from one of your links)
it "returns 200 ok"
#request.headers['X-Indeed-Signature'] = signature
post :indeed, parameters
response.status.should == 200
end
You don't need subject(:response)
I was able to fix it by using #request.env instead of #request.headers like so:
describe ApplyController do
context 'when valid' do
let(:parameters) do
file = File.join File.dirname(__FILE__), '..', 'samples', 'Indeed.json'
JSON.parse(File.read file)
end
let(:signature) { 'GC02UVj0d4bqa5peNFHdPQAZ2BI=' }
it 'returns 200 ok if Request is valid' do
#request.env['X-Indeed-Signature'] = signature
post :indeed, parameters
expect(response.status).to eq 200
end
end
end
I had many issues with the rubocop to avoid it, I wanted to put the headers into let. In addition call request.headers.merge! instead of #request.headers['key']=value.
I took the fix from here:
describe ApplyController do
context 'when valid' do
let(:parameters) do
file = File.join File.dirname(__FILE__), '..', 'samples', 'Indeed.json'
JSON.parse(File.read file)
end
let(:headers) do
{
signature: 'GC02UVj0d4bqa5peNFHdPQAZ2BI='
}
it 'returns 200 ok if Request is valid' do
request.headers.merge! headers
post :indeed, parameters
expect(response.status).to eq 200
end
end
end
Ok this is pretty silly of rspec.
Custom headers in Request Specs
headers = {
'AUTH' => 'super secret key'
}
post '/api/some_action', { user_id: 1337 }.to_json, headers
And in your controller:
def some_action
token = request.headers['AUTH']
end
Custom headers in Controller Specs
headers = {
'AUTH' => 'super secret key'
}
post '/api/some_action', { user_id: 1337 }, headers
And in your controller:
def some_action
token = request.headers['rack.session']['AUTH']
end
Just sharing the differences I had between the two. I don't believe I have any special configuration in rspec or rails to have the two different spec types' headers to be placed differently.