Test download of pdf with rspec and pdfkit

weltschmerz picture weltschmerz · Mar 7, 2013 · Viewed 9.1k times · Source

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!

Answer

Jonathan MacDonald picture Jonathan MacDonald · Mar 7, 2013

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!