3
votes

If you have succeeded in testing post, put, and delete http methods of a Rails API protected with the doorkeeper OAuth2 provider gem, please share and I'll give you the love.

The doorkeeper wiki documentation and sample application show pretty well how to test a get method. I succeeded testing a post with something like what follows using the Capybara test driver with Cucumber. Failed to test any API that routes from put or delete. Failed to post using an rspec test.

@user = create :user
@client = create(:oauth_application)
@token = create(:oauth_token, :application => @client, :resource_owner_id => @user)
json_for_new_entry = {
  date_attr: Time.now.to_date,
  decimal_attr: '1.1',
  string_attr: 'oath2, you make me blue',
  bool_attr: false,
  int_attr: 1
}.to_json
page.driver.header 'Authorization', "Bearer #{@token.token}"
page.driver.post api_entry_path, json_for_new_entry, 
  'CONTENT_TYPE' => 'application/json'

The factories are nothing special:

factory :user, :class => User do |user|
  sequence :email do |n| "user#{n}@example.com" end 
  pwd = "password"
  password  pwd 
end 

factory :oauth_application, :class => Doorkeeper::Application do
  sequence(:name) { |n| "application_name_#{n}" }
  #redirect_uri 'urn:ietf:wg:oauth:2.0:oob'
  redirect_uri 'http://localhost:3000/'
end 

factory :oauth_token, :class => Doorkeeper::AccessToken do
  association :application, :factory => :oauth_application
  association :resource_owner_id, :factory => :user
end 

My environment is a little behind latest versions:

  • rails gems at 3.1.12
  • capybara 2.2.0
  • cucumber 1.3.10
  • devise 2.2.7
  • warden 1.2.3
  • doorkeeper 0.7.4
  • rspec-core 2.14.5
  • rspec-expectations 2.14.3
  • rspec-mocks 2.14.3
  • rspec-rails 2.14.0
3

3 Answers

5
votes

Assuming the intention of your test is to verify the underlying API functionality and not the doorkeeper protection then this is the hack I use:

In my base controller:

module Api
  class BaseController < ActionController::Base

    doorkeeper_for :all unless Rails.env.test?

    private

      def current_user
        if Rails.env.test? && $test_user
           $test_user
        else
           @current_user ||= User.find(doorkeeper_token.resource_owner_id)
        end

      end

  end
end

In my tests I have a login helper:

def login(user)
  $test_user = user
end

def logout
  $test_user = nil
end

I'm not proud of that code but nonetheless I can now get on with my life instead of worrying about how to make rails/doorkeeper/capybara et al work together during testing.

3
votes

You can use the example included in doorkeeper wiki as follow

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

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

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

I used the answer that Moustafa gave, but I wanted to DRY it up so I put the following into spec/support/doorkeeper_oauth.rb:

shared_context "doorkeeper_oauth", oauth: true do
  let(:dummy_token) { double(:acceptable? => true) }
  before do
    if controller.present?
      allow(controller).to receive(:doorkeeper_token) { dummy_token }
    end
end

Then, in your controller spec you change the opening line slightly:

describe Api::V2::WidgetsController, oauth: true do

which pulls in the shared context via the "metadata" method.

edit: I have used this for at least GET and POST, which success in both cases.