Reputation: 809
class ApplicationController < ActionController::Base
# ...
end
class ApiApplicationController < ActionController::API
# ...
end
class IotApplicationController < ApiApplicationController
# ...
end
class Iot::HardwaresController < IotApplicationController
def index
# ...
end
end
Rails.application.routes.draw do
scope module: :iot do
resources :hardwares, only: [ :index ], constraints: { format: :json }
end
...
end
$ rake routes
Prefix Verb URI Pattern Controller#Action
...
hardwares GET /hardwares(.:format) iot/hardwares#index {:format=>:json}
require 'rails_helper'
RSpec.describe Iot::HardwaresController, type: :controller do
describe "GET #index" do
context "with invalid params" do
it "renders a JSON response with errors" do
get :index, params: { "test": 1 }
expect(response).to have_http_status(:bad_request)
end
end
end
end
$ rspec .
Iot::HardwaresController
GET #index
with invalid params
renders a JSON response with errors (FAILED - 1)
Failures:
1) Iot::HardwaresController GET #index with invalid params renders a JSON response with errors
Failure/Error: get :index, params: {"test": 1}
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"iot/hardwares", :test=>1}
# ./spec/controllers/iot/hardwares_controller.rb:17:in `block (4 levels) in <top (required)>'
Finished in 0.01547 seconds (files took 6.79 seconds to load)
1 example, 1 failure
How to write route in rspec correctly?
Upvotes: 1
Views: 1909
Reputation: 191
Edit: After looking at provided routes I think that main problem might be that you namespaced controller but not resource in routes, if that is the problem you will find solution below with some other suggestions.
Make sure you have a routing properly set in routes.rb
in your case you should have something like:
namespace :iot do
resources :hardwares
end
Then you will need to specify path
instead of method name in your get
request inside RSpec example:
get "/iot/hardwares", params { "test": 1 }
Let's say we have a BooksController
with index
action. In our routes.rb
file there is resources: :books
.
Provided that routes are setup correctly your example looking like this should work:
require 'rails_helper'
RSpec.describe Iot::HardwaresController, type: :controller do
describe "GET #index" do
context "with invalid params" do
it "renders a JSON response with errors" do
get "/iot/hardwares", params: { "test": 1 }
expect(response).to have_http_status(:bad_request)
end
end
end
end
To make it even better you could extract path to let variable as you will be probably using it for more examples. Like this: require 'rails_helper'
RSpec.describe Iot::HardwaresController, type: :controller do
describe "GET #index" do
let(:path) { "/iot/hardwares" }
context "with invalid params" do
it "renders a JSON response with errors" do
get path, params: { "test": 1 }
expect(response).to have_http_status(:bad_request)
end
end
end
end
Also you could consider changing your specs to be request specs instead of controller specs. In the release notes of RSpec you can find:
For new Rails apps: we don't recommend adding the rails-controller-testing gem to your application. The official recommendation of the Rails team and the RSpec core team is to write request specs instead. Request specs allow you to focus on a single controller action, but unlike controller tests involve the router, the middleware stack, and both rack requests and responses. This adds realism to the test that you are writing, and helps avoid many of the issues that are common in controller specs. In Rails 5, request specs are significantly faster than either request or controller specs were in rails 4, thanks to the work by Eileen Uchitelle1 of the Rails Committer Team.
You can read more on this here: http://rspec.info/blog/2016/07/rspec-3-5-has-been-released/
Upvotes: 1