2

I'm using the wicked_pdf gem, and I'm currently trying to speed up my spec suite.

I realised that some of my specs are generating PDF in my tmp folder, which is quite time-consuming.

Is there any way to completely stub the wicked_pdf generation, so it don't actually generate the PDF?

artm
  • 3,559
  • 1
  • 26
  • 36
Ruff9
  • 1,163
  • 15
  • 34

2 Answers2

4

It depends on how you are using it, and how much you want to cut out during your test suite, but probably a good place is WickedPdf::PdfHelper#make_pdf, which you could stub with something like this in an RSpec test:

describe MyController do
  describe '#show.pdf' do
    it 'creates a PDF'
      let(:tiny_pdf) do
        # What is the smallest possible valid PDF?
        # https://stackoverflow.com/a/17280876/23915
        "%PDF-1.4\ntrailer<</Root<</Pages<</Kids[<</MediaBox[0 0 3 3]>>]>>>>>>"
      end

      # Here is the actual stubbing
      allow(WickedPdf::PdfHelper).to receive(:make_pdf).and_return tiny_pdf

      get :show, params: { id: 1, format: :pdf }
      expect(response.status).to eq 200
    end
  end
end

Or you could override it globally by reopening the class and changing the definition:

if Rails.env.test?
  class WickedPdf
    class PdfHelper
      def make_pdf(options = {})
        "%PDF-1.4\ntrailer<</Root<</Pages<</Kids[<</MediaBox[0 0 3 3]>>]>>>>>>"
      end
    end
  end
end
Unixmonkey
  • 18,485
  • 7
  • 55
  • 78
  • 2
    if this can help I had an error using `allow(...)` but could fix it with: `allow_any_instance_of(WickedPdf::PdfHelper).to receive(:make_pdf).and_return tiny_pdf ` – Adrien Nov 21 '19 at 22:53
  • This needs an update, since nowdays (wicker_pdf v 2.6.3) `PdfHelper` is a module and `make_pdf` is a private method – MikeMarsian Jun 21 '22 at 14:45
0

Stubbing out WickedPdf::PdfHelper#make_pdf as in the other answer prevents testing what's being rendered with e.g. expect(response).to render_template("show").

To find which methods lead to writing to files I temporarily added expect(File).not_to receive(:open) before the get ... format: :pdf and found:

     Failure/Error: render pdf: "...", template: "show"

       (File (class)).open("/tmp/wicked_pdf20200304-24076-r7r1eh.html", 194, {:perm=>384})
           expected: 0 times with any arguments
           received: 1 time with arguments: ("/tmp/wicked_pdf20200304-24076-r7r1eh.html", 194, {:perm=>384})

     # /usr/local/bundle/gems/wicked_pdf-1.4.0/lib/wicked_pdf/tempfile.rb:10:in `initialize'
     # /usr/local/bundle/gems/wicked_pdf-1.4.0/lib/wicked_pdf.rb:58:in `new'
     # /usr/local/bundle/gems/wicked_pdf-1.4.0/lib/wicked_pdf.rb:58:in `pdf_from_string'
     # /usr/local/bundle/gems/wicked_pdf-1.4.0/lib/wicked_pdf/pdf_helper.rb:91:in `make_pdf'
     # /usr/local/bundle/gems/wicked_pdf-1.4.0/lib/wicked_pdf/pdf_helper.rb:113:in `make_and_send_pdf'
     # /usr/local/bundle/gems/wicked_pdf-1.4.0/lib/wicked_pdf/pdf_helper.rb:40:in `render_with_wicked_pdf'
     # /usr/local/bundle/gems/wicked_pdf-1.4.0/lib/wicked_pdf/pdf_helper.rb:30:in `render'
     # ./app/controllers/reports_controller.rb:21:in `block (2 levels) in show'
     # ./app/controllers/reports_controller.rb:11:in `show'

I then experimented with stubbing at different places in this backtrace and found that the following makes the test as fast as the usual "html" controller tests while still allowing to test for render_template("show"):

        it "returns http success" do
          allow_any_instance_of(WickedPdf::PdfHelper).to receive(:make_and_send_pdf)
          get :show, params: { id: 1, format: :pdf }
          expect(response).to have_http_status(:success)
        end

        it "renders the show template" do
          allow_any_instance_of(WickedPdf::PdfHelper).to receive(:make_and_send_pdf)
          get :show, params: { id: 1, format: :pdf }
          expect(response).to render_template("show")
        end

this also makes returning tiny pdf unnecessary.

artm
  • 3,559
  • 1
  • 26
  • 36