Ruby WebMock: Getting Actual Parameters Passed Through a Method and Using Them in Spec File - ruby

I'm using WebMock to stub out HTTP requests. I have this one particular call where, instead of creating dummy data to pass through, I want to be able to capture the actual parameters I would pass into my send() method. Therefore, I need access to those actual parameters in my spec and I imagine I would need to somehow capture that context.
So, for example, in my application I'm calling this method:
send(method, uri, :body => data_file)
And in my spec file I'm stubbing the method:
FoobarModule.should_receive(:send).with(args)
Is there any way I could -- in WebMock, Rspec -- get the context of when send() is being called in the application and grab those parameters I'm passing through to use them within the spec and replace them with args?
I've looked through the documentation and I don't see much of anything on this. If there's anyone aware of this, I would greatly appreciate your help. Thanks.

Using WebMock you could use request callbacks to capture request data:
WebMock.allow_net_connect!
WebMock.after_request do |request_signature, response|
puts request_signature
end

Related

how to stub specific IDs only in cucumber test?

Very new to Ruby and cucumber, and i've got a controller that accepts an ID. Basically a rest API, so the client would call /cows/1234 and /cows/777. That would then route to getFluffyCow and pass :id = 1234 or 777.
My initial attempt is as follows:
allow(getFluffyCow).to receive(:call).with(1234).and_return(mock_cow1)
allow(getFluffyCow).to receive(:call).with(777).and_return(mock_cow2)
but the response is returning nothing. What am I doing wrong?
Thanks!
The params will come through as strings so specify the ID's as strings when stubbing the :call method:
allow(getFluffyCow).to receive(:call).with('1234').and_return(mock_cow1)
allow(getFluffyCow).to receive(:call).with('777').and_return(mock_cow2)

Rails, rspec: using "send()" to dynamically generate capybara URLs for controller specs

Inside a controller spec for a #show action:
resource_name = "adoption_transfer_type"
it "returns a single resource" do
resource = create(resource_name.to_sym)
# Works
xhr :get, api_v1_lookups_adoption_transfer_type_path(resource.id)
# Does not work
xhr :get, send("api_v1_lookups_#{resource_name}_path(#{resource.id})")
end
It results in the following error:
Failure/Error: xhr :get, send("api_v1_lookups_adoption_transfer_type_path(#{resource.id})")
NoMethodError:
undefined method `api_v1_lookups_adoption_transfer_type_path(66)'
It looks like send(...) is converting it to a string literal instead of executing it as Ruby code, but I thought that was the purpose of the send(...) method.
The broader picture is I'm using a single spec file to generate the specs for several lookup resources, since they are all the same and there's no reason to manage 10+ files when I can do it all in one.
the string interpolates to api_v1_lookups_adoption_transfer_type_path(2) which means you're trying to call some method by that name. Instead you want:
send("api_v1_lookups_#{resource_name}_path", resource.id)
This is how you pass arguments to a send call, also i'd get into the habit of using public_send =)

What class does this method (read) come from (open-uri ruby)

I read some code like:
source = URI.join(uri).read
This basically goes to the URI, and stores the source of the webpage in the variable.
I tried this in IRB:
URI.join(uri).class
and it returned URI::HTTP, but, when I tried URI.join(uri).read.class => String.
I checked String class but there is no read method there.
I want to stub this method but am not able to because I don't know where it comes from.
read is from Ruby's StringIO module, which acts like the normal IO class.
OpenURI provides read via the StringIO class, which is how it fools us, and our code, into thinking the URL is a device we can read from.
URI.join(uri).read.class returns String because the page is read from the site pointed to by the URL, and the content is a string. OpenURI overrides the URI class and adds read to it. If you try:
require 'uri'
URI.join('http://example.com').read
without having required OpenURI, you'll get an error because, by itself, URI doesn't know how to read.
URI.join('http://example.com')
=> #<URI::HTTP:0x0000010292de68 URL:http://example.com>
URI.join('http://example.com').read
NoMethodError: undefined method `read' for #<URI::HTTP:0x0000010218b3b8 URL:http://example.com>
Rather than stub URI.read() (provided by OpenURI as noted in the Tin Man's answer), consider using a library like WebMock that can intercept HTTP requests regardless of the exact mechanism used to make them.

Raising OpenURI::HTTPError caused wrong number of arguments error

I am testing how a method handles a 302 HTTPError exception. I tried to stub the one method call to raise one programmatically, however it keep complaining that wrong number of arguments error (0 for 2)
the code tested this particular line:
document = Nokogiri.HTML open(source_url)
and in the spec I stubbed it like this:
subject.stub(:open).and_raise(OpenURI::HTTPError)
subject.should_receive(:ended=).with(true)
subject.update_from_remote
I don't think it is related to Nokogiri.HTML() or Open-uri.open(), so why is this happening?
Also, how would I try to make this HTTPError as a 302 redirect error? Thanks
I found out that OpenURI::HTTPError's constructor requires two parameters. Rspec by default will call the error class's new method with no parameter, which cause this error. So I need to manually create an error object by passing the required parameters.
exception_io = mock('io')
exception_io.stub_chain(:status,:[]).with(0).and_return('302')
subject.stub(:open).with(anything).and_raise(OpenURI::HTTPError.new('',exception_io))
This is a very late reply, but for others who may find this helpful: if you use the FakeWeb gem in conjunction with Nokogiri, you can do this kind of testing without having to get so involved with the internals of the code. You can register a URI with FakeWeb in your test, and tell it what to return. For example:
FakeWeb.register_uri(:get, 'http://www.google.com', :status => ['404', 'Not Found'])
The URI argument you provide needs to match the URI your method is calling. FakeWeb will then intercept the call, and return the status you provide.

Sinatra/Rack params[] in before block

I'm making a site using Sinatra, everything is going well, or was until I needed to access the params[] hash in the before block.
Basically, I'm trying to do this:
before do
if params[:forum_id]
#forum = Forum.find(params[:forum_id])
build_breadcrumbs(#forum.parents)
# ... more code, snipped to keep it short
end
end
But the thing is, I can't call the params[] hash in the before block, does anyone have any ideas?
The reason I'm putting this code in the before block is because I'd rather not have to go and put it in every one of my get and post blocks for every page.
From the docs:
Before filters are evaluated before each request within the same
context as the routes will be and can modify the request and response.
Since this happens before the actual request, you can't access the request parameters. What you can do is put the repetitive code into a method and call that in your route blocks.
This is not true anymore. I just tested it. You can now access params in before {...}

Resources