I'm writting an API for a pet project of mine and was running rails 3.2.9
I decided to update rails in order to avoid security problems but I suddenly ran into some problems.
I've been able to resolve most of them but I keep getting this and don't know what to do with it.
I am using RSPEC to test a json API and until this upgrade everything was going just fine and all routes were working perfectly.
I'm not sure wether it's a bug or a bad usage from me, so I'm sorry if it's the former.
Here is my code :
Routes :
Fake::Application.routes.draw do
namespace :api do
namespace :v1 do
scope '/user' do
match "signup" => "registrations#create", :via => :post
match "delete" => "registrations#destroy", :via => :delete
match "login" => "sessions#create", :via => :post
match "logout" => "sessions#destroy", :via => :delete
end
end
end
end
Spec :
require 'spec_helper'
describe Api::V1::SessionsController do
before do
@user = {
:email => Faker::Internet::email,
:pseudo => Faker::Internet::user_name,
:password => Faker::Lorem::words(2).join
}
user = User.create @user
end
context 'should login in' do
it 'should be ok ' do
post '/api/v1/user/login', :user => @user
JSON.parse(response.body)["success"].should == true
end
it 'should fail without credentials' do
post '/api/v1/user/login', {}
JSON.parse(response.body)["success"].should == false
end
end
end
And the result :
± rspec spec/controllers/sessions_controller_spec.rb 5:21:10 PM
Rack::File headers parameter replaces cache_control after Rack 1.5.
FF
Failures:
1) Api::V1::SessionsController should login in should be ok with auth_token
Failure/Error: post '/api/v1/user/login', :user => @user
ActionController::RoutingError:
No route matches {:user=>{:email=>"[email protected]", :pseudo=>"linwood_gislason", :password=>"repellendusaliquid"}, :controller=>"api/v1/sessions", :action=>"/api/v1/user/login"}
# ./spec/controllers/sessions_controller_spec.rb:17:in `block (3 levels) in <top (required)>'
2) Api::V1::SessionsController should login in should fail without credentials
Failure/Error: post '/api/v1/user/login', {}
ActionController::RoutingError:
No route matches {:controller=>"api/v1/sessions", :action=>"/api/v1/user/login"}
# ./spec/controllers/sessions_controller_spec.rb:22:in `block (3 levels) in <top (required)>'
Finished in 0.50905 seconds
2 examples, 2 failures
Failed examples:
rspec ./spec/controllers/sessions_controller_spec.rb:15 # Api::V1::SessionsController should login in should be ok with auth_token
rspec ./spec/controllers/sessions_controller_spec.rb:21 # Api::V1::SessionsController should login in should fail without credentials
Edit :
Rails version : 3.2.11
Rspec version : 2.12.2
Ruby version : ruby 1.9.3p0
Did you also upgrade rspec or rspec-rails? If so, from what version to what version (rspec-rails only just released 2.12.2)?
I did a global update of my gems on my system and updated the Gemfile.lock with "bundle update".
It is using rspec-rails 2.12.2 and rspec 2.12.2
below is an excerpt of my Gemfile.lock
rspec-core (2.12.2)
rspec-expectations (2.12.1)
diff-lcs (~> 1.1.3)
rspec-mocks (2.12.1)
rspec-rails (2.12.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 2.12.0)
rspec-expectations (~> 2.12.0)
rspec-mocks (~> 2.12.0)
I find it weird that rspec-mocks is not 2.12.2 but 2.12.1 but well...
I find it weird that rspec-mocks is not 2.12.2 but 2.12.1 but well...
That is quite intentional. We don't want to have to release the whole suite to do patch releases on each gem, so the rspec gem depends on "rspec-xxx", "~> 2.12.0" where xxx is replaced by each of "core", "expectations", and "mocks": https://github.com/rspec/rspec/blob/master/rspec.gemspec#L31
In this case, 2.12.1 is the latest 2.12 release of rspec-core and rspec-mocks, whereas 2.12.2 is the latest release of rspec-expectations. Make sense?
BTW you can see that expressed in the last 3 lines of the part of Gemfile.lock you posted above:
rspec-core (~> 2.12.0)
rspec-expectations (~> 2.12.0)
rspec-mocks (~> 2.12.0)
Makes sense :)
Thanks
@Shahor were you able to find a workaround for this issue? I'm having the exact same problem.
@rafael It's a spare project and I didn't have much time this week so I didn't really dig.
Plus I'm "fairly new" to testing so I really don't know where to check for a solution =/
I don't know how to resolve this. If you have any idea feel free to comment again :)
I'm upping this since I have no idea what to do on the matter :(
Anyone has an idea/suggestion about how to make this work ? I don't know where to start looking at.
I am experiencing the same issue. I upgraded Rails version, along with rspec and rspec-rails. Now most of my controller tests fail with ActionController::RoutingError.
The application continues to work as expected though.
Yup, I would happily fix this if I knew where to start from :)
Well. My problem turned out to be with nested controllers and the change between journey 1.0.3 and 1.0.4.
The following works through the app, but would raise ActionController::RoutingError in a test:
resources :payments, only: [:index] do
resources :payment_policies, only: [:index], controller: "Payments::PaymentPolicies"
end
But replacing it with:
resources :payments, only: [:index] do
resources :payment_policies, only: [:index], controller: "payments/payment_policies"
end
Or:
resources :payments, only: [:index] do
resources :payment_policies, only: [:index], module: :payments
end
Fixes the problem. I'm not entirely sure where I should report a bug. Perhaps the controller syntax I was using is deprecated. But it may have broken. @alindeman have any input?
FYI that code is copied out of a proof of concept rails app available here:
https://github.com/kmcphillips/rspec_rails_routing_error_example
I don't really know if this is a bug I should report somewhere, or if that routing syntax was just working incidentally.
I tend to think it's a bug since my router doesn't really look like yours and is still not working =/
I can't find a way to rewrite it to make it work actually.
MyApp::Application.routes.draw do
namespace :api do
namespace :v1 do
# user stuff
scope '/user' do
match "signup" => "registrations#create", :via => :post
match "delete" => "registrations#destroy", :via => :delete
match "login" => "sessions#create", :via => :post
match "logout" => "sessions#destroy", :via => :delete
end
end
end
end
(thanks for the update :+1: )
You're spec is in the context of Api::V1::SessionsController so you just have to call the correct action :
context 'should login in' do
it 'should be ok ' do
post :create, {}
JSON.parse(response.body)["success"].should == true
end
it 'should fail without credentials' do
post :create, {}
JSON.parse(response.body)["success"].should == false
end
end
For me it works.
It would probably work, yup, but since it's an API and it should respond on http queries I'd like to test it like I would use it. Using the action directly wouldn't replicate the environment it will be used in.
So, try something like this :
spec/requests/api/v1/registrations_controller_spec.rb
require 'spec_helper'
describe Api::V1::RegistrationsController do
before do
@user = {
:email => Faker::Internet::email,
:pseudo => Faker::Internet::user_name,
:password => Faker::Lorem::words(2).join
}
#user = User.create @user
end
context 'should login in' do
it 'should be ok ' do
post api_v1_login_path, {}
JSON.parse(response.body)["success"].should == true
end
it 'should fail without credentials' do
post api_v1_login_path, {}
JSON.parse(response.body)["success"].should == false
end
end
end
I think this is a solution.
Because you want try if a request give you what you want, you don't want to test the Api::V1::RegistrationsController methods.
So may be rspec-rails acting in different way depending on your folders.
Nice try, but not working =/
3) Api::V1::SessionsController should login in should be ok with auth_token
Failure/Error: post api_v1_login_path, :user => @user
ActionController::RoutingError:
No route matches {:user=>{:email=>"[email protected]", :pseudo=>"cordelia_mayer", :password=>"laborenisi"}, :controller=>"api/v1/sessions", :action=>"/api/v1/user/login"}
# ./spec/controllers/sessions_controller_spec.rb:17:in `block (3 levels) in <top (required)>'
You didn't create the spec file in the right place, I still see the same error.
For me this is what I get :
rspec spec/requests/api_v1_spec.rb
1) Api::V1::SessionsController should login in should be ok
Failure/Error: post api_v1_login_path, {}
ActionView::MissingTemplate:
Missing template api/v1/sessions/create, application/create with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee]}. Searched in:
* "/Users/aweaoftheworld/Desktop/test_app/app/views"
# ./spec/requests/api_v1_spec.rb:16:in `block (3 levels) in <top (required)>'
Because I didn't doo anything in my controller except creating the methods.
And this what I get when running:
rspec spec/controllers/api/v1/sessions_controller_spec.rb
1) Api::V1::SessionsController should login in should be ok
Failure/Error: post api_v1_login_path, {}
ActionController::RoutingError:
No route matches {:controller=>"api/v1/sessions", :action=>"/api/v1/user/login"}
# ./spec/controllers/api/v1/sessions_controller_spec.rb:16:in `block (3 levels) in <top (required)>'
Hum... not sure what you mean by that.
Here's my directory structure :
Just try to move your spec into the file spec/requests/api_1_spec.rb and run it.
I didn't find why but rspec acting differently depending on the directory.
Ok thanks, it's working as expected.
I don't understand it though, why is it working under this repertory and not under the classic "controllers" (as it was before the rails update that broke everything) ? Can't find any ressource on that.
I'll go with this for now, but this is weird :/
Thanks
@Shahor Yeah this is really weird, didn't find anything about it too :s
Hey same here.
It does work on requests and not on controllers, but shouldn't this class be in controllers?
With controller specs, you use get :index
(for example), not get foos_path
. Controller specs don't run through the entire stack.
I understand that, but in my case I have the routing tester which tests that url /v1/users/create maps to v1/users#create. Which works.
And the test for controller is telling me that controller: "v1/users" action: "create doesn't exist", but it does. The same URL in requests does work. That's what weird for me.
And the test for controller is telling me that controller: "v1/users" action: "create doesn't exist", but it does. The same URL in requests does work. That's what weird for me.
If you post a small app I can pull down, I'll take a look.
Sure :)
In /spec/routing/v1/users_routing_spec.rb
require "spec_helper"
describe V1::UsersController do
describe "routing" do
it "routes to #create" do
post("v1/users").should route_to("v1/users#create")
end
end
end
Then, this WORKS in /spec/requests/v1_users_controller_spec.rb. Note the post v1_users_path
require 'spec_helper'
describe V1::UsersController do
describe "POST create" do
describe "with valid emails params" do
it "creates a new User" do
expect {
post v1_users_path, :user => valid_attributes, :format => :json
}.to change(User, :count).by(1)
end
end
This doesn't work in /spec/controllers/v1/users_controller_spec.rb.
returns RoutingError controller: "v1/users", action: "create", user: "{email: "[email protected]", password: "123456"}"
require 'spec_helper'
describe V1::UsersController do
describe "POST create" do
describe "with valid emails params" do
it "creates a new User" do
expect {
post :create , :user => valid_attributes, :format => :json
}.to change(User, :count).by(1)
end
end
I'm not sure this is the problem, but since I see this and it _might_ be related: you can't really simulate sending JSON at a controller spec.
What if you run this instead in the controller spec?
post :create, :user => { :email => "[email protected]", :password => "123456" }
I know this is a pretty old and closed issue but I am still having this problem currently with Rails 4.1 and Rspec 2.14. My situation is very similar but not exactly the same and I am not sure how the solution or workarounds specified here apply to me.
I request the repo owners / admins to re-open this issue (or ask me to create a new one - whichever you find fit) based on the sample code below :
Here are the gems I am using :
rspec (2.14.1)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
rspec-core (2.14.8)
rspec-expectations (2.14.5)
diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.14.6)
rspec-rails (2.14.2)
actionpack (>= 3.0)
activemodel (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
My routes definition :
scope 'api/:version' do
scope 'utils' do
get 'valid_event' => 'utils#valid_event'
end
end
Please note that it is a scope
unlike the previous code snippets which use a namespace
. So my controller lives at the usual location app/controller/utils_controller.rb
The output of rake routes
valid_event GET /api/:version/utils/valid_event(.:format) utils#valid_event
My controller spec
require 'spec_helper'
describe UtilsController do
describe 'valid_event' do
it 'should return false if org_id param is missing' do
get :valid_event, app_id: '123456', format: :json
response_hash = JSON.parse(response.body)
expect(response_hash['valid']).to be_false
end
# And 5 more example - all of which fail like the above one.
end
end
And when I run the specs I get this error :
UtilsController valid_event should return false if org_id param is missing
Failure/Error: get :valid_event, app_id: '123456', format: :json
ActionController::UrlGenerationError:
No route matches {:action=>"valid_event", :app_id=>"123456", :controller=>"utils", :format=>:json}
# ./spec/controllers/utils_controller_spec.rb:8:in `block (3 levels) in <top (required)>'
# -e:1:in `<main>'
The controller code itself works just fine. It is only the specs that fail.
What am I missing?
Further to the above mentioned details if I change the routes definition to any of the following the specs pass without any change anywhere else.
scope 'utils' do
get 'valid_event' => 'utils#valid_event'
end
get 'valid_event' => 'utils#valid_event'
It's only with nested scope
d routes that the tests are failing.
@sriranggd can you please open a new issue for this. I just tried with RSpec 3 and Rails 4 and I didn't have any problems. If possible, please setup a new sample repository which demonstrates the issue, trying to keep it as minimal as possible.
Eh stale page, I see you did that. Thanks
I'm currently still experiencing this issue. We even used the defined path only to get the No route matches {:controller=>"foo", :action=>"bar"}
even when it's defined and being used appropriately. This issue needs to be looked at further.
@moultonBLiNQ please open a new issue, providing your steps to reproduce, or if possible the repository where the issue is happening. Be sure to include your routes, controller, a single simple failing spec, Ruby version, Rails version, and RSpec versions.
Is there any progress on this? It's been more than two years and this issue keeps coming up several times. I'm not even sure if this is a Rails issue or Rspec's.
It's a closed issue so no. Routing errors and behaviour in different spec types are mostly a Rails issue, if you can replicate an issue in RSpec without the equivalent minitest also breaking feel free to open a new issue with that reproduction :)
Most helpful comment
That is quite intentional. We don't want to have to release the whole suite to do patch releases on each gem, so the rspec gem depends on "rspec-xxx", "~> 2.12.0" where xxx is replaced by each of "core", "expectations", and "mocks": https://github.com/rspec/rspec/blob/master/rspec.gemspec#L31
In this case, 2.12.1 is the latest 2.12 release of rspec-core and rspec-mocks, whereas 2.12.2 is the latest release of rspec-expectations. Make sense?