I am new to testing and I have a question.
This code tests if that route is correct, ok?
test "root should route to home#index" do
assert_routing "/", {controller: "home", action: "index"}
end
How can I test the opposite? I have
resources :sessions, :only=>[:new, :create, :destroy]
In my routes. How would I test that you can't enter sessions#edit?
Could it be that I should not test that?
EDIT: I forgot to mention it, I'm using the default tools.
You could try this, it will fail unless the test assert_generates raises an "UrlGenerationError" => unable to generate the url for sessions#edit
test "route should not exist" do
begin
assert_generates "sessions/edit", controller: :sessions, action: :edit
flunk "Route to should not exist"
rescue ActionController::UrlGenerationError
end
end
If you're using RSpec you could do
it "does not route to sessions/edit" do
expect(:get => "/sessions/edit").not_to be_routable
end
See https://relishapp.com/rspec/rspec-rails/docs/routing-specs/be-routable-matcher for more information on writing routing specs
Related
I have the following route:
resources :success_criteria, except: :new
The following spec fails:
describe SuccessCriteriaController do
describe 'routing' do
it 'routes to #new' do
expect(get('/success_criteria/new')).to_not be_routable
end
end
end
Failure message:
Failure/Error: expect(get('/posts/new')).to_not be_routable
expected {:get=>"/posts/new"} not to be routable, but it routes to {:controller=>"posts", :action=>"show", :id=>"new"}
The controller looks like this:
class SuccessCriteriaController < InheritedResources::Base
load_and_authorize_resource
end
Why does Rails think that posts/new would point to a post with the ID new? That's not right, is it? Does it maybe have to do with InheritedResources?
I believe that if you don't add a constraint to your show route saying that it will only accept digits, everything you put after posts are mapped to be an id to that route.
That means that if your try to access posts/something it would probably throw an ActiveRecord error showing that it couldn't find the Post with id=something.
To add a constraint, add constraints like this:
resources :success_criteria, except: :new, constraints: { id: /\d+/ }
I'm implementing an API on my app, and testing it with Rspec.
my items controller doesn't have the new or edit actions, and the routes.rb has no routes for them:
namespace :api, defaults: {format: 'json'} do
namespace :v1 do
resources :items, except: [:new, :edit]
end
end
My rspec test for them looks like:
it "raises error on #new" do
expect(:get => "/api/v1/items/new").to have_http_status(404)
end
but when I execute the tests on it I get:
Api::V1::ItemsController routing raises error on #new
Failure/Error: expect(:get => "/api/v1/items/new").to have_http_status(404)
expected a response object, but an instance of Hash was received
# ./spec/routing/items_routing_spec.rb:11:in `block (3 levels) in <top (required)>'
I'm not sure how to deal with this case and get the test to pass.
You are probably looking for be_routable matcher:
it { expect(get: '/api/v1/items/new').to_not be_routable }
From docs:
The be_routable matcher is best used with should_not to specify that a
given route should not be routable. It is available in routing specs (in
spec/routing) and controller specs (in spec/controllers).
As a workaround for the issue with new being interpreted as show, you can use alternative matcher called route_to:
it { expect(get: '/api/v1/items/new').to_not route_to('/api/v1/items#new') }
or
it { expect(get: '/api/v1/items/new').to_not route_to(controller: '/api/v1/items', action: 'new') }
You're passing in a hash to expect:
{ :get => "/api/v1/items/new" }
but your assertion is only valid for response objects. You probably want to do something along the lines of
get "/api/v1/items/new"
expect(response).to have_http_status(404)
but if you haven't defined that route yet, this test will probably fail as well.
See this for documentation on the have_http_status matcher.
Routes that work fine in my application fail on any get/put call in rspec testing with 'No route matches'. What am I doing wrong here?
Here's a simple example, from contracts_controller_spec.rb:
it 'should redirect to edit on show' do
get :show
response.should be_success
response.should render_template(:edit)
end
The above fails with the following:
ContractsController api calls should redirect to edit on show
Failure/Error: get :show
ActionController::RoutingError:
No route matches {:controller=>"contracts", :action=>"show"}
the show method in contracts_controller.rb:
def show
Rails.logger.debug("getting contract info....")
get_contract_info
Rails.logger.debug("...got contract info.")
render :action => :edit
end
routes.rb content:
resource :contract, :only=>[:show, :edit, :update], :protocol =>ROUTES_PROTOCOL do
member do
get :print
end
end
rake routes output:
print_contract GET /contract/print(.:format) contracts#print {:protocol=>"http"}
edit_contract GET /contract/edit(.:format) contracts#edit {:protocol=>"http"}
contract GET /contract(.:format) contracts#show {:protocol=>"http"}
PUT /contract(.:format) contracts#update {:protocol=>"http"}
using rspec-rails 2.14.0
This app was recently upgraded from Rails 2.3 to 3.2, which has otherwise been successful
note the non-standard show/edit routes: no id is required, and forcing an id still results in No route matches {:controller=>"contracts", :id=>"1", :action=>"show"}
:protocol is bit weird, try to remove ??
I have a failing test that I'm struggling to understand. I have a controller class Users::QueriesController < ApplicationController at app/controllers/users/queries_controller.rb which has a show action, and a corresponding namespaced route:
namespace :users do
resources :queries
end
I also have a test at test/controllers/users/queries_controller_test.rb:
require 'test_helper'
class Users::QueriesControllerTest < ActionController::TestCase
test "accessing :show action" do
get :show
assert_response :success
end
end
Running this test results in ActionController::UrlGenerationError: No route matches {:controller=>"users/queries", :action=>"show"}.
Running rake routes includes this line: users_query GET /users/queries/:id(.:format) users/queries#show.
What's going wrong here? I'm using Rails 4.0.0.
I think you need to provide an id to the show action
test "accessing :show action" do
get :show, {:id => 1}
assert_response :success
end
That's the right way prior to rails 4.
Please have a try, and let me know the outcome.
This question has probably been asked a dozen times on Stack Overflow (e.g. (1), (2), (3), (4), (5)) but every time the answer seems to be different and none of them have helped me. I'm working on a Rails Engine and I'm finding that Rspec2 gets route errors, but I can reach the routes in the browser. Here's the situation:
In the engine's routes.rb:
resources :mw_interactives, :controller => 'mw_interactives', :constraints => { :id => /\d+/ }, :except => :show
# This is so we can build the InteractiveItem at the same time as the Interactive
resources :pages, :controller => 'interactive_pages', :constraints => { :id => /\d+/ }, :only => [:show] do
resources :mw_interactives, :controller => 'mw_interactives', :constraints => { :id => /\d+/ }, :except => :show
end
Excerpted output of rake routes:
new_mw_interactive GET /mw_interactives/new(.:format) lightweight/mw_interactives#new {:id=>/\d+/}
...
new_page_mw_interactive GET /pages/:page_id/mw_interactives/new(.:format) lightweight/mw_interactives#new {:id=>/\d+/, :page_id=>/\d+/}
And my test, from one of the controller specs (describe Lightweight::MwInteractivesController do):
it 'shows a form for a new interactive' do
get :new
end
...which gets this result:
Failure/Error: get :new
ActionController::RoutingError:
No route matches {:controller=>"lightweight/mw_interactives", :action=>"new"}
...and yet when I go to that route in the browser, it works exactly as intended.
What am I missing here?
ETA: To clarify a point Andreas raises: this is a Rails Engine, so rspec runs in a dummy application which includes the engine's routes in a namespace:
mount Lightweight::Engine => "/lightweight"
...so the routes shown in rake routes are prefaced with /lightweight/. That's why the route shown in the Rspec error doesn't seem to match what's in rake routes. But it does make the debugging an extra step wonkier.
ETA2: Answering Ryan Clark's comment, this is the action I'm testing:
module Lightweight
class MwInteractivesController < ApplicationController
def new
create
end
...and that's it.
I found a workaround for this. Right at the top of the spec, I added this code:
render_views
before do
# work around bug in routing testing
#routes = Lightweight::Engine.routes
end
...and now the spec runs without the routing error. But I don't know why this works, so if someone can post an answer which explains it, I'll accept that.
I think the might be something wrong higher up in you specs
how did the "lightweight" get into this line :controller=>"lightweight/mw_interactives"
the route says
new_mw_interactive GET /mw_interactives/new(.:format)
not
new_mw_interactive GET /lightweight/mw_interactives/new(.:format)
add a file spec/routing/root_routing_spec.rb
require "spec_helper"
describe "routes for Widgets" do
it "routes /widgets to the widgets controller" do
{ :get => "/" }.should route_to(:controller => "home", :action => "index")
end
end
then add a file spec/controllers/home_controller_spec.rb
require 'spec_helper'
describe HomeController do
context "GET index" do
before(:each) do
get :index
end
it {should respond_with :success }
it {should render_template(:index) }
end
end