I'm running into issue which seems to indicate that ActionController::TestCase.get() method ignores what I have in routes.rb.
Rails version is 3.0.10.
I have the following RSpec2 test of my XmlRpcController#index action:
it "should get nothing in response to GET request" do
get :index
response.response_code.should == 400 #bad_request
end
And the only line related to this route in routes.rb is:
post 'rpc', :to => "xml_rpc#index"
'rake routes' also shows only this route defined.
As a result when I run this test that action actually DOES get executed! I judge this by putting a simple puts inside it) and also a log contains:
Processing by XmlRpcController#index as HTML
Also if I go to 'localhost:3000/rpc' in browser - it says no route found: just like it should. But tests have other behavior and this puzzles me...
Can anybody hint my why does this happen? I'm only starting learning about RoR :)
Earlier it seemed to me that these 'get/post' methods of TestCase do respect routes.rb...
Am I missing something obvious? :)
It seems that 'get :index' method is ignoring the routes.rb indeed.
The real solution for me was to use be_routable rspec matcher written for this particular purpose:
describe "GET 'contact'" do
it "should be successful" do
{ :get => '/rpc' }.should_not be_routable
end
end
Figured this out thanks to some user from Ruby-Forum. More info here.
Related
I have tests like those:
RSpec.describe RestaursController, :type => :controller do
context "GET /restaurs/:id" do
before do
#rest = FactoryGirl.create :restaur
end
context "resource exists" do
subject { get "restaurs/#{#rest.id}"}
it { expect(subject).to render_template(:show) }
end
context "resource doesn't exists" do
subject { get "restaurs/#{#rest.id + 1}" }
it { expect(subject).to redirect_to(:root) }
end
end
end
When I run those tests RSpec says:
Failure/Error: subject { get "restaurs/#{#rest.id}"}
ActionController::UrlGenerationError:
No route matches {:action=>"restaurs/7", :controller=>"restaurs"}
But I think my routes are OK. Look on rake routes log
Prefix Verb URI Pattern Controller#Action
restaurs GET /restaurs(.:format) restaurs#index
POST /restaurs(.:format) restaurs#create
new_restaur GET /restaurs/new(.:format) restaurs#new
edit_restaur GET /restaurs/:id/edit(.:format) restaurs#edit
restaur GET /restaurs/:id(.:format) restaurs#show
PATCH /restaurs/:id(.:format) restaurs#update
PUT /restaurs/:id(.:format) restaurs#update
DELETE /restaurs/:id(.:format) restaurs#destroy
root GET / restaurs#index
Have you got any ideas? What is the problem? Maybe it is about RSpec syntax or something like that?
That isn't how you get actions in a controller test. The argument to get is the name of the action, not a routable path. Routing isn't involved in testing controllers, and neither is rake routes.
You're giving it the action name "restaurs/7", which obviously isn't the real name of a method on your controller. Instead, you should be using get :show to invoke the actual method "show" on your controller, and then passing a hash of parameters:
get :show, id: #rest.id + 1
Similarly, you would use get :index, not get "/", and you would use get :edit, id: ..., not get "/restaurs/#{...}/edit". It's the actual method your meant to test on your controller, not whether a route actually leads you to the correct method.
As a related aside, your opening context is out of place. You shouldn't be using GET /restaurs:/:id as a context. Routing isn't involved here. Just test the method names.
I'm trying to set up a member route for my 'foo' controller, which is named 'bar' such that it should ONLY respond to post requests. However, I notice that in my RSpec tests it responds to ALL request types (GET, POST, PUT, DELETE).
I was under the impression that defining the route as so, would restrict it such that it would only respond to POST requests:
resources :foo do
member do
post 'bar'
do
end
This seems further confirmed by the fact that when I run rake routes it ONLY shows the 'bar' route like so:
bar_foo POST /foo/:id/bar(.:format) {:action=>"bar", :controller=>"foo"}
However, from RSPEC, the following test fails (meaning the controller processes request successfully) for GET, PUT, & DELETE:
describe FooController do
describe "GET bar" do
it "should not be successful" do
foo = FactoryGirl.create(:foo)
get :bar, :id => foo.id
response.should_not be_ok
end
end
end
Am I missing something small here? How do I restrict my 'bar' member route to only respond to "post" requests.
EDIT:
This appears to be an issue with either RSpec 2.0 or ActionController::TestCase, because I get the following error when I try to hit /foo/:id/bar on my sever with anything but POST:
Routing Error
No route matches [GET] "/foo/1/bar"
From my own experience it appears that RSpec controller tests will not attempt to enforce routing behavior as long as the route exists. RSpec does provide route testing, specifically the be_routable matcher.
Given the following route.rb snippet:
post :foo, to: 'foo#create'
it appears
it "won't work as expected" do
get :foo
expect(response).to be_ok #=> pass
post :foo
expect(response).to be_ok #=> pass
end
will pass. Only when the route is missing entirely from route.rb will it fail.
The following will pass and can be used to perform the test we're interested in:
it "responds to only the proper HTTP verbs" do
expect(get: :foo).not_to be_routable #=> pass - Cannot GET 🙅♂️
expect(post: :foo).to be_routable #=> pass - POST works 🎉
end
I was trying to write an integration test testing, if my controller raises a ActiveRecord::RecordNotFound exeption for deleted articles (which are just marked as deleted):
it "should return 404 for deleted articles" do
#article = Factory :article, :status => "deleted"
expect { get edit_article_path(:id => #article.id) }.to raise_error(ActiveRecord::RecordNotFound)
end
These kind of tests work fine in a controller spec, but inside of the spec/requests I get this error:
expected ActiveRecord::RecordNotFound, got #<ActionController::RoutingError: No route matches {:action=>"edit", :controller=>"articles", :id=>595}>
So it looks up my routes correctly (since it knows the controller etc.) but still raises the error. Why is that?
Thanks, Johannes
If this test is in your spec/controllers directory, then the get method you're calling isn't expecting a path, it's expecting a symbol for the controller action you want to call. So you'd need to change the expect line to something like:
expect { get :edit, :id => #article.id }.to raise_error(ActiveRecord::RecordNotFound)
Take a look at the RSpec Controller Spec documentation for more info.
I can't seem to work around the 'get' method in my rspec controller specs for my scoped routes.
I'm scoping the routes for my 'visitor' controllers so that they are within the 'visitor' module namespace, but are at the root of the routing. So 'mysite.com/foo' goes to the Visitor::FooController.
config/routes.rb
scope :module => 'visitor' do
resources :inquiries
end
spec/controllers/visitor/inquiries_controller_spec.rb
require 'spec_helper'
describe Visitor::InquiriesController do
describe 'GET new' do
it 'should render template visitor/inquiries/new' do
get :new
end
end
end
app/controllers/visitor/inquiries_controller.rb
class Visitor::InquiriesController < Visitor::BaseController
def new
end
end
When I run the spec I get the following error.
No route matches {:controller=>"visitor/inquiries", :action=>"new"}
I tried adding some additional parameters for get (e.g. :url => 'inquiries/new', :controller => 'inquiries') but I can't seem to get around this issue. Hitting 'inquiries/new' with my browser works fine and shows that my routes are working as expected.
I'm new to rspec so there may be some fundamental issue I'm not understanding here. Otherwise I'm looking for a way to push past this issues so I can test these 'visitor' controllers. Any help is appreciated!
The problem was fixed when I restarted my computer the next day. There seemed to be some sort of issue with Spork that was causing the problem. I'm not sure if this question can be removed, but it probably doesn't provide a lot of value to Stackoverflow.
Have a look to your config/routes.rb
uncomment follow line: match ':controller(/:action(/:id(.:format)))'
Now it should works
I;m trying to write a spec that tests a controller that is namespaced, let's call it Admin::FooController. My spec is called admin_foo_controller_spec.rb. In the spec, I'm trying to write a very basic spec to see if it can retrieve an action of a controller.
describe "GET 'index'" do
it "should be successful" do
get 'index'
response.should be_success
end
end
But instead I get an error:
Failure/Error: get 'index'
No route matches {:controller=>"admin/foo"}
For another action, I have basically the same test, and I get that the response is not successful. In the actual webapp, I can access these urls fine. One thing I should mention is that this isn't a RESTful resource (it makes no sense as one) so it's really just a group of related administrative actions, so in my routes.rb it's basically like
namespace :admin do
scope "foo" do
match "action1" => "foo#action1"
match "action2" => "foo#action2"
match "/index" => "foo#settings"
match "settings" => "foo#settings"
end
end
Any ideas what I'm doing wrong? It seems like namespacing is asking for trouble with rails, especially for a novice like me. Thanks!
In your route your have no index action in you Foo controller try to get 'settings'
describe "GET 'index'" do
it "should be successful" do
get 'settings'
response.should be_success
end
end
In a controller spec you need define the action of your controller not the real route. You try the routes in a integration test.