Rspec using post request to get response - ruby-on-rails

I am trying to make a post request to an action in my controller using rspec, which should return a JSON response. This is my current test code which uses the Facebook Graph Gem. I am unsure of my code:
it "creates JSON format metadata with facebook post social message info about social account" do
stub_request(:post, "https://graph.facebook.com/test_fixed_origin_id_str/likes").with(:body => {"access_token"=>"this_is_a_test_token"}, :headers => {'Content-Type'=>'application/x-www-form-urlencoded'}).to_return(:status => 200, :body => "", :headers => {})
post :like, id: combined_id, format: :json
end
What would be the best way to make a post request to an API? I apologize if my question is not too clear but I have little experience with making requests in tests.
Thanks

One thing I can recommend is to just use the VCR gem (https://github.com/vcr/vcr). Essentially, the main idea behind this is that when your tests run the first time, the vcr will "record" the JSON response from the API endpoint.
In next iterations of the test, it will simply "play back" this response instead of making a live call to the server everytime. This has its benefits (speed, simplicity), but also you have to keep in mind that if the API response does change over time (ie. if FB changed their response), you would have to make sure to re-record what is coming back.

Related

How do I post json data in an rspec feature test powered by Capybara

Short question
I need to post JSON in feature tests, something like in my controller tests:
post '/orders.json', params.to_json, format: :json
But I need to do it in feature tests, and page.driver.post only posts form data. How do I post JSON in Capybara?
Long Explanation
I have a (non-Rails) app (let's call it the planet) that posts JSON to my rails app (call it a star) to create a record, and then forwards the user to the url for the show action.
I'm creating a feature spec, but since the first interaction isn't part of the Rails, app, I need to mock it using JSON.
I've been using this:
page.driver.post '/orders.json', params.to_json
But this seems to post as a form, whereas my planet application posts JSON. This leads to some really funky parameter problems, where parsing JSON gives me different params from form-data.
How do I post JSON in Capybara?
TL;DR - you don't
Capybara is designed to emulate a user for feature tests. Hence why the post method is driver specific (page.driver.xxx) and really isn't intended for use directly by tests. A user can't just submit a POST without a page to submit it from. Therefore, if you do actually need to test this via feature tests, the best solution is to create a small test app that provides a page you can have Capybara visit which will automatically (or on button click, etc) have the browser make the AJAX post to the app under test and handle the response.
So, turns out that it just isn't possible with Capybara. See Thomas Walpole's answer for more details.
As a workaround, I used httparty:
require 'httparty'
RSpec.feature 'Checkouts', type: :feature do
include HTTParty
base_uri 'http://localhost:3000'
private
def checkout_with(cart)
post orders_path(format: :json).to_s,
body: cart.to_json,
headers: { 'Content-Type' => 'application/json' }
end
end

Streaming API with Rails not able to get streamed data

I am trying to fetch data from Twitter Streaming API in my rails app and i have created my own module which gives me twitter Authorization Head. I am able to get authorized but i am not getting the response back... all i see is the request in pending state (i am guessing as its streaming and connection not being closed). What can i do to my below code so that i can start printing the response as i get from Streaming API ?
class MainController < ApplicationController
include Oauth::Keys
def show
#oauth_signature_string = Oauth::Signature.generate(signature_params)
#header = Oauth::HeaderString.create(header_params)
RestClient::Request.execute(method: :GET, url: 'https://stream.twitter.com/1.1/statuses/sample.json', :headers => {:Authorization => %Q(OAuth ****************************)} )
end
end
Because Twitter is "streaming" the data and not closing the connection, your RestClient request is not being ended and your show action is hanging there and not "finishing". So, rails can't continue and render the default main/show.html.erb page.
So, you might want to look into ActionController::Streaming class and see if you can rewrite you views and HTTP call to utilize it. Or, it would be much easier to use a non-streaming API edge.
Also, what you are doing seems to be a better fit for javascript. You might want to use Twitter's official Javascript api to do all authentications and status streams.

Rails - Sending a GET Request

I'm trying to retrieve a user's Google account information when a form is submitted. In order to do so, I have to make a GET request to an url. Here's what it says in the YouTube API documentation
To request the currently logged-in user's profile, send a GET request
to the following URL. Note: For this request, you must provide an
authentication token, which enables YouTube to identify the user.
https://gdata.youtube.com/feeds/api/users/default
https://developers.google.com/youtube/2.0/developers_guide_protocol_profiles?hl=en
How do I make it so a custom (or specificall this) GET request happens when the form is submitted, and how do I provide the authentication token? Information that might help: When the form is submitted, it will go to the VideoController's new method.
Also after making the request, how do I access the information? I need to see whether <yt:relationship> is present or not in the given information.
Thanks!
I find HTTParty gem as very useful for working with external APIs in rails.
You can make requests as
response = HTTParty.post("http://www.example.com", :timeout => 5, :body => "my body content", :query => { hash_of_params_here } ,:headers => {'Content-Type' => 'application/json', 'AuthKey' => "your_key_here"})
response object will have 'statuscode', 'headers', 'body' etc (whatever youtube send back in your case). You can access its content using
response.parsed_response
same for get requests too
Please do read more about it for better understanding before getting started.
Sources : Documentation & Tutorial
Yuo can use excon gem to make specific CRUD or only get requests to external resources, for example, it should be something like this:
Excon.post('http://youtube.com', :body => 'token=sjdlsdjasdljsdlasjda')
PS: But seem you not requied the direct gems, tru useing google-api gem, as it described here in the documentation.

Parsing Request Headers in Test::Unit

I'm trying to parse HTTP request headers in Test::Unit, but to no avail. I'm writing a functional test for a controller like so:
test "create a shopify order" do
get :order, PARAMS, {HEADER1 => VAL, HEADER2 => VAL}
assert_response :success # Make sure this returns 200, first off
...
end
Normally, I would read the headers like, request.headers[HEADER1], but this returns nil in Test::Unit. request isn't defined.
How do I actually grab the value of the headers I set in the above request? And how do I assign them to request? My app pulls from webservices, and I need to test the values that are passed through in headers, so I don't want to change my app code. I just need to simulate what those requests are like in Test::Unit.
Thanks!
Knowing what test quite you're using certainly helps (thanks Jesse). I found that I'd been looking at the doc for integration tests, not functional tests, and that setting headers works differently in functional tests:
http://twobitlabs.com/2010/09/setting-request-headers-in-rails-functional-tests/
So I wasn't setting the headers I thought I was. They were being read just fine--just not set.

RSpec approach to test XML and HTTP responses?

I have a RESTful site that uses both the XML and web responses (API and web site). Since there are a lot of pages, my current goal is setting up RSpec to simply request each of the pages in both data formats and check if the returned response is 200. What is the best way to check for both XML and HTTP 200 response? I know I should be doing TDD upfront, but right now I need this as a shell.
Example: I want to request both "/users" and "/users.xml" and test if there weren't any server errors (200 OK)
I wrote a blog post on testing JSON APIs with RSpec a couple of weeks ago.
Basically, the way we are doing it is to get the actual response, and parse it to make sure it has the right content. As an example:
context "#index (GET /artworks.json)" do
# create 30 Artwork documents using FactoryGirl, and do a HTTP GET request on "/artworks.json"
before(:each) do
30.times { FactoryGirl.create(:artwork) }
get "/artworks.json"
end
describe "should list all artworks" do
# the request returns a variable called "response", which we can then make sure comes back as expected
it { response.should be_ok }
it { JSON.parse(response.body)["results"].should be_a_kind_of(Array) }
it { JSON.parse(response.body)["results"].length.should eq 30 }
# etc...
end
end
Obviously a simple example, but hopefully you get the idea. I hope this helps.

Resources