Feedjira: VCR not recording cassetes - ruby-on-rails

I have a very simple controller that grabs some data from rss using Feedjira. I want to test this controller by recording the RSS response. Here is the controller code:
def index
#news = Feedjira::Feed.fetch_and_parse URI.encode("http://news.google.com/news/feeds?q=\"#{query}\"&output=rss")
end
and my spec test:
it "should assign news feed", :vcr do
get :index
assigns(:news).entries.size.should == 6
assigns(:news).entries[0].title.should == "First item title"
end
and code for vcd config:
VCR.configure do |c|
c.cassette_library_dir = Rails.root.join("spec", "vcr")
c.hook_into :fakeweb
c.ignore_localhost = true
end
RSpec.configure do |c|
c.treat_symbols_as_metadata_keys_with_true_values = true
c.around(:each, :vcr) do |example|
name = example.metadata[:full_description].split(/\s+/, 2).join("/").underscore.gsub(/[^\w\/]+/, "_")
options = example.metadata.slice(:record, :match_requests_on).except(:example_group)
VCR.use_cassette(name, options) { example.call }
end
end
For some unknown reason, the VCR cassete is not being recorded in this specific test. All other tests that use web calls are working, but with this one with Feedjira it seems that vcr does not detects the network calls. Why?

According to Feedjira's home page, it uses curb, not Net::HTTP to make HTTP requests:
An important goal of Feedjira is speed - fetching is fast by using
libcurl-multi through the curb gem.
VCR can only use FakeWeb to hook into Net::HTTP requests. To hook into curb requests, you'll need to use hook_into :webmock instead.

As of this commit in Feedjira 2.0, Feedjira uses faraday, which means you can follow the testing guide in the Faraday readme or use VCR.
Feedjira uses VCR internally now too.
Example
For example you could use vcr in an rspec example like this,
it 'fetches and parses the feed' do
VCR.use_cassette('success') do
feed = Feedjira::Feed.fetch_and_parse 'http://feedjira.com/blog/feed.xml'
expect(feed.last_modified).to eq('Fri, 07 Oct 2016 14:37:00 GMT')
end
end

Related

Browsermob Proxy + Selenium + Ruby setup giving 550 response

So I am looking at trying to integrate Browsermob into a Ruby project so i can edit http responses.
I have been following the setup with Selenium instructions from the Github and another article I found about performance testing - which I also want to do.
For this, I have gone with the code from the performance testing article but the results I am getting are the same.
The code is
require 'selenium-webdriver'
require 'browsermob/proxy'
require 'rspec-expectations'
include RSpec::Matchers
require 'json'
def configure_proxy
proxy_binary = BrowserMob::Proxy::Server.new('my/path/to/browsermob-proxy-2.1.4/bin/browsermob-proxy')
proxy_binary.start
proxy_binary.create_proxy
end
def browser_profile
browser_profile = Selenium::WebDriver::Firefox::Profile.new
browser_profile.proxy = #proxy.selenium_proxy
browser_profile
end
def setup
#proxy = configure_proxy
#driver = Selenium::WebDriver.for :firefox, profile: browser_profile
end
def teardown
#driver.quit
#proxy.close
end
def capture_traffic
#proxy.new_har
yield
#proxy.har
end
def run
setup
har = capture_traffic { yield }
#har_file = "./selenium_#{Time.now.strftime("%m%d%y_%H%M%S")}.har"
har.save_to #har_file
teardown
end
run do
#driver.get 'http://the-internet.herokuapp.com/dynamic_loading/2'
#driver.find_element(css: '#start button').click
Selenium::WebDriver::Wait.new(timeout: 8).until do
#driver.find_element(css: '#finish')
end
end
performance_results = JSON.parse `yslow --info basic --format json #{#har_file}`
performance_grade = performance_results["o"]
performance_grade.should be > 90
Now, the problem I get is that as soon as I try to run this code (isolated away from my project or even within it) I get:
(.rvm/gems/ruby-2.5.3/gems/rest-client-2.0.2/lib/restclient/abstract_response.rb:220:in 'rescue in exception_with_response': HTTP status code 550 (RestClient::RequestFailed)
Does anyone know why I would be getting this? I understand that a 550 is an action not taken code but I'm confused as to why I would be getting this?
Any help would be VERY much appreciated!

Can I log the unhandled VCR request body?

I'm using the VCR gem to mock HTTP queries. I've recorded cassettes, but then I had to change some stuff around, and now I'm getting an error:
An HTTP request has been made that VCR does not know how to handle:
POST http://api.endpoint.here/path.json
Now, because it's a POST request, the VCR is configured to match those on body as well as path. Can I log or dump the body of the unhandled request so I can tweak the cassettes accordingly? Thank you.
Won't callback achieve what you need?
VCR.configure do |c|
c.after_http_request do |request, response|
if request.method == :post
puts "POST Request:#{request.uri}"
puts "#{request.to_hash}" # or request.body
end
end
c.allow_http_connections_when_no_cassette = true
end

Test download of pdf with rspec and pdfkit

I am developing a rails 3.2 application with which users can download pdfs. I enjoy test driven development a lot using rspec and shoulda matchers, but I'm at a loss with this one.
I have the following code inside my controller:
def show_as_pdf
#client = Client.find(params[:client_id])
#invoice = #client.invoices.find(params[:id])
PDFKit.configure do |config|
config.default_options = {
:footer_font_size => "6",
:encoding => "UTF-8",
:margin_top=>"1in",
:margin_right=>"1in",
:margin_bottom=>"1in",
:margin_left=>"1in"
}
end
pdf = PDFKit.new(render_to_string "invoices/pdf", layout: false)
invoice_stylesheet_path = File.expand_path(File.dirname(__FILE__) + "/../assets/stylesheets/pdfs/invoices.css.scss")
bootstrap_path = File.expand_path(File.dirname(__FILE__) + "../../../vendor/assets/stylesheets/bootstrap.min.css")
pdf.stylesheets << invoice_stylesheet_path
pdf.stylesheets << bootstrap_path
send_data pdf.to_pdf, filename: "#{#invoice.created_at.strftime("%Y-%m-%d")}_#{#client.name.gsub(" ", "_")}_#{#client.company.gsub(" ", "_")}_#{#invoice.number.gsub(" ", "_")}", type: "application/pdf"
return true
end
This is fairly simple code, all it does is configure my PDFKit and download the generated pdf. Now I want to test the whole thing, including:
Assignment of instance variables (easy, of course, and that works)
The sending of data, i.e. the rendering of the pdf => And this is where I'm stuck
I have tried the following:
controller.should_receive(:send_data)
but that gives me
Failure/Error: controller.should_receive(:send_data)
(#<InvoicesController:0x007fd96fa3e580>).send_data(any args)
expected: 1 time
received: 0 times
Does anyone know of a way to test that the pdf is actually downloaded/sent? Also, what more things do you see that should be tested for good test coverage? E.g., testing for the data type, i.e. application/pdf, would be nice.
Thanks!
Not sure why you're getting that failure but you could instead test the response headers:
response_headers["Content-Type"].should == "application/pdf"
response_headers["Content-Disposition"].should == "attachment; filename=\"<invoice_name>.pdf\""
You asked for advice regarding better test coverage. I thought I'd recommend this: https://www.destroyallsoftware.com/screencasts. These screencasts have had a huge impact on my understanding of test-driven development -- highly recommended!
I recommend using the pdf-inspector gem for writing specs for PDF related Rails actions.
Here's an exemplary spec (which assumes the Rails #report action writes data about a Ticket model in the generated PDF):
describe 'GET /report.pdf' do
it 'returns downloadable PDF with the ticket' do
ticket = FactoryGirl.create :ticket
get report_path, format: :pdf
expect(response).to be_successful
analysis = PDF::Inspector::Text.analyze response.body
expect(analysis.strings).to include ticket.state
expect(analysis.strings).to include ticket.title
end
end

Get URL headers without the HTML

A bit of a strange question. Is there a way to ask a webserver to return only the headers and not the HTML itself ?
I want to ask a server for a URL and see if its valid (not 404/500/etc) and follow the redirections (if present) but not get the actual HTML content.
Thanks
Preferably a way to do this in Ruby
use HEAD instead of GET or POST
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html Section 9.4
As suggested, check the Net::HTTP library..
require 'net/http'
Net::HTTP.new('www.twitter.com').request_head('/').class
This is exactly what HEAD HTTP method does.
For Ruby, there is a beautiful gem, much simpler than the low-level net/http that allows you to perform HEAD requests.
gem install rest-open-uri
then
irb> require 'rubygems'
=> true
irb> require 'rest-open-uri'
=> true
irb> sio = open("http://stackoverflow.com", :method => :head)
=> #
irb> sio.meta
=> {"expires"=>"Tue, 30 Nov 2010 18:08:47 GMT", "last-modified"=>"Tue, 30 Nov 2010 18:07:47 GMT", "content-type"=>"text/html; charset=utf-8", "date"=>"Tue, 30 Nov 2010 18:08:27 GMT", "content-length"=>"193779", "cache-control"=>"public, max-age=18", "vary"=>"*"}
irb> sio.status
=> ["200", "OK"]
It follows redirections. You have to rescue for SocketError when host doesn't exists or OpenURI::HTTPError if file doesn't exists.
If you want something more powerfull have a look at Mechanize or HTTParty.
Use Ruby's net/http and the HEAD method that Mak mentioned. Check ri Net::HTTP#head from the command line for info.
actually i had to fold pantulis' answer into my own. it seems like there are two kinds of urls neither fns worked alone so i did
module URI
def self.online?(uri)
URI.exists?(uri)
end
def self.exists?(uri)
URI.exists_ver1?(uri)
end
def self.exists_ver1?(url)
#url = url
["http://", "https://"].each do |prefix|
url = url.gsub(prefix, "")
end
begin
code = Net::HTTP.new(url).request_head('/').code
[2,3].include?(code.to_i/100)
rescue
URI.exists_ver2?(#url)
end
end
def self.exists_ver2?(url)
url = "http://#{url}" if URI.parse(url).scheme.nil?
return false unless URI.is_a?(url)
uri = URI(url)
begin
request = Net::HTTP.new uri.host
response= request.request_head uri.path
#http status code 200s and 300s are ok, everything else is an error
[2,3].include? response.code.to_i/100
rescue
false
end
end
end

Mechanize with FakeWeb

I'm using Mechanize to extract the links from the page.
To ease with development, I'm using fakeweb to do superfast response to get less waiting and annoying with every code run.
tags_url = "http://website.com/tags/"
FakeWeb.register_uri(:get, tags_url, :body => "tags.txt")
agent = WWW::Mechanize.new
page = agent.get(tags_url)
page.links.each do |link|
puts link.text.strip
end
When I run the above code, it says:
nokogiri_test.rb:33: undefined method `links' for #<WWW::Mechanize::File:0x9a886e0> (NoMethodError)
After inspecting the class of the page object
puts page.class # => File
If I don't fake out the tags_url, it works since the page class is now Page
puts page.class # => Page
So, how can I use the fakeweb with mechanize to return Page instead of File object?
Use FakeWeb to replay a prefetched HTTP request:
tags_url = "http://website.com/tags/"
request = `curl -is #{tags_url}`
FakeWeb.register_uri(:get, tags_url, :response => request)
agent = WWW::Mechanize.new
page = agent.get(tags_url)
page.links.each do |link|
puts link.text.strip
end
Calling curl with the -i flag will include headers in the response.
You can easily fix that adding the option :content_type => "text/html" you your FakeWeb.register_uri call

Resources