Signed cookies and Test:unit don't mix: "NoMethodError" - unit-testing

I am using signed cookies to maintain my user across pages, pretty much implemented as here.
I use two methods, sign_in(account) and sign_out to manipulate my cookies, creating or destroying them as you would expect ...
module SessionsHelper
def sign_in account
cookies.signed[:auth_account] = {
:expires => 1.week.from_now,
:value => [account.id, account.hash]
}
end
def sign_out
cookies.delete(:auth_account)
end
end
However, when trying to use this method, or the authenticate method that matches it in the ApplicationController from the functional tests, I get a NoMethodError:
NoMethodError: undefined method `signed' for {}:ActiveSupport::HashWithIndifferentAccess
I realise from this and this that this is an issue with the way cookies are defined differently in the test case, but I can't get any of these solutions to work. For completeness, an example test that fails with the above error:
require 'test_helper'
class AccountsControllerTest < ActionController::TestCase
include SessionsHelper
setup do
# We need to fake authentication by manually
# assigning an account to the sign_in process
sign_in accounts(:ia)
#account = accounts(:ia)
end
test "should 403 on index if unauthenticated" do
sign_out
get :index
assert_response :forbidden
end
test "should 200 on index if authenticated" do
get :index
assert_response :success
end
end

You can't set cookies in your test with the cookies variable like you do in your controller.
The cookies variable in your tests is use for read cookies after doing requests call (get/post...) and not for writing
In order to spoof login within your tests you should set cookies via #request.cookies[:auth]
you can put the following method in your test_helper and use it in all your tests
def signin user
#request.cookies[:auth] = user.auth
end
and in your tests
test "get dashboard if logged in" do
signin #user
get :index
end

Related

Redirect_to claims to work, but doesn't actually happen in the browser

Here is the Controller code where I call the redirect:
def helpful
flash[:notice] = I18n.t(:thanks_for_feedback)
redirect_to :back
end
The log claims:
Redirected to http://localhost:3000/p/anime/2?page=1
Completed 302 Found in 3147.7ms (Searchkick: 857.1ms)
But, nothing actually happens in the browser (Chrome, if it matters).
Probably you're using an AJAX request.
If it is the case, take a look: Rails 3: How to "redirect_to" in Ajax call?

After user's cookie expires execute an action in rails

I want to execute an action after user's cookie expires.
The action is session#destroy. Any idea how to do that?
This is session_store.rb
Rails.application.config.session_store(
key: '_app_session',
expire_after: ENV['SESSION_EXPIRE'].to_i.minutes
)
If you are using devise gem then you can simply authenticate user before action like this. This will check use session expired or not.
before_action :authenticate_user!
For manual to check the session is expired or not before action.
Add this line to your application controller :
before_action :expire_session
private
def expire_session
time_left = (session[:expire_after] - Time.now).to_i
unless time_left > 0
# redirect to login page
else
session[:expire_after] = Time.now + ENV['SESSION_EXPIRE'].to_i.minutes
end
end

Rails 4 Devise 3 multiple New Registration pages

Using Rails 4 and Devise 3, I would like to have different registration pages based on the URL my user is given.
As an example, each of the following should be directed to a different view that acts as devise registration.
www.mydomain.com <-- current root to registrations#new
www.mydomain.com/user_type_1
www.mydomain.com/user_type_2
www.mydomain.com/user_type_3
How would I do this? I can copy app/views/devise/registrations/new.html.erb to capture the form but how would I make the routing work?
My routes are currently set up as such (I close each session so the user can sign up a friend, but that is not relevant to this question)
devise_scope :user do
authenticated :user do
root :to => 'devise/sessions#destroy', as: :authenticated_root
end
unauthenticated :user do
root :to => 'devise/registrations#new', as: :unauthenticated_root
end
end
So you want three different url paths that point to three different views, but you want the forms to all send their info to the same REST endpoint in the same controller (users#create)? That sounds simple. You have GET requests to get the html/erb files for each registration page (welcome#index, welcome#cool, welcome#coolest), and routes for each to send the GET request to the right controller action.
Then you set up the forms to all send their info to POST to users#new, and one route from there.
Does that make sense?

Rails Integration test for edit/update

I am trying run an integartion test, testing an email that is sent after the user uses the edit action of the order controller to assign the shipping date of the product.
This is what I have so far:
# the user visits the order edit page
get "orders/#{order.id}/edit"
assert_response :success
# the user submits the edit form with a shipped_on date
# a nonredirect response is returned
post_via_redirect "/orders/#{order.id}/edit",
order: {
ship_date: "2014-3-13 20:20:20"
}
assert_response :success
#check that the user was redirected to edit template
assert_template "edit"
I think this is not working because I am making a POST request and not at PUT request. So my question is, how do I make the PUT request to the update action and pass the new information that would normally be in the form submitted through the browser.
There is a method put_via_redirect , so it can be used in your test.
More information about the method is there http://apidock.com/rails/ActionController/Integration/Session/put_via_redirect

Trying to get a POST to return 400 bad request

I have a create method that builds a new model through an association and I was expecting it to return a 400 response with some text if no params were in the POST request. However, I get an error.
This is in Rails 4.0.2
controller methods:
def create
#cast_profile = current_user.build_cast_profile(cast_profile_params)
if #cast_profile.save
redirect_to cast_profile_path
else
render :edit
end
end
def cast_profile_params
params.require(:cast_profile).permit(:name, :email, :public)
end
If I pass the params its all fine but I'm trying to test the bad request scenario.
Here's the error:
ActionController::ParameterMissing: param not found: cast_profile
I could rescue it explicitly but I thought strong parameters was supposed to do that automatically.
The behaviour is as follows:
Handling of Unpermitted Keys
By default parameter keys that are not explicitly permitted will be
logged in the development and test environment. In other environments
these parameters will simply be filtered out and ignored.
Additionally, this behaviour can be changed by changing the
config.action_controller.action_on_unpermitted_parameters property in
your environment files. If set to :log the unpermitted attributes will
be logged, if set to :raise an exception will be raised.
(source)
I would suggest rescuing from this exception with 400 status (Bad Request):
rescue_from ActionController::ParameterMissing do
render :nothing => true, :status => :bad_request
end