-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds Grape::Endpoint.setup for pre-run endpoint config. #397
Conversation
Well, it's a workaround. But don't we really want people to be able to write something like this: MyAPI.helpers.stub(:current_user).and_return ... The fact is, you can just re-define a helper in a spec without a stub. MyAPI.helpers do
def current_user
# return a stub
end
end The question is, how do we turn this into the syntax above? |
The problem is that Grape is context-sensitive. Where you declare your helpers matters (helpers declared before one endpoint but after another are available on the latter but not the former). So we can't simply say This approach allows you to say "I don't care about context, I want this to happen when the endpoint runs" which, in my opinion, is the effect we want to achieve but may not be the most elegant way to achieve that effect. |
I suggest a different approach in the Endpoint class put this: def method_missing(method_name, *args, &block)
if helper.respond_to?(method_name)
helper.set_context(request, env, whatever)
helper.send(method_name, *args, &block)
else
super
end
end and thus, have a helpers object which can be easily stubbed out, by accessing MyApiClass.helpers (or helpers_object, as helpers is taken) it makes it slightly slower as it takes a little stroll down the module tree to get to method_missing, but the endpoint really only has 5 ancestors, so it's not that big an overhead to use it. |
That would be fine. Can you please try a PR? |
sure. will try to get a PR ready later today. |
I think the early setup mechanism here might work better towards the same goal, but I couldn't get the syntax to work. Check out https://github.com/dblock/grape/blob/spec-helpers/spec/grape/api_spec.rb#L913 for the two specs I would like to be able to pass. |
@mbleigh I want to revive this. Check out https://github.com/dblock/grape/blob/spec-helpers/spec/grape/api_spec.rb#L913 - does the setup method cover stubbing in those scenarios? |
@dblock sorry for being a month late to the party, not sure I follow. Are you asking if my setup method can give you functionality something like you have in your fork? I believe so. it "allows stubbing helpers" do
puts "declare"
subject.helpers do
def foo
'foo'
end
end
subject.get "/" do
foo
end
get "/"
last_response.body.should eql "foo"
Grape::Endpoint.setup{|ep| ep.stub!(:foo).and_return("bar")}
get "/"
last_response.body.should eql "bar"
Grape::Endpoint.setup nil
end |
@mbleigh I meant I'd like to see the tests in https://github.com/dblock/grape/blob/spec-helpers/spec/grape/api_spec.rb#L913 merged onto this PR and for them to pass. |
@dblock looking at your tests, I don't think this can ever or even necessarily should ever work. It implies a kind of global scope that simply doesn't exist in Grape. Helpers are mixed into the endpoint, and endpoints are dynamically generated based on the entire settings stack context that exists when they are defined. The way I see it, the only potential workaround for this that comes close to what you're describing would be to provide an easy means to reach in and grab an endpoint. Something like: endpoint = subject.at(:get, "/some/path/here")
endpoint.stub!(:dup).and_return(:endpoint)
endpoint.stub!(:helper_method).and_return("something else") Which, coincidentally, I've been thinking about as a potentially very useful thing anyway. Other than that, I think the only serviceable option is something like this |
I am OK with merging this. It needs a section in README and an entry in CHANGELOG. After reading this I wondered whether |
Do you have an example of a library that uses |
Actually, |
You're right. |
You should squash this after all the things. |
OK, I think I did the squashing correctly. Let me know if there's anything off here. |
Perfect, will merge after green build. |
Adds Grape::Endpoint.setup for pre-run endpoint config.
Just for clarity (and because the first example given above was slightly changed before this PR was merged in), here is the way to use this functionality in your specs:
|
For latest versions of RSpec this is works:
|
current_userをsessionで管理するようにしたのでそれに合わせた修正をした。 Grapeのhelpersブロックに定義したメソッドのモックの仕方は以下を参考にした。 ruby-grape/grape#397 Grapeでrailsで使っているsessionを使うため方法は以下を参考にした。 https://stackoverflow.com/questions/35344117/why-does-session-doesnt-work-in-grape-rails
https://stackoverflow.com/a/71306761/2771889 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 |
@thisismydesign Is this something useful for the docs? Care to contribute? |
This pull request addresses #396 by providing a
Grape::Endpoint.setup
class method which can be used to manipulate an Endpoint just before it begins executing. The use of this in a test suite would go something like this:Let's say I have a
current_user
helper that I want to stub. Let's say I don't even have it implemented yet, but I don't want it to error out while I'm building my library. Simple!I'm entering this as a pull request for a few reasons:
setup
step which precludes nesting or multiple layers of setup. I'm not sure if this is the right way to go, but I wanted to start with a straightforward implementation.Thoughts?