Rspec test to post as json - ruby-on-rails

I am having problems trying to post as JSON to my controller action within my rspec test
RSpec.describe RegistrationsController, type: :controller do
context 'Adding a Valid User' do
it 'Returns Success Code and User object' do
#params = { :user => {username: 'name', school: 'school'} }.to_json
post :create, #params
end
end
end
At the moment I want to get a successful post request firing but am getting this error back all the time
Failure/Error: post :create, #params
AbstractController::ActionNotFound:
Could not find devise mapping for path "/lnf".
My routes are setup like so
Rails.application.routes.draw do
constraints(subdomain: 'api') do
devise_for :users, path: 'lnf', controllers: { registrations: "registrations" }
devise_scope :user do
post "/lnf" => 'registrations#create'
end
end
end
Rake routes outputs the following
Prefix Verb URI Pattern Controller#Action
user_registration POST /lnf(.:format) registrations#create {:subdomain=>"api"}
lnf POST /lnf(.:format) registrations#create {:subdomain=>"api"}
So i have 2 declarations for the same action?
Could anyone shed some light on this please
Thanks

Ok so after a painstaking few hours i have got my tests passing correctly and posting as json by doing the following
require 'rails_helper'
RSpec.describe RegistrationsController, type: :controller do
before :each do
request.env['devise.mapping'] = Devise.mappings[:user]
end
context 'Adding a Valid User' do
it 'Returns Success Code and User object' do
json = { user: { username: "richlewis14", school: "Baden Powell", email: "richlewis14#gmail.com", password: "Password1", password_confirmation: "Password1"}}.to_json
post :create, json
expect(response.code).to eq('201')
end
end
end
My Routes are back to normal
Rails.application.routes.draw do
constraints(subdomain: 'api') do
devise_for :users, path: 'lnf', controllers: { registrations: "registrations" }
end
end
And in my test environment I had to add
config.action_mailer.default_url_options = { host: 'localhost' }
The key here was
request.env['devise.mapping'] = Devise.mappings[:user]
Not fully sure as yet to what it does, its next on my list to find out, but my tests are starting to run and pass

Related

How to test session constrained routes with rspec routing specs?

I have such code in my routes.rb:
Rails.application.routes.draw do
authorized = ->(request) { request.session[:user_id].present? }
not_authorized = ->(request) { request.session[:user_id].blank? }
constraints authorized do
resources :users
end
constraints not_authorized do
get 'login' => 'auth#login_page'
post 'login' => 'auth#create_session'
get '*unmatched_route', to: 'auth#login_page'
root 'auth#login_page'
end
end
And I have such users_routing_spec.rb file:
require "rails_helper"
RSpec.describe UsersController, type: :routing do
describe "routing" do
it "routes to #index" do
expect(:get => "/users").to route_to("users#index")
end
end
end
This test fails as it routes to 'auth#login_page' because there is no user_id
in session.
How can I call auth#create_session in advance to the expectation?
There is no request or #request object and I also can't make a manual request to 'auth#create_session'

Rails Spec Controller Test failing with custom route

Rails 5.1
RSpec 3.6
I have a Controller:
class SessionController < ApplicationController
def new
end
end
A custom route:
get 'login' => 'sessions#new'
RSpec Test:
require 'rails_helper'
RSpec.describe SessionController, type: :controller do
describe "GET #new" do
before do
routes.draw { get "login" => "sessions#new" }
end
it "returns http success" do
get :login
expect(response).to have_http_status(:success)
end
end
end
and get error:
ActionController::UrlGenerationError: No route matches {:action=>"login", :controller=>"session"}
So "get" within a controller test seems always map to the action not the route. What should i do to get this test run? thanks in advance.
ActionController::UrlGenerationError: No route matches
{:action=>"login", :controller=>"session"}
Your controller name is SessionController, so your route should be
get 'login' => 'session#new' not get 'login' => 'sessions#new'
require 'rails_helper'
RSpec.describe SessionController, type: :controller do
describe "GET #new" do
before do
routes.draw { get "login" => "session#new" }
end
it "returns http success" do
get :login
expect(response).to have_http_status(:success)
end
end
end
Change it in your routes.rb as well.
When you are writing tests and you use the methods get, post, delete, etc., those methods assume that any parameter you pass them is the name of an action within the controller being tested. So, this works:
get :new
because it generates url_for(:controller => :sessions, :action => :new).
This doesn't work:
get '/login'
because it generates url_for(:controller => :sessions, :action => '/login').

Could not find devise mapping for controller path

I know there are a ton of questions with this same problem but none of the solutions seem to be working for my situation.
I've defined my own sessions, registrations, and users controllers since I'm using an API with token authentication, but I can't seem to get my routes/scoping working.
I get the following error message upon trying to run an Spec test on my sessions controller (which inherits from DeviseController)
Failure/Error: post :create, credentials
AbstractController::ActionNotFound:
Could not find devise mapping for path "/api/v1/sessions/create?user_login%5Bemail%5D=rosina%40russel.name&user_login%5Bpassword%5D=12345678".
This may happen for two reasons:
1) You forgot to wrap your route inside the scope block. For example:
devise_scope :user do
get "/some/route" => "some_devise_controller"
end
2) You are testing a Devise controller bypassing the router.
If so, you can explicitly tell Devise which mapping to use:
#request.env["devise.mapping"] = Devise.mappings[:user]
I've actually done both of these things based on other answers that I've read, but I don't think its done correctly for my specific situation.
Here is the spec test I'm trying to run
describe "POST #create" do
before(:each) do
#user = FactoryGirl.create :user
#user.skip_confirmation!
#request.env['devise.mapping'] = Devise.mappings[:user]
end
context "when the credentials are correct" do
before(:each) do
credentials = { user_login: { :email => #user.email, :password => "12345678"} }
post :create, credentials
end
it "returns the user record corresponding to the given credentials" do
#user.reload
user_response = JSON.parse(response.body, symbolize_names: true)
expect(user_response[:auth_token]).to eql #user.auth_token
end
it { should respond_with :created }
end
end
As you can see, I'm specifying what it's saying that I haven't specified.
Here is the snippet from my routes.rb before the definition of my API in it's namespace:
namespace :api, defaults: { format: :json } do
namespace :v1 do
devise_for :users, skip: [:sessions, :registrations]
devise_scope :user do
post 'sessions', to: 'sessions#create'
delete 'sessions', to: 'sessions#destroy'
end
If anyone sees anything from with this please let me know, I'd love to test my controller...
And yes, my sessions_controller is located in app/controllers/api/v1/sessions_controller.rb and it is properly defined as class API::V1::SessionsController < DeviseController
I noticed that devise_for is supposed to SET Devise.mapping but that seems to not be happening at all!
I should've done this right away. I sent Devise.mappings.inspect to the logger and it read that the mapping was stored in :api_v1_user so the key in the mapping hash corresponds to the namespace that you wrote devise_for in... hopefully this will help others
Based on your routes, API is in json format. So you need to specify that when sending post method. Which is why I think rspec is complaining about that route not existing because it doesn't know to use json. Try changing this
post :create, credentials
to this
post :create, credentials, format: :json

Testing overridden Devise controllers – "No route matches"

I ran rails g devise:controllers users and my routes look like
devise_for :users, controllers: {
sessions: 'sessions'
}
I have a app/controllers/users/sessions_controller that I want to test. My routes look like:
$ rake routes
Prefix Verb URI Pattern Controller#Action
new_user_session GET /users/sign_in(.:format) sessions#new
user_session POST /users/sign_in(.:format) sessions#create
I set up my test like this:
# test/controllers/users/sessions_controller_test.rb
require 'test_helper'
class SessionsControllerTest < ActionController::TestCase
tests Users::SessionsController
test "sign in sanity check" do
user = users(:one)
post :create, email: user.email, password: 'password'
assert_response :success
end
end
Which fails with the error:
ActionController::UrlGenerationError: No route matches {:action=>"create", :controller=>"users/sessions", :email=>"one#example.com", :password=>"password"}
How do I correctly POST to the URL I want? I've tried all sorts of variations, but I'm missing some magic sauce here.
Change your routes.rb to
devise_for :users, controllers: {
sessions: 'users/sessions'
}
And in your test, make sure you have
class SessionsControllerTest < ActionController::TestCase
tests Users::SessionsController
include Devise::TestHelpers
test "sign in sanity check" do
request.env["devise.mapping"] = Devise.mappings[:user]
user = users(:one)
post :create, email: user.email, password: 'password'
assert_response :success
end
end
(You can see how Devise itself does it for an example.)

Devise, Rails-API, Routing issue

I have the following routes setup inside a rails api app:
constraints subdomain: 'api', path: '/' do
namespace 'api', path: '/' do
scope module: 'v1' , constraints: ApiConstraints.new(version: 1, default: true) do
devise_scope :user do
post 'sign_in' => 'sessions#create'
delete 'sign_out' => 'sessions#destroy'
end
resources :question
end
end
end
# rake routes
Prefix Verb URI Pattern Controller#Action
api_sign_in POST /sign_in(.:format) api/v1/sessions#create {:subdomain=>"api"}
api_sign_out DELETE /sign_out(.:format) api/v1/sessions#destroy {:subdomain=>"api"}
When I got to execute this test:
require 'rails_helper'
RSpec.describe Api::V1::SessionsController, :type => :controller do
describe '#create' do
it 'creates a session' do
#request.env["devise.mapping"] = Devise.mappings[:user]
user = User.create(email: 'rob#edukate.com', password: 'password')
post :create, action: :create, user_login: { password: user.password, email: user.email}
expect(response).to be_success
end
end
end
I get this error:
F
Failures:
1) Api::V1::SessionsController#create creates a session
Failure/Error: post :create, action: :create, user_login: { password: user.password, email: user.email}
AbstractController::ActionNotFound:
Could not find devise mapping for path "/sign_in?user_login%5Bemail%5D=rob%40edukate.com&user_login%5Bpassword%5D=password".
I have tried many variations of routes but I cannot get this simple test to pass. If I cannot get it completed like this I'll just roll my own Auth; but it appears devise is doing something odd with a Abstract controller. Thanks in advance!

Resources