Skip to content

Testing protected controllers

Tim Liner edited this page Jan 8, 2019 · 14 revisions

Few things you should be aware of when testing controllers protected by doorkeeper.

Valid tokens

in the majority of cases, you'll only need to stub the doorkeeper_token method in your controller:

describe Api::V1::ProfilesController do
  describe 'GET #index' do
    let(:token) { double :acceptable? => true }

    before do
      allow(controller).to receive(:doorkeeper_token) { token }
      # controller.stub(:doorkeeper_token) { token } # => RSpec 2
    end

    it 'responds with 200' do
      get :index, :format => :json
      response.status.should eq(200)
    end
  end
end

Stubbing :acceptable? => true will bypass the doorkeeper filter, since the token is valid. If you prefer to return false then the response status will be 401 unauthorized.

Scopes

If you have an action that requires a specific scope, you will need to stub the token scope:

# controllers/api/v1/profiles_controller.rb
class Api::V1::ProfilesController < ApiController
  before_action :only => [:create] do
    doorkeeper_authorize! :write
  end
  # ...
  
  def create
    respond_with 'api_v1', Profile.create!(params[:profile])
  end
end

# spec/controllers/api/v1/profiles_controller_spec.rb
describe 'POST #create (with scopes)' do
  let(:token) do
    stub :acceptable? => true, :scopes => [:write]
  end

  before do
    allow(controller).to receive(:doorkeeper_token) { token }
    # controller.stub(:doorkeeper_token) { token } # => RSpec 2
  end

  it 'creates the profile' do
    Profile.should_receive(:create!) { stub_model(Profile) }
    post :create, :format => :json
    response.status.should eq(201)
  end
end

Integration

If you need to test the controller fully integrated with your app, you'll need to create the necessary models:

describe Api::V1::CredentialsController do
  describe 'GET #me (integrated)' do
    let!(:application) { Factory :application } # OAuth application
    let!(:user)        { Factory :user }
    let!(:token)       { Factory :access_token, :application => application, :resource_owner_id => user.id }

    it 'responds with 200' do
      get :me, :format => :json, :access_token => token.token
      response.status.should eq(200)
    end

    it 'returns the user as json' do
      get :me, :format => :json, :access_token => token.token
      response.body.should == user.to_json
    end
  end
end

MiniTest::Spec

You can accomplish the same test above with MiniTest (no Rspec) by creating a mock Token and stubbing the acceptable? method:

describe API::V1::ProfilesController do
  describe 'unauthorized' do
    it "should return unauthorized" do
      get :index
      assert_response :unauthorized
    end
  end

  describe 'authorized' do
    let(:user) { users(:one) }
    let(:token) { Minitest::Mock.new }
    setup do
      token.expect(:acceptable?, true, [Doorkeeper::OAuth::Scopes])
    end

    it "should return success" do
      @controller.stub :doorkeeper_token, token do
        get :index
        assert_response :success
      end
    end
  end
end

More examples

For more examples, check the doorkeeper provider app on Github here.

Clone this wiki locally