Reputation: 6313
I have a constraint in my routes to only allow ajax requests to be routed. How do I test this with rspec? Specifically what test would show that /schedules is routable, but only from AJAX.
routes.rb
class OnlyAjaxRequest
def matches?(request)
request.xhr?
end
end
resources :schedules, :constraints => OnlyAjaxRequest.new
I currently have the following passing part of the test to show that a normal GET request is not routable, but I want to know how to test that an AJAX GET request is routable.
spec/routing/schedules_routing_spec.rb
require 'spec_helper'
describe "GET /schedules" do
it "returns http failure to non AJAX request" do
{:get => '/schedules'}.should_not be_routable
end
end
Upvotes: 2
Views: 2959
Reputation: 286
I tested my spec example by stubbing the method xhr?
of the class ActionDispatch::Request
.
require 'rails_helper'
describe "GET /schedules" do
it "routes to /schedules when request is an ajax request" do
allow_any_instance_of(ActionDispatch::Request).to receive(:xhr?).and_return(true)
expect(get: '/schedules').to be_routable
end
end
Upvotes: 1
Reputation: 6724
I wrote the answer to the question linked in Steve Rowley's answer, and in my opinion the same advice applies here. Ask yourself -- what am I trying to test? Are you testing whether Rails' routing DSL will apply the routing constraint as advertised? That's not something you need a test for in your application, in my opinion. So you want to test whether the routing constraint will apply to xhr requests but not to non-xhr requests.
For that, you just need a unit test for the routing constraint object itself. Something like
describe OnlyAjaxRequest
describe "#matches?" do
subject { OnlyAjaxRequest.new.matches?(req) }
context "xhr request" do
let(:req) { double('request', :xhr? => true) }
it { should be_true }
end
context "non-xhr request" do
let(:req) { double('request', :xhr? => false) }
it { should be_false }
end
end
end
Honestly, in this particular case it's hard for me to see much reason to bother with even these tests, but that's how I'd test what you're trying to test.
Upvotes: 1
Reputation: 5644
To test your '/schedules' AJAX route, try the code below:
require 'spec_helper'
describe "GET /schedules" do
it "returns http success for an AJAX request" do
{:get => '/schedules', format: :xhr}.should be_routable
end
end
It turns out the code above won't work as SteveRowley points out in one of the answers. The second argument is ignored so the above code just tests the regular get '/schedules' route.
Since rspec-rails doesn't provide any helpers for testing AJAX routes in a route spec, you're going to have to test it indirectly in a controller spec like:
xhr :get, :index
expect(response).to be_ok
Since you have to test if the AJAX route is working through your controller spec, it'd help to leave a comment in your routing spec stating that AJAX requests are expected to be routable and that this is tested via the controller spec. Having a routing spec that checks that non-AJAX requests for '/schedules' should not be routable doesn't make sense unless paired with another assertion that checks that AJAX requests for '/schedules' should be routable. Having no way to test that through the routing spec, the next best option is to leave a comment and test that indirectly via a controller spec.
Upvotes: 2
Reputation: 1578
Would
xhr :get, :index
expect(response).to be_ok
in the schedules controller spec work for your purposes? Understand this isn't directly testing if that route is "routable."
Looking at the route matcher code in rspec-rails, it didn't appear that those matchers support extra options. Later I found this answer:
How to test route constraints with rspec
That explains this better than I could. Their recommendation was to just test your constraint class and trust that Rails routing works as expected. There are a few tests for block/object constraints in the Rails source:
https://github.com/rails/rails/blob/master/actionpack/test/dispatch/routing_assertions_test.rb
Since your main concern is to limit the type of request you will accept and your other test validates that those limits work as expected, to be honest I would stick with just the controller spec approach to test the happy path. If you had more complex constraints that matched different routes based on the request object's properties, I'd probably test the constraint class itself as the other answer suggests.
Upvotes: 2