Search code examples
ruby-on-railsrestrspec2controllers

Request spec works as expected; Controller spec allows :post when it shouldn't


Why is it that this request spec works as it should:

require "spec_helper"

describe "POST on a GET route" do
  it "should not allow this" do
    post "/applicants/new"
    assert_response :missing
  end
end

But in this controller spec, GET, POST, PUT, and DELETE all work the same when they should not:

require 'spec_helper'

describe ApplicantsController do
  it "should not allow this" do
    post :new
    should respond_with :missing # but it responds with 200
  end
end

UPDATE: Added ApplicantsController code and route definition:

class ApplicantsController < InheritedResources::Base    
  respond_to :html
  actions :index, :new, :create

  def new
    if current_user
      redirect_to resume_application_path and return
    end

    @applicant = Applicant.new
    @applicant.applications.build
    @applicant.build_user_detail
    new!
  end    
end

Routes:

resources :applicants

UPDATE: After much researching and digging into the API, I believe this is by design as the Controller specs inherit from ActionController::TestCase while the Request specs inherit from ActionDispatch::IntegrationTest. In the case of Controller specs, the HTTP verbs become merely descriptive.

Could someone confirm that this is by design? Or should I file a bug report?

Thank you!


Solution

  • This seems surprising, but it makes sense when you look at it from the perspective of testing the controller actions in isolation. Normally, controller actions don't need to know about HTTP request methods. Specifying a route without a method illustrates this:

      match 'sample' => 'applicants#index'
    

    Now GET /sample and POST /sample will both route to the index action. Unless you code for it, the controller will not know the difference between a GET and a POST request. Controller specs do not test whether request method/action combinations are routable, since that is the responsibility of the routing engine.

    You can verify which routes work and which don't with routing specs:

    it "recognizes and generates #new" do
      { :get => "/applicants/new" }.should route_to(:controller => "applicants", 
          :action => "new")
    end
    
    it "does not recognize POST /applicants/new" do
      { :post => "/applicants/new" }.should_not be_routable
    end