Is it possible to use 'form_authenticity_token' inside a spec? - ruby-on-rails

It's possible to use form_authencity_token inside a controller in Rails.
def create
#user = self.resource = warden.authenticate!(auth_options)
sign_in(resource_name, resource)
#csrfToken = form_authenticity_token
#user
end
My question is: is it possible to have form_authencity_value inside a spec? I'm testing a controller and a JSON response from SessionsController (Devise). And I have to update csrf-token constantly to don't get erros like: Can't verify CSRF token authenticity in my requests.
Please, I'm already sending to the server my csrf-token and it's working perfectly. My problem here is with RSpec, to test my RABL response after logging in (and logout - that is not a RABL view).
My test is something like this:
expected_response = {
'id' => #user.id,
'email' => #user.email,
'first_name' => #user.first_name,
'last_name' => #user.last_name,
'created_at' => #user.created_at,
'updated_at' => #user.updated_at,
'csrfToken' => # PROBLEM
}.to_json
expect(response.body).to eq(expected_response)
How can I have form_authencity_value inside my spec?

If you are able to assign it to #csrfToken, then what you need is:
{
# ...
#csrfToken' => assigns(:csrfToken)
}
The assigns method can dig up any controller instance variable you've set.

Another possibility is to stub out form_authenticity_token if you aren't assigning it to an instance variable.
expect(controller).to receive(:form_authenticity_token).and_return('a_known_value')
You can use expect or allow. Now you have a known value to compare against.

Related

How do I bypass recaptcha verification in rails controller w/ RSPEC?

In my rails UsersController - users#sign_up action, I perform verification to ensure the user has a valid recaptcha v3 token before moving on to the rest of the controller logic. If the recaptcha verification fails then the controller returns and responds with an error message. However, my rspec tests are failing because I am unsure how to mock / bypass the verification in the controller.
spec/requests/auth_spec.rb:
RSpec.describe "Authentication Requests", type: :request do
context "sign up user" do
it "fails to sign up a user without email address" do
headers = { :CONTENT_TYPE => "application/json" }
post "/api/v1/sign_up", :params => { :email => nil, :password => "password123"}.to_json, :headers => headers
expect(response.header['Content-Type']).to include('application/json')
expect(response_body_to_json).to eq({"error"=>"Failed to create user"})
end
end
end
The test is failing when I post to /api/v1/sign_up because there are missing params for the recaptcha token. As far as I understand, it isn't possible to mock a recaptcha v3 token. Therefore it would be preferable to have verify_recaptcha return true for the rspec test.
controllers/api/v1/users_controller:
def sign_up
# Rspec fails here with missing params error
return if !verify_recaptcha('sign_up', recaptcha_params[:token])
#user = User.new(user_credential_params)
if #user.valid?
# Handle success/fail logic
end
end
private
def user_credential_params
params.permit(:email, :password)
end
def recaptcha_params
params.permit(:token)
end
controllers/concerns/users_helper.rb:
def verify_recaptcha(recaptcha_action, token)
secret_key = Rails.application.credentials.RECAPTCHA[:SECRET_KEY]
uri = URI.parse("https://www.google.com/recaptcha/api/siteverify?secret=#{secret_key}&response=#{token}")
response = Net::HTTP.get_response(uri)
json = JSON.parse(response.body)
recaptcha_valid = json['success'] && json['score'] > 0.5 && json['action'] == recaptcha_action
if !recaptcha_valid
render :json => { :error_msg => 'Authentication Failure' }, :status => :unauthorized
return false
end
return true
end
Can I stub / mock the verify_recaptcha method that comes from the users_helper concern to return true? Is there a better way to accomplish this?
I did due diligence before asking this question and I found this post: mocking/stubbing a controller recaptcha method with rspec in rails.
This was the answer for that post:
allow(controller).to receive(:verify_recaptcha).and_return(true)
The above didnt work for me because individual had their verify_recaptcha method inside of ApplicationController.rb (which seems a little dirty in my opinion). Given that my verify_recaptcha method is inside of a concern, I am not sure how to access the concern via Rspec.
You can try adding UserController.expects(:verify_recaptcha).returns(true) to your test.
This will bypass the recaptcha or Just try finding where the verify_recaptcha method exists and then write controller or class name before the expect method in
UserController.expects(:verify_recaptcha).returns(true)

Rspec not testing passing tests in regards to redirect

I am in a bootcamp and I cannot seem to pass this test. The project is creating your bootleg version of twitter and the test is:
it 'signup directs user to twitter index' do
params = {
:username => "skittles123",
:email => "skittles#aol.com",
:password => "rainbows"
}
post '/signup', params
expect(last_response.location).to include("/tweets")
end
My controller that handles this test is below:
post '/users' do
#user = User.create(params[:user])
#error = #user.errors.full_messages
unless #error == []
redirect to '/signup'
else
session[:user_id] = #user.id
redirect to '/tweets'
end
end
Basically what happens is that when I register a user and the data persists into the database my test should pass cause the expected last_response.location is to include '/tweets' and that is where
it redirects to. I don't understand why it's not passing.
Because the test was asking for post /signup and instead of using /signup as the route method name after the user posted the information to create the account I used /users. This caused the error.

Rspec testing instance variables with user creation

I'm testing to make sure that a created user is assigned to my instance variable #user. I understand what get means, but I'm not sure what to write for the test. I'm returning with an argument error for a bad URI or URL. What's wrong with my test and how do I fix it?
it "checks #user variable assignment for creation" do
p = FactoryGirl.create(:user)
get :users
# I'm confused on what this line above means/does. What does the hash :users refer
#to
assigns[:user].should == [p]
end
The expected URI object or string error refers to get :users and the error is as follows
Failure/Error get :users
ArgumentError:
bad argument: (expected URI object or URI string)
I guess that what you want is
it "checks #user variable assignment for creation" do
p = FactoryGirl.create(:user)
get :show, id: p.id
assigns(:user).should == p
end
The line you were not sure about checks that content of the assigned variable (#user) in the show view of the user p, is equal to the p user you just created more information there
what action are you trying to test? usually, for creation, you need to test that the controller's "create" action creates a user and assigns an #user variable
I would test it this way:
describe 'POST create' do
it 'creates a user' do
params = {:user => {:name => 'xxx', :lastname => 'yyy'}}
User.should_receive(:create).with(params)
post :create
end
it 'assigns the user to an #user instance variable' do
user = mock(:user)
User.stub!(:create => user)
post :create
assigns(:user).should == user
end
end
notice that I stub/mock all user methods, since you are testing a controller you don't have to really create the user, you only test that the controller calls the desired method, the user creation is tested inside the User model spec
also, I made 2 tests (you should test only 1 thing on each it block if possible, first it test that the controller creates a user, then I test that the controller assigns the variable
I'm assuming your controller is something like this:
controller...
def create
#user = User.create(params[:user])
end
which is TOO simple, I guess you have more code and you should test that code too (validations, redirects, flash messages, etc)

Rails - passing parameters in a redirect_to - is session the only way?

I have a controller set as the root of my app. It accepts in a parameter called uid and checks to see if the user exists. If not, I want it to redirect to the new user page and pre-populate the uid field with the uid in the parameter.
In my root_controller:
def index
if params[:uid]
#user = User.find_by_uid(params[:uid])
if (!#user.blank?)
# do some stuff
else
session[:user_id] = params[:uid]
redirect_to(new_user_path, :notice => 'Please register as a new user')
end
else
# error handling
end
end
In my users_controller, GET /users/new action:
def new
#user = User.new
#user.uid = session[:user_id]
# standard respond_to stuff here
end
This all works fine, but is this an acceptable way to do this? I originally tried passing the uid in the redirect statement, like:
redirect_to(new_user_path, :notice => 'Please register as a new user', :uid => params[:uid])
or even testing it with:
redirect_to(new_user_path, :notice => 'Please register as a new user', :uid => 'ABCD')
but neither seemed to pass the value to users_controller...I couldn't access it using params[:uid] from that controller.
Is session a proper place to store stuff like this, or is there a better way to pass it via the redirect? Thanks!
A session is fine to store that kind of information. Depending on what you are doing with the uid it might actually be dangerous to allow it to be read from the URL. Imagine if the end user was malicious and started putting other user's IDs into there.
For messages that should only last until the next request Rails actually has the flash object which will carry it over for you.
http://guides.rubyonrails.org/action_controller_overview.html#the-flash
That said, if you want to redirect to a url and pass some params, do so like this:
redirect_to(new_user_path(:notice => 'Please register as a new user', :uid => 'ABCD'))
The params you want to pass are arguments to the new_user_path method, not the redirect_to method.

Rails inherited resources usage

I'm using Inherited Resources for my Rails 2.3 web service app.
It's a great library which is part of Rails 3.
I'm trying to figure out the best practice for outputting the result.
class Api::ItemsController < InheritedResources::Base
respond_to :xml, :json
def create
#error = nil
#error = not_authorized if !#user
#error = not_enough_data("item") if params[:item].nil?
#item = Item.new(params[:item])
#item.user_id = #user.id
if !#item.save
#error = validation_error(#item.errors)
end
if !#error.nil?
respond_with(#error)
else
respond_with(#swarm)
end
end
end
It works well when the request is successful. However, when there's any error, I get a "Template is missing" error. #error is basically a hash of message and status, e.g. {:message => "Not authorized", :status => 401}. It seems respond_with only calls to_xml or to_json with the particular model the controller is associated with.
What is an elegant way to handle this?
I want to avoid creating a template file for each action and each format (create.xml.erb and create.json.erb in this case)
Basically I want:
/create.json [POST] => {"name": "my name", "id":1} # when successful
/create.json [POST] => {"message" => "Not authorized", "status" => 401} # when not authorized
Thanks in advance.
Few things before we start:
First off. This is Ruby. You know there's an unless command. You can stop doing if !
Also, you don't have to do the double negative of if !*.nil? – Do if *.present?
You do not need to initiate a variable by making it nil. Unless you are setting it in a before_chain, which you would just be overwriting it in future calls anyway.
What you will want to do is use the render :json method. Check the API but it looks something like this:
render :json => { :success => true, :user => #user.to_json(:only => [:name]) }
authorization should be implemented as callback (before_filter), and rest of code should be removed and used as inherited. Only output should be parametrized.Too many custom code here...

Resources