Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing subdomain constrained routes in Rails 3

Tags:

I'm testing my Rails applications with Test::Unit. A problem I often come across is testing my application's routes for which I haven't found a solution yet.

At the moment, I'm working on an application which uses Basecamp-style subdomains to differentiate accounts.

There are routes which require a subdomain

constraints(SubdomainRoute) do
  get  "/login" => "user_sessions#new", :as => :login
  get  "/logout" => "user_sessions#destroy", :as => :logout
  ...
end

as well as routes which can be accessed only without a subdomain

constraints(NoSubdomainRoute) do
  match "/" => "public#index", :as => :public_root
  match "/signup" => "public#signup", :as => :signup
  ...
end

The class SubdomainRoute is defined as:

class SubdomainRoute
  def self.matches?(request)
    request.subdomain.present? && request.subdomain != "api" && request.subdomain != "www"
  end
end

The class NoSubdomainRoute pretty much does the opposite.

Routing works as expected, but how do I test those using Test::Unit?

In functional tests, I can do something like

assert_routing "/signup", :controller => "public", :action => "signup"

but I cannot provide a subdomain, so in fact that's only testing Rails internals which adds nothing to testing my application. What I want to test in this case is wheter signup_path/signup_url is accessible with or without a subdomain.

In code, something like this

assert_raise(ActionDispatch::RoutingError) { get "http://account.test.host/signup" }
get "http://www.test.host/signup"
assert_response :success

get does not work in this case because Test::Unit treats the whole URL as the controller's action (... :action => "http://account.test.host/signup").

Setting

@request.host = "subdomain.test.host"

only has influences on your inner controller code (e.g. getting current account by extracting subdomain from host) but does not affect routing in this case.

I don't know if the situation is any different in integration tests.

So the two main questions are

  1. Where are routes meant to be testet in general?
  2. How are they tested regarding this special case?

I'm williing to try out different approaches (Capybara and friends) but I don't want to switch my testing framework (already had my RSpec-time) since I'm otherwise very happy with Test::Unit.

Thanks in advance and kind regards!

like image 536
Michael Trojanek Avatar asked Jun 12 '11 18:06

Michael Trojanek


1 Answers

Actually the solution is very simple as assert_routing does support URLs:

assert_routing "http://subdomain.example.com/login",
  { :controller => "user_sessions", :action => "new" }

assert_routing "http://www.example.com/signup",
  { :controller => "public", :action => "signup" }

The ability to provide a URL to assert_routing was added here.

Search strategy:

  • Found assert_routing was defined in actionpack
  • gem install gemedit
  • gem edit actionpack
  • Opened lib/action_dispatch/testing/assertions/routing.rb and found recognized_request_for is what handles the path processing
  • Opened the file via GitHub, and selected 'Blame' to see which commit added that functionality
like image 71
justsee Avatar answered Oct 07 '22 00:10

justsee