Search code examples
minitestshoulda

Shoulda route matcher with subdomains


I am using shoulda matchers to test critical routes on Rails 4.2.1 with Ruby 2.2.0 on a new application. I just moved my API namespace to a subdomain, and I can't figure out how to get the shoulda routes matcher (or any other concise routes test) to work.

Here is some example code:

config/routes.rb (using versionist for versioning, but that shouldn't be relevant)

  namespace :api, path: '', constraints: { subdomain: 'api'} do
    api_version(module: 'V1',
                path: {value: 'v1'},
                defaults: {format: 'json'}, default: true) do
      resources :bills,         only: :index
    end
  end

app/controllers/api/v1/bills_controller.rb

module API
  module V1
    class Bill < APIVersionsController
      # GET api.example.com/v1/bills.json
      def index
        @bills = Bill.all.limit(10)
        render json: @bills
      end
    end
  end
end

test/controllers/api/v1/routing_test.rb

module API
  module V1
    class RoutingTest < ActionController::TestCase
      setup { @request.host = 'http://api.example.com' }
      should route('/v1/bills')
             .to(controller: :bill, action: :index, format: :json)
    end
  end
end 

Before I was using a subdomain, should route('/api/v1/bills').to(action: :index, format: :json) in my BillsControllerTest worked just fine.

Now, when I run rake test, I get Minitest::Assertion: No route matches "/v1/bills".

  • I've tried putting this in the BillControllerTest (no change);
  • I've tried an integration test (route matcher doesn't work);
  • I've tried setting the host with setup { host! 'api.example.com' } and setup { @request.host = 'api.example.com' }
  • I've tried putting the full URL in the get request ( { get 'http://api.example.com/v1/bills' } );
  • and I've tried putting subdomain: 'api' and constraints: subdomain: 'api' anywhere that might make sense.

What is a concise way to do route testing with subdomains/what is the current best practice? Is there a way to get the shoulda route matcher to work with them?


Solution

  • This ended up being a simple fix. I just needed to add a subdomain constraint in the #to method and ensure the #route method had the full url:

    module API
      module V1
        class RoutingTest < ActionController::TestCase
          should route(:get, 'http://api.example.com/v1')
                   .to('api/v1/data#index', 
                       subdomain: 'api', 
                       format: :json)
          ...
    

    Or, if you are in data_controller_test.rb,

    module API
      module V1
        class DataControllerTest < ActionController::TestCase
          should route(:get, 'http://api.example.com/v1')
                   .to(action: :index, 
                       subdomain: 'api', 
                       format: :json)
          ...