How do I unit test a controller method that is called via a custom route?
The relevant route is:
/auth/:provider/callback(.:format) {:controller=>"sessions", :action=>"create"}
On the spec for the SessionsController I can't just use get :create since that route doesn't exist. If I also use get /auth/facebook/callback/ it'll tell me that No route matches {:controller=>"sessions", :action=>"/auth/facebook/callback"}.
It also seems like I can't just use controller.create since #create accesses some keys from the request hash and it also redirects to another path, even if I set request.env['something'] in the spec file.
A functional test should test the function of each action
(given a set of parameters)
Crucially, you should keep your functional tests decoupled from your routes.
(else what's the point in the routing abstraction anyway)
In test::unit a functional test looks something like this
test "#{action_name} - does something" do
#{http_verb} :#{action_name}, :params => {:their => "values"}
assert_response :#{expected_response}
end
Note, we don't mention routing anywhere.
So a real example for your create
test "create - creates a session" do
get :create, :provider => "your provider"
assert_response :success
end
Rails will choke if it can't match a route to this request.
If this doesn't work I suggest you check two things
"get" is the correct http verb
there are no other required parameters in your route (I can see :provider is one)
If I'm doing anything wacky with routing,
I normally add a separate test.
test "create - routing" do
assert_recognizes({
:controller => "sessions",
:action => "create",
:provider => "yourProvider"
}, "/auth/yourProvider/callback")
end
As long as this matches up with your action test
all should be well.
Related
I have a custom route for devise:
devise_scope :user do
get '/login' => "devise/sessions#new", :as => :new_user_session
get '/logout' => 'devise/sessions#destroy',
...
I want to make sure that when the request /login is called, that it gets correctly routed to devise and that the response is successful.
How do you test for custom routing and a successful request?
If you're using the built-in TestUnit to test, check out the Rails Guide on testing controllers.
If you're using Rspec, check out the Rspec Github Page for information on testing controllers.
It depends on you testing suite, personally I use RSpec + Capybara for my Rails projects.
If you don't have a testing suite yet I highly recommend this guide.
http://everydayrails.com/2012/03/12/testing-series-intro.html
In this particular instance, I'd say you want two tests. One for the routing and one for a successful request. Using rspec, this will look something like:
#spec/routing/devise_routing_spec.rb
require 'spec_helper'
describe "Devise Routes" do
it "should route the login correctly" do
{:get => "login"}.should route_to(controller: "devise/sessions", action: "new")
end
end
and
#spec/controllers/devise/session_controller_spec.rb
require 'spec_helper'
describe Devise::Sessions do
it "should be successful with a login request" do
get "new"
response.should be_success
end
end
I'm writing a set of tests for routes for our api controller. I'm curious whether there is a faster way. We have a bunch of urls like this:
routes.rb
post '/api/unfollow' => 'api#unfollow', :as => :unfollow
/spec/routing/unfollow_routes_spec.rb
require "spec_helper"
describe "route to api unfollow" do
it "should route correctly" do
{:post => unfollow_path }.should route_to(:controller => "api", :action => "unfollow")
end
end
Does this look like a reasonable strategy? Is it advised to put only a single route per file? I'd rather put all the routes for a single controller in a single file. On the route definition with named routes, is there a way to leave it blank and rails can infer that it is unfollow_path ?
thx in advance
I'm trying to test my namespaced controller and not having much luck. I have the following route setup:
namespace :api do
get 'organization/:id/questions/:number', controller: 'questions', action: 'index', as: 'organization_questions'
end
which produces the following route:
api_organization_questions GET /api/organization/:id/questions/:number(.:format) {:controller=>"api/questions", :action=>"index"}
that route works, and I'm able to successfully make a request to it with the following url: http://localhost:3000/api/organization/1/questions/1234567890
However when I try to make a get request to it in my unit test I get the following error:
No route matches {:controller=>"api/questions", :action=>"/api/organization/1/questions/1234567890"}
my get request looks like this:
get api_organization_questions_path(#organization.id, '1234567890')
Not sure what I'm doing wrong!?
What are you using for testing ? RSpec? The first parameter for the get method is the action. The code below should make the request you want:
describe Api::QuestionsController do
it "should do something" do
get :index, :id => #organization.id, :number => '1234567890'
end
end
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;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.