Setting page/respone.body in Capybara used to work in Webrat - ruby-on-rails

I am migrating to Capybara.
One of the problems I have is migrating the pdf step.
This step sets page.body to a parsed pdf.
That way I can use the default cucumber steps.
When 'I follow the PDF link "$label"' do |label|
click_link(label)
page.body = PDF::Inspector::Text.analyze(page.body).strings.join(" ")
end
Ex.
When I follow the PDF link "Catalogue"
Then I should see "Cheap products"
The error I get is this one:
undefined method `body=' for #<Capybara::`enter code here`Document> (NoMethodError)

On top, make sure you set :js => true like this:
scenario 'do something', :js => true do
str = PDF::Inspector::Text.analyze(page.body).strings.join(" ") # or whatever string you want
# then just use javascript to edit or add the body
page.evaluate_script("document.write(#{str});")
end
Now this is dependent on the driver, but it's one solution...

There is no setter for body defined in the source in capybara, so you cannot set it externally like that. Try this (untested):
page.instance_variable_set(:#body, PDF::Inspector::Text.analyze(page.body).strings.join(" "))

This worked for me:
Then /^I should be served the document as a PDF$/ do
page.response_headers['Content-Type'].should == "application/pdf"
pdf = PDF::Inspector::Text.analyze(page.source).strings.join(" ")
page.driver.response.instance_variable_set('#body', pdf)
end
Then /^I should see the document details$/ do
page.should have_content("#{#document.customer.name}")
page.should have_content("#{#document.resources.first.resource.name}")
page.should have_content("Document opened at #{#document.created_at.strftime("%e-%b-%4Y %r")}")
end
Note that I'm serving my PDF inline
pdf = DocumentPdf.new(#document)
send_data pdf.render, :filename => "document_#{#document.created_at.strftime("%Y-%m-%d")}",
:type => "application/pdf",
:disposition => "inline"

Related

AXLSX: Parsing xlsx file for rspec tests

Any idea how to write view specs (presence of headers, rows, etc.) for a generated xlsx file from the xlsx gem? Not sure if I'm doing it correctly in the first place but here's what I have so far
RSpec.describe "spreadsheet.xlsx.axlsx", :type => :view do
...
it "should have header Books" do
assign(:spreadsheet, spreadsheet)
render
# rendered.rows[0].cells.map(&:value).should include "Books"
end
end
In pry, rendered is in a utf-8 encoded string I'm not sure how to parse for headers, etc.
=> "PK\u0003\u0004\u0014\u0000\u0000\u0000\b\u0000\u0000\u0000!\xECc8k\xD4\
Is there a way I can just test the generated xlsx file like I would an html view?
Something like...
it "has header Books" do
assign(:worksheet, worksheet)
render
expect(rendered).to have_xpath("(//table)[1]/thead/tr/td", :text => "Books")
end
Thanks in advance!
It appears rendered is the raw response so you can use something like the axlsx_rails request specs:
File.open('/tmp/xlsx_temp.xlsx', 'w') {|f| f.write(rendered) }
wb = nil
expect{ wb = Roo::Excelx.new('/tmp/xlsx_temp.xlsx') }.to_not raise_error
wb.cell(2,1).should == 'Some value'
This uses the roo gem to parse the file since Axlsx does not read xlsx.
See:
https://github.com/straydogstudio/axlsx_rails/blob/master/spec/axlsx_request_spec.rb#L19-L22

Capybara::ElementNotFound - How to click on specific button with id using Capybara

Trying to access this button on root url:
here is html
with this test:
feature "New comment button" do
scenario "User can add new comment on root page", :js => true do
visit root_path
id = 152
click_button("#button_#{id}")
within("#comment_row_#{id}") do
fill_in('content', :with => 'this is a comment')
click_button('create comment')
page.must_have_flash_message('Successfully created')
end
end
and geting this:
Capybara::ElementNotFound: Unable to find button "#button_152"
How to get this element using id ?
I am using selenium-web-driver
EDIT
WHAT I TRIED
# page.driver.browser.switch_to.frame 'top-frame' # Selenium::WebDriver::Error::NoSuchFrameError: Unable to locate frame: top-frame
# page.find('#button_152').click # not working
# click_button("#button_152") # not working
# first(:xpath, '//button[#id="button_152"]').click
2.This is an overview of frames :
all iframes are just google chrome addons
4.link to full html
You can read about switching windows and frames here: http://docs.seleniumhq.org/docs/03_webdriver.jsp#moving-between-windows-and-frames
Ruby specific bindings here: https://code.google.com/p/selenium/wiki/RubyBindings
Capybara handling iframes: handling iframe with capybara ruby
As for your problem, here's an example you can edit:
within_frame 'evernoteFilingTools' do
click_button("#button_#{id}")
#button_#{id} # not working
#page.find("#button_#{id}",:visible => true).click # does not work as well
within("#comment_row_#{id}") do
fill_in('content', :with => 'this is a comment')
click_button('create comment')
page.must_have_flash_message('Successfully created')
end
end
You should replace evernoteFilingTools with the iframe ID that contains the content you want to manipulate
Sometimes, it can be thrown off by invalid markup. This HTML has a div (<div class="icons">) inside a table, which is not valid. Try running the markup through a validator such as http://validator.w3.org/ and fix any errors it reports. That might fix your Capybara problem as well.

Ruby on Rails - send_file is not working

I wrote the following code.
def help_doc
pdf_filename = File.join(Rails.root, "/public/doc.pdf")
send_file(pdf_filename, :filename => "doc.pdf" :type => "application/pdf", :diposition => "inline")
end
It's working, but not as I want. I'd like to view in the browser the pdf, but it's doing download of the document.
I thought that just writing :disposition => "inline" and I could see on the browser the pdf.
Try removing the content disposition. You have a typo in your code, deposition vs disposition, and you're missing a comma after filename.

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

Integrate Jasper in Rails 3

I'm trying to integrate a rails 3 app with jasper following this wiki:
http://wiki.rubyonrails.org/rails/pages/HowtoIntegrateJasperReports
But it seems that a lot of information isn't updated so it's been very hard to make it work by myself. I've also read a topic at ruby-forum: http://www.ruby-forum.com/topic/139453
with some details explained but still couldn't make it work.
My first problem is related with the render_to_string method:
When the controller method runs I receive a "Template is missing" error:
this is the method:
def report
#customers = Customer.all
send_doc(render_to_string(:template => report_customers_path, :layout => false), '/pdfs', 'report.jasper', "customers", 'pdf')
end
Although this seems simple I'm not understanding why is this happening. Doesn't render_to_string with layout => false suposed to get me the string result of that action?
I also tried :action instead of :template, but it does the same.
If anybody with some expertise with this integration could help...
Thanks in advance,
André
We actually use jasperreports to create reports, and recently upgraded to Rails 3.0. To create the xml, we use xml.erb templates. Jasper reports runs in a separate glassfish server Here's the general idea:
url = URI.parse(my_url_string)
dataxml = render_to_string(:template => my_template_name).gsub(/\n/, '')
params = {'type' => 'pdf', 'compiledTemplateURI' => my_jasper_file, 'data' => dataxml }
request = Net::HTTP::POST.new(url.request_uri)
request.set_form_data(params)
obj = Net::HTTP.new(url.host, url.port)
obj.read_timeout = my_timeout_setting
response = obj.start { |http| http.request(request) }
case response
when Net::HTTPOK
send_data(response.body, :filename => my_chosen_filename, :type => "application/pdf", :disposition => "inline")
else
raise "failed to generate report"
end
I don't know anything about jasper, but it sounds like you want to do two things: render a PDF template and then send the raw output back w/ a PDF mime type:
pdf_contents = render_to_string(:template => 'users/report')
send_data(pdf_contents, :file_name => 'report.pdf', :type => 'application/pdf')
You're passing in the external URL as the template path, but that's probably wrong if you're getting errors about the template path. Fix the template path first.
Use savon to interact with jaserserver in rails3.
Here is an example:
require 'logger'
require 'savon'
logger = Logger.new(STDOUT)
logger.info "Test jasper via Savon-SOAP"
#client = Savon::Client.new {
wsdl.document = "http://localhost:8080/jasperserver/services/repository?wsdl"
http.auth.basic "jasperadmin", "jasperadmin"
}
logger.info "runReport method"
begin
result = #client.request :run_report do
soap.body = "<requestXmlString>
<![CDATA[
<request operationName='runReport' >
<argument name='RUN_OUTPUT_FORMAT'>PDF</argument>
<resourceDescriptor name='' wsType='' uriString='/reports/samples/AllAccounts' isNew='false'>
<label></label>
</resourceDescriptor>
</request>
]]>
</requestXmlString>"
end
send_data result.http.raw_body, :type => 'application/pdf', :filename => 'report.pdf', :disposition => 'attachment'
rescue Exception => e
logger.error "SOAP Error: #{e}"
end
Try to change the render_to_string() code to this:
#customers.to_xml

Resources