Erik Trautman
Erik Trautman

Reputation: 6029

RSpec controller testing with non-RESTful route redirects

I'm trying to test some basic aspects of a controller that is reached via a nonstandard set of routes. I can't seem to connect to the appropriate controller/action in my LessonsController, which is reached via redirected routes that are meant to appear to lead to the CoursesController.

When I run my specs, I either get a routing error or the response comes back empty and I'm not sure how to parse it for useful nuggets.

# app/controllers/lessons_controller.rb
def index
  ... set some instance vars ...
end

# The CoursesController has index and show methods of its own which aren't used here

# app/config/routes.rb
...
get 'courses/:course_name' => redirect('/courses/%{course_name}/lessons'), :as => "course"
get 'courses/:course_name/lessons' => 'lessons#index', :as => "lessons"
...

# spec/controllers/courses_controller_spec.rb
describe CoursesController do
  it "test some instance vars" do
    get :show, :course_name => Course.first.title_url
    assigns(:some_ivar).should_not be_empty
  end
end

The error:

AbstractController::ActionNotFound: The action 'course' could not be found for CoursesController

RSpec attempt #2:

# spec/controllers/courses_controller_spec.rb
...
  get :course, :course_name => Course.first.title_url
...

The attempt #2 error:

NoMethodError: undefined method `empty?' for nil:NilClass

If I run similar trial-and-error approaches by instead starting with the lessons_controller_spec.rb file (e.g. trying get :index there), I get similar errors. There is no direct route set up for lessons#index, only the redirects.

The response object in my second example is enormous (though the body is empty) so I won't include it unless someone thinks it's useful.

I'm definitely regretting the non-RESTful architecture, but given what it is, is there any idea how to get the controller spec to target the appropriate action inside the LessonsController?

Rails 3.2.12, RSpec 2.14.4, Capybara 2.0.2

Upvotes: 0

Views: 1563

Answers (1)

Billy Chan
Billy Chan

Reputation: 24815

Short answer: No.

Actually there are two types of get available in tests.

One type is for controller testing. This get can only accept argument as "action", say :index, :show etc. So you can only use it within current controller test. (Doc here: http://api.rubyonrails.org/classes/ActionController/TestCase/Behavior.html#method-i-get)

The other type is for integration testing. This get can accept any path as argument. http://api.rubyonrails.org/classes/ActionDispatch/Integration/RequestHelpers.html#method-i-get

The two types have same name get but usage is different.

What in your question is controller testing. So you are use the first one. You can only reach actions inside CoursesController. That's why you meet error.

I strongly recommend you to revise the routes right now. It's not about RESTful or not, but your routes break conversion all the day. What's the point the path is lesson, but controller is course? And why you write a Course controller when there is no route for him?

Upvotes: 3

Related Questions