Search code examples
ruby-on-railsrspecrspec-rails

How to test a customized not_found route in rails


I have the following situation:

EDITED

In my routes.rb

namespace :api, defaults: { format: :json } do
    namespace :v1 do
        # the definitions of other routes of my api
        # ...
        match '*path', to: 'unmatch_route#not_found', via: :all
    end
end

EDITED

My controller:

class Api::V1::UnmatchRouteController < Api::V1::ApiController
  def not_found
    respond_to do |format|
      format.json { render json: { error: 'not_found' }, status: 404 }
    end
  end
end

My test is as shown:

require 'rails_helper'

RSpec.describe Api::V1::UnmatchRouteController, type: :controller do
  describe 'get response from unmatched route' do
    before do
      get :not_found, format: :json
    end

    it 'responds with 404 status' do
      expect(response.status).to eq(404)
    end

    it 'check the json response' do
      expect(response.body).to eq('{"error": "not_found"}')
    end
  end
end

It seems right to me, however I got the same error for both it statments:

1) Api::V1::UnmatchRouteController get response from unmatched route responds with 404 status
 Failure/Error: get :not_found, format: :json

 ActionController::UrlGenerationError:
   No route matches {:action=>"not_found", :controller=>"api/v1/unmatch_route", :format=>:json}
 # /home/hohenheim/.rvm/gems/ruby-2.3.1@dpms-kaefer/gems/gon-6.1.0/lib/gon/spec_helpers.rb:15:in `process'
 # ./spec/controllers/api/v1/unmatch_route_controller_spec.rb:14:in `block (3 levels) in <top (required)>'

EDITED

The purpose with this route is be trigged when there's no other route possible in my api, with a custom json 404 response. This route and controller is working as expected right now, when we access routes like: /api/v1/foo or /api/v1/bar

How can I write the tests properly?

Additional info: Rails 4.2.6, Rspec 3.5.4


Solution

  • If you try to write routes spec, it won't work too and it will return something strange.

     Failure/Error:
           expect(get("/unmatch")).
             to route_to("unmatch_route#not_found")
       The recognized options <{"controller"=>"unmatch_route", "action"=>"not_found", "path"=>"unmatch"}> did not match <{"controller"=>"unmatch_route", "action"=>"not_found"}>, difference:.
       --- expected
       +++ actual
       @@ -1 +1 @@
       -{"controller"=>"unmatch_route", "action"=>"not_found"}
       +{"controller"=>"unmatch_route", "action"=>"not_found", "path"=>"unmatch"}
    

    Beside action not_found, it returned path => unmatch that maybe why controller spec didn't work as expected. Thus instead of controller test you can use request test as below.

    require 'rails_helper'
    
    RSpec.describe "get response from unmatched route", :type => :request do
      before do
        get '/not_found', format: :json
      end
    
      it 'responds with 404 status' do
        expect(response.status).to eq(404)
      end
    
      it 'check the json response' do
        expect(response.body).to eq('{"error": "not_found"}')
      end
    end