0
votes

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?

2

2 Answers

1
votes

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
0
votes

Have you tried this path(get '/bar', to: 'application#foo') are accessible in your browser?