I'm testing a controller in my application and have the following code in my controller:
describe CsdlController do
describe "GET /csdl/inclusive" do
before do
# Create domains that are included
#domain = create(:validated_domain)
end
it "returns a CSDL with valid domains" do
get "/csdl/include.json"
response.body.should =~ /#{#domain.text}/
end
end
end
I also have the following route:
match "/csdl/:type" => 'csdl#show'
However when I run the specs it gives me the following error:
No route matches {:controller=>"csdl", :action=>"/csdl/include.json"}
I have a feeling that I'm using RSpec incorrectly here but not sure how to solve it. Any ideas?
I should add that it seems to work perfectly when I actually call it through my browser.
In controller tests you call actions via name not via route paths:
get :show, type: 'include', format: 'json'
Related
I have a direct route like so:
direct :homepage do
"http://www.rubyonrails.org"
end
And I am trying to test this but I am not sure how. This is what I have:
describe 'redirect' do
it 'directs to homepage', type: :request do
get :homepage
expect(response).to redirect_to('http://www.rubyonrails.org')
end
end
But this fails:
1) redirect directs to homepage
Failure/Error: get :homepage
URI::InvalidURIError:
bad URI(is not URI?): "http://www.example.com:80homepage"
I have the url_helpers included in my Rspec config.
How do I test a direct route?
See: https://guides.rubyonrails.org/routing.html#direct-routes
As soon as I wrote this example, it became clear.
describe 'redirect' do
it 'directs to homepage' do
expect(homepage_url).to eq('http://www.rubyonrails.org')
end
end
I was writing my test in request specs. This works.
I have a controller spec looking like this:
# config_controller_spec.rb
require "spec_helper"
describe Api::V4::ConfigController, type: :controller do
let(:parsed_response) { response.body.to_json }
describe 'GET app_config' do
it "renders successfully" do
get :app_config
expect(response).to be_success
expect(parsed_response).to eq("{key: val}")
end
end
end
When I run it however, I get:
ActionController::UrlGenerationError:
No route matches {:action=>"app_config", :controller=>"api/v4/config"}
I don't under stand why. I googled around and figured that if I add: use_route: :config to the get call like so: get :app_config, use_route: :config, then it works for some reason, though I don't understand why? But when appending that, I get the following deprecation error:
DEPRECATION WARNING: Passing the `use_route` option in functional tests are deprecated. Support for this option in the `process` method (and the related `get`, `head`, `post`, `patch`, `put` and `delete` helpers) will be removed in the next version without replacement.
Functional tests are essentially unit tests for controllers and they should not require knowledge to how the application's routes are configured. Instead, you should explicitly pass the appropiate params to the `process` method.
Previously the engines guide also contained an incorrect example that recommended using this option to test an engine's controllers within the dummy application.
That recommendation was incorrect and has since been corrected.
Instead, you should override the `#routes` variable in the test case with `Foo::Engine.routes`. See the updated engines guide for details.
Here is my controller:
# config_controller.rb
class Api::V4::ConfigController < Api::V4::BaseController
def app_config
render json: Api::V6::Config.app_config, root: false
end
end
And routes:
# routes.rb
MyApp::Application.routes.draw do
constraints subdomain: /\Awww\b/ do
namespace :api, defaults: {format: 'json'} do
get 'app_config' => 'config#app_config'
end
end
end
Use a request spec instead of a controller spec:
describe "Api V4 Configuration", type: :request do
let(:json) { JSON.parse(response.body) }
subject { response }
describe 'GET app_config' do
before { get "/api/v4/app_config" }
it { should be_successful }
it "has the correct contents" do
expect(json).to include(foo: "bar")
end
end
end
One of biggest changes with Rails 5 was the depreciation of ActionController::TestCase (which RSpec controller specs wrap) in favor of integration tests. Thus using request specs is a more future proof solution - using less abstraction also means that your specs will cover routing properly as well.
Also you don't seem to be nesting your routes properly:
# routes.rb
MyApp::Application.routes.draw do
constraints subdomain: /\Awww\b/ do
namespace :api, defaults: {format: 'json'} do
namespace :v4 do
get 'app_config' => 'config#app_config'
end
end
end
end
See:
Replacing RSpec controller specs
I've got routes setup so that they work as expected in my controllers; I can use both room_path and rooms_path as expected.
However when I try to use the same routes in a controller spec for some reason then I get an error:
ActionController::UrlGenerationError:
No route matches {:action=>"/1", :controller=>"rooms"}
My routes.rb file:
root "rooms#index"
resources :rooms, :path => '/', only: [:index, :create, :show] do
resources :connections, only: [:create,:destroy]
end
And if I rake routes:
room_connections POST /:room_id/connections(.:format) connections#create
room_connection DELETE /:room_id/connections/:id(.:format) connections#destroy
rooms GET / rooms#index
POST / rooms#create
room GET /:id(.:format) rooms#show
However my test fails:
describe "GET room_path(room)" do
it "renders show" do
#room = Room.create
get room_path(#room)
expect(response.status).to eq(200)
expect(response).to render_template(:show)
end
end
While my controllers can use the same route helpers without issue:
class RoomsController < ApplicationController
def index
end
def create
#room = Room.create
redirect_to room_path(#room)
end
def show
#room = Room.find(params[:id])
end
end
I'm not sure why in my tests it seems to go looking for a "/1" action rather than rooms#show like I would expect.
Update
So continuing to play this I've been able to get the test green by changing to the following:
describe "GET room_path(room)" do
it "renders show" do
#room = Room.create
get :show, params: { id: #room.id }
expect(response.status).to eq(200)
expect(response).to render_template(:show)
end
end
I would still love to understand why my helpers aren't working though. Is this to be expected? Manually writing the Parameters hash is kind of a PITA.
I don't know what version of Rails and RSpec you're on. This works for me on Rails 4.2 and Rspec 3.4.4:
describe "my neat test description", type: :routing do
it "can use path helper" do
puts whatever_path
end
end
The type: :routing pulls in the path and url helpers.
I believe the reason you don't have that by default is that rspec is replicating a lot of the environment for the different types of tests. For controller tests, it's pulling in the various path and url helpers because generally speaking they're used there often enough to be worth pulling in. In model tests, for example, they aren't used there often so they aren't pulled in by default.
These helpers live on the app object.
I'm trying to write a test for SessionsController and I wrote the following:
I'm using Spec 3.3
RSpec.describe SessionsController, type: :controller do
describe SessionsController do
describe "POST create" do
it "sign in should have a valid route" do
post('/api/signin').should route_to('api/sessions#create')
end
end
end
end
This app is to work mostly as an API, so for now, there's no need for views.
In my routes I have the following:
match '/api/signin', to: 'api/sessions#create',
Yet the test is not passing.
Any suggestions?
EDIT: The errors:
rspec ./spec/controllers/sessions_controller_spec.rb:27 # SessionsController SessionsController POST create sign in should have a valid route
rspec ./spec/controllers/sessions_controller_spec.rb:31 # SessionsController SessionsController POST create creates a new session
EDIT2: Added full test code
You must specify type: :routing and use assert_routing which has the benefice to test your route in 2 ways (route generation and route matching)
I make my answer general, so other people can take info from it, please adapt to your case
describe MyController, type: :routing do
it 'routing' do
# This is optional, but also a good reminder to tell me when I add a route
# and forgot to update my specs.
# Please see bellow for the helper definition
expect(number_of_routes_for('my_controller')).to eq(8)
# Then test for the routes, one by one
assert_routing({method: :get, path: '/my_controller'}, {controller: 'my_controller', action: 'index'})
assert_routing({method: :get, path: '/my_controller/1'}, {controller: 'my_controller', action: 'show', id: '1'})
# ... And so on, for each route
end
end
Note: If get errors with assert_routing (I guess it will be the case with match, but I can't remember) then have a look at assert_generates and assert_recognizes
And the number_of_routes_for helper
def number_of_routes_for(controller)
Rails.application.routes.routes.to_a.select{ |r| r.defaults[:controller] == controller }.count
end
i am working in Rspec of ROR..
I am trying to test my controllers using RSpec.i am having a Users controller with functions like new , tags, etc..
i created a file under spec/users_controller_spec.rb
and added the test cases as.
require 'spec_helper'
describe UsersController do
integrate_views
it "should use UsersController" do
controller.should be_an_instance_of(UsersController)
end
describe "GET 'new'" do
it "should be successful" do
get 'new'
response.should be_success
end
it "should have the title" do
get 'new'
response.should have_tag("title", "First app" )
end
end
end
which gets pass.
But when i add a test case for tags ..
like
describe "GET 'tags'" do
it "should be successful" do
get 'tags'
response.should be_success
end
end
this results in an error as
F...
1)
'UsersController GET 'tags' should be successful' FAILED
expected success? to return true, got false
why it is coming like this ?? i am very new to ROR and cant find the reason of why i am getting this error..
How to make this pass .
Also i tried the Url
http://localhost:3000/users/tags which is running for me .. But on testing using $spec spec/ i am getting the error ..
Your test may be failing for any number of reasons. Does the route require an ID in the parameter hash? Is the controller action redirecting? Is the controller raising an error?
You'll need to look at the controller code /and/or routes.rb to discover the cause of the failure. Take note of before filters in the controller, which may not allow the action to be reachable at all.
You need to add custom routes that are not within the default 7 routes. Assuming you have resources :users within your routes you will need to modify it. I'm also assuming that your tags route is unique to individual users.
resources :users do
member do
# creates /users/:user_id/tags
get :tags
end
end
And in your RSpec test you would call it like
describe '#tags' do
user = create :user
get :tags, user_id: user.id
end
If the route is not to be unique per user the other option is a collection route, something like:
resources :users do
collection do
# creates /users/tags
get :tags
end
end