This project is archived and is in readonly mode.

#5805 ✓ resolved
ms (at budstikka)

[PATCH] assert_recognizes does not support constraints

Reported by ms (at budstikka) | October 14th, 2010 @ 12:27 PM | in 3.x

In a Rails 3.0.0 app with a HomeController and an #index action:

# routes.rb
class FooConstraint
  def self.matches?(request)
    false  # Ensures routes with this constrains should _never_ match
  end
end

Constraints::Application.routes.draw do
  constraints FooConstraint do
    root :to => 'home#index'
  end
end
# home_controller_test.rb
require 'test_helper'
class HomeControllerTest < ActionController::TestCase
  test "should route to home" do
    assert_recognizes({ :controller => "home", :action => "index" }, "/")
  end
end

This test should fail, as it does when I try to hit / in my web browser ('No route matches "/"').

It seems the code in FooConstrains.matches? is never run.

Comments and changes to this ticket

  • Ryan Bigg

    Ryan Bigg October 14th, 2010 @ 12:33 PM

    • State changed from “new” to “incomplete”
    • Importance changed from “” to “Low”

    Please attach a failing test case to this ticket as per the Contributing to Rails guide that can be found at http://guides.rubyonrails.org.

  • ms (at budstikka)

    ms (at budstikka) October 15th, 2010 @ 11:41 AM

    I haven't been able to make a failing test case, as there is no assert_not_recognizes method. The test case in the attached patch should fail, but it does not. I couln't find any test for the routing assert_* methods themselves. I'd be happy to write more correct tests with a little guidance.

    The main point here is that assert_recognizes does not seem to restrict the routes when the tests are run in the way the constraints do when the code is run in the app and accessed from a web browser.

  • Ryan Bigg

    Ryan Bigg October 19th, 2010 @ 08:32 AM

    • Tag cleared.

    Automatic cleanup of spam.

  • Dim

    Dim November 8th, 2010 @ 01:26 PM

    Here's a working (in this case, failing) patch.

  • Dim

    Dim November 8th, 2010 @ 01:37 PM

    Apologies, please ignore the last post. Here's an even better patch (not sure if it's the best way to validate constraints though).

  • Dim

    Dim November 8th, 2010 @ 02:02 PM

    Ok, this is my final go - I promise!

  • Dim

    Dim November 11th, 2010 @ 03:49 PM

    • Title changed from “assert_recognizes does not support constraints” to “[PATCH] assert_recognizes does not support constraints”
  • Brian Ploetz

    Brian Ploetz December 13th, 2010 @ 05:42 PM

    Actually, I seem to be able to test some constraints, but not others. Section 3.9 of the Routing guide says:

    3.9 Request-Based Constraints

    You can also constrain a route based on any method on the Request object that returns a String.

    I'm able to test a constraint on :format, but not on :protocol. For example:

    # config/routes.rb
    ProtocolBug::Application.routes.draw do
      scope :constraints => { :format => /(json|xml)/ } do
        match '/foos.(:format)' => 'foos#index', :via => :get
      end
    end
    
    # app/controllers/foos_controller.rb
    class FoosController < ApplicationController
      # GET /foos?...
      def index
        render :nothing => true
      end
    end
    
    # test/functional/foos_controller_test.rb
    require 'test_helper'
    class FoosControllerTest < ActionController::TestCase
      test "should route to index" do
        assert_recognizes({ :controller => "foos", :action => "index", :format => "xml" }, "/foos.xml")
      end
    
      test "should fail to route to index" do
        assert_recognizes({ :controller => "foos", :action => "index", :format => "bogus" }, "/foos.bogus")
      end
    end
    

    And when I run the functional tests the test with the bogus format fails (as MS notes above, there's no "assert_not_recognized", so I'm just letting it fail here for you to see that the routing constraint is working correctly).

    [bploetz:~/workspace/protocol_bug]> rake test:functionals

    Started

    E.

    Finished in 0.027135 seconds.

    1) Error: test_should_fail_to_route_to_index(FoosControllerTest): ActionController::RoutingError: No route matches "/foos.bogus" /Users/bploetz/.rvm/gems/ruby-1.9.2-p0@server/gems/actionpack-3.0.3/lib/action_dispatch/routing/route_set.rb:523:in recognize_path'

    /Users/bploetz/.rvm/gems/ruby-1.9.2-p0@server/gems/actionpack-3.0.3/lib/action_dispatch/testing/assertions/routing.rb:211:in recognized_request_for'

    /Users/bploetz/.rvm/gems/ruby-1.9.2-p0@server/gems/actionpack-3.0.3/lib/action_dispatch/testing/assertions/routing.rb:44:in assert_recognizes' test/functional/foos_controller_test.rb:8:inblock in <class:FoosControllerTest>'

    2 tests, 1 assertions, 0 failures, 1 errors, 0 skips

    However, if I add a constraint on :protocol => "https://", it does not honor it in the test.

    # config/routes.rb
    ProtocolBug::Application.routes.draw do
      scope :constraints => { :protocol => "https://" } do
        match '/foos' => 'foos#index', :via => :get
      end
    end
    
    # test/functional/foos_controller_test.rb
    require 'test_helper'
    class FoosControllerTest < ActionController::TestCase
      test "should route to index" do
        assert_recognizes({ :controller => "foos", :action => "index", :protocol => "https://" }, "/foos")
      end
    end
    

    [bploetz:~/workspace/protocol_bug]> rake test:functionals

    Started

    E

    Finished in 0.007458 seconds.

    1) Error: test_should_route_to_index(FoosControllerTest):
    ActionController::RoutingError: No route matches "/foos"
    /Users/bploetz/.rvm/gems/ruby-1.9.2-p0@server/gems/actionpack-3.0.3/lib/action_dispatch/routing/route_set.rb:523:in recognize_path' /Users/bploetz/.rvm/gems/ruby-1.9.2-p0@server/gems/actionpack-3.0.3/lib/action_dispatch/testing/assertions/routing.rb:211:inrecognized_request_for' /Users/bploetz/.rvm/gems/ruby-1.9.2-p0@server/gems/actionpack-3.0.3/lib/action_dispatch/testing/assertions/routing.rb:44:in assert_recognizes' test/functional/foos_controller_test.rb:4:inblock in <class:FoosControllerTest>'

    1 tests, 0 assertions, 0 failures, 1 errors, 0 skips

    And the protocol constraint seems to be correct according to rake routes:

    [bploetz:~/workspace/protocol_bug]> rake routes

    foos GET /foos(.:format) {:protocol=>"https://", :controller=>"foos", :action=>"index"}

    I don't know if this is a different issue than this one, but figured I'd point it out.

  • Steve Schwartz

    Steve Schwartz February 12th, 2011 @ 08:38 PM

    What is the status of this ticket? I am also encountering this problem, in that the routing constraint works fine, but the specs fail when they should be passing. I'd like to help fix it if the patch still needs work.

  • Andrew White

    Andrew White February 13th, 2011 @ 04:40 PM

    In terms of testing a constraint against a protocol you have to pass a full url to assert_recognizes, e.g:

    test "should route to index when using https" do
      assert_recognizes({ :controller => "foos", :action => "index" }, "https://test.host/foos")
    end
    

    For testing that a route fails to recognize then wrap the assert_recognizes in an assert_raises, e.g.:

    test "should not route to index when using http" do
      assert_raises(ActionController::RoutingError) do
        assert_recognizes({ :controller => "foos", :action => "index" }, "http://test.host/foos")
      end
    end
    

    There is an issue with class based constraints as the recognize_path method in ActionDispatch::Routing::RouteSet bypasses the constraints app. However I think I can fix that with a bit of refactoring of ActionDispatch::Routing::Mapper::Constraints so that I can check a constraint without doing a call.

    Be aware though this is a functional test method - if there's a dependency in your class based constraint that needs the full application running then you're best off using an integration test, RSpec request spec or Cucumber feature for checking the constraint is working.

  • Andrew White

    Andrew White February 13th, 2011 @ 04:48 PM

    • State changed from “incomplete” to “open”
    • Milestone set to 3.x
    • Assigned user set to “Andrew White”
  • Repository

    Repository February 13th, 2011 @ 11:41 PM

    • State changed from “open” to “resolved”
  • Repository

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

Tickets have moved to Github

The new ticket tracker is available at https://github.com/rails/rails/issues

Shared Ticket Bins

Attachments

Referenced by

Pages