I am running into a big problem with simple rspec controller tests in a brand new Rails 5 project
Here is my routes.rb
Rails.application.routes.draw do
get '/foo', to: 'application#foo'
get '/bar', to: 'application#foo'
end
and here is my ApplicationController.rb
class ApplicationController < ActionController::Base
def foo
render html: 'foo', status: 200
end
def bar
render html: 'bar', status: 200
end
end
If I boot my server with rails s
I can access both /foo
and /bar
endpoints and see the correct foo
html page.
However, when I run this rspec:
ENV['RAILS_ENV'] = 'test'
require File.expand_path('../../config/environment', __dir__)
require 'rspec/rails'
RSpec.describe ApplicationController, type: :controller do
it 'can get foo' do
get 'foo'
end
it 'can get bar' do
get 'bar'
end
end
The test fails with this output:
1) ApplicationController can get bar
Failure/Error: get 'bar'
ActionController::UrlGenerationError:
No route matches {:action=>"bar", :controller=>"application"}
Why can't rspec find my /bar route when my browser can?
Curiously, if I change that route in my routes.rb file to use the bar action:
get '/bar', to: 'application#bar'
suddenly rspec can find the route and the tests pass...
I need to use arbitrary actions for my routes though, so conforming to this pattern to satisfy rspec is not an option. How can I get rspec to work?
Change your controller spec to a request spec, which is the preferred way of testing controllers in Rails as of RSpec 3.5
You're getting that error due to the fact that in your original config you don't have the #bar
action bound to a URL. So when the spec executes #bar
there is no URL for that action.
A controller spec doesn't work like you might think; there's nothing attempting a request to the path you specify. Instead, it's executing the code you have written in the #bar
action and pulling the URL from the response.
To alleviate this, you can change your spec type:
to :request
instead of :controller
.
Then you can do:
RSpec.describe ApplicationController, type: :request do
it 'can get foo' do
get '/foo'
end
it 'can get bar' do
get '/bar'
end
end