Question

I have Rails app with Grape API.

The interface is done with Backbone and Grape API provides it all data.

All it returns is user-specific stuff, so i need reference to currently logged in user.

Simplified version looks like this:

API initialization:

module MyAPI
  class API < Grape::API
    format :json

    helpers MyAPI::APIHelpers

    mount MyAPI::Endpoints::Notes
  end
end

Endpoint:

module MyAPI
  module Endpoints
    class Notes < Grape::API
      before do
        authenticate!
      end

      # (...) Api methods
    end
  end
end

API helper:

module MyAPI::APIHelpers
  # @return [User]
  def current_user
    env['warden'].user
  end

  def authenticate!
    unless current_user
      error!('401 Unauthorized', 401)
    end
  end
end

So, as you can see, i get the current user from Warden and it works fine. But the problem is with testing.

describe MyAPI::Endpoints::Notes do
  describe 'GET /notes' do
    it 'it renders all notes when no keyword is given' do
      Note.expects(:all).returns(@notes)
      get '/notes'
      it_presents(@notes)
    end
  end
end

How can I stub helpers's method *current_user* with some specific user?

I tried:

  • setting env/request, but it doesn't exist before calling get method.
  • stubbing MyAPI::APIHelpers#current_user method with Mocha
  • stubbing MyAPI::Endpoints::Notes.any_instance.stub with Mocha

Edit: At the moment, it's stubbed this way:

spec:

  # (...)
  before :all do
    load 'patches/api_helpers'
    @user = STUBBED_USER
  end
  # (...)

spec/patches/api_helpers.rb:

STUBBED_USER = FactoryGirl.create(:user)
module MyAPI::APIHelpers
  def current_user
    STUBBED_USER
  end
end

But it's definitely not the answer :).

Was it helpful?

Solution

comments mentioned in this issue should help you, It's how even Grape tests it's helpers,

https://github.com/intridea/grape/blob/master/spec/grape/endpoint_spec.rb#L475 (If the code is not there on the same line due to changes, just do a ctrl+f & look for helpers)

Here's some code from the same file

it 'resets all instance variables (except block) between calls' do
  subject.helpers do
    def memoized
      @memoized ||= params[:howdy]
    end
  end

  subject.get('/hello') do
    memoized
  end

  get '/hello?howdy=hey'
  last_response.body.should == 'hey'
  get '/hello?howdy=yo'
  last_response.body.should == 'yo'
end

OTHER TIPS

Option 1

The recommended way is to use Grape::Endpoint.before_each:

context 'when user is logged in' do
  before do
    Grape::Endpoint.before_each do |endpoint|
      allow(endpoint).to receive(:current_user).and_return(user)
    end
  end

  after { Grape::Endpoint.before_each nil }
end

But this is quite verbose. It can live in a shared context, but you can't pass user as a parameter explicitly so you'd end up with:

let(:user) { create(:user) }
# ...
include_context 'signed in user'

Option 2

My preferred way is a more RSpec-like stubbing:

# helper
module AuthHelper
  def current_user
    # ...
  end
end

# api
module API
  module V1
    class Auth < Grape::API
      helpers AuthHelper
    end
  end
end

# spec
before do
  allow_any_instance_of(AuthHelper).to receive(:current_user).and_return(user)
end

Option 3

You can also define helpers:

API::V1::User.helpers do
  def current_user
    user
  end
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top