3
votes

I'm pretty new to Rails. We are using Devise to handle user authentication and RSpec for testing the application (Rails 4).

I have an Admin devise model which has access to some authenticated routes. Here's an excerpt from routes.rb:

devise_for :admins

authenticate :admin do
  get 'admin', to: 'admin#index'
end

It (obviously) works flawlessly: if I visit /admin, I get redirected to /admins/sign_in and, once I sign in (or if I already am in session) I have direct access to /admin.

Now, as I understand, routes should be tested inside spec/routes/<controller_name>_routes_spec.rb. I like the idea of testing routes (and that the right controller handle each route with the right action etc.) on their own.

We're facing the issue of testing routes when the said routes are authenticated. Including

config.include Devise::TestHelpers[, type: :controller]

inside spec/spec_helper.rb still doesn't make the sign_in (or sign_[out|up]) methods available inside routes specs.

What are we supposed to do? How should we test authenticated routes? It just feels wrong to me that non authenticated routes are tested as spec/routes, while authenticated routes should be tested inside integration tests, manually filling sign-in forms with Capybara-like stuff.

(note: I read this, but it didn't help at all)

1
That's the downside of authenticated routes I guess. - Bart
Which means we don't test them? We test them inside integration tests? We try to hack our way into using sign_in outside of controllers? - whatyouhide
Wouldn't they just act as regular routes in the tests? I didn't ever feel like testing device's methods themselves though. - Bart
@Bartosz they don't. They behave differently based on the Admin (in my specific case) being/not beign signed in, and I'd like to test exactly that. Any suggestions? - whatyouhide

1 Answers

0
votes

You can include the devise helper in your routes controller by removing the conditional in your spec_helper config. Mine looks like this:

...

RSpec.configure do |config|
  config.include Devise::TestHelpers

...

end

def sign_in_user( user=nil )
  @user = FactoryGirl.build(:user)
  @user.skip_confirmation!
  @user.save!
  sign_in @user
end

Or if you want to insure that you're not abusing devise in weird place you can include it in just the controller and routing tests.

RSpec.configure do |config|
  config.include Devise::TestHelpers, type: :controller
  config.include Devise::TestHelpers, type: :routing

...

end

This is all assuming you're typing your spec files. One of my routing files looks like this:

require "spec_helper"

RSpec.describe WidgetsController, :type => :controller do
  describe "routing" do

    before(:each) do 
      sign_in_user
    end

    it "routes to #index" do
      expect(:get => "/widgets").to route_to("widgets#index")
    end

    it "routes to #new" do
      expect(:get => "/widgets/new").to route_to("widgets#new")
    end

    it "routes to #show" do
      expect(:get => "/widgets/1").to route_to("widgets#show", :id => "1")
    end

    it "routes to #edit" do
      expect(:get => "/widgets/1/edit").to route_to("widgets#edit", :id => "1")
    end

    it "routes to #create" do
      expect(:post => "/widgets").to route_to("widgets#create")
    end

    it "routes to #update" do
      expect(:put => "/widgets/1").to route_to("widgets#update", :id => "1")
    end

    it "routes to #destroy" do
      expect(:delete => "/widgets/1").to route_to("widgets#destroy", :id => "1")
    end
  end
end