Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Test PDF within Cucumber and Capybara
# normal Gem dependancy declarations
# ...
group :test, :cucumber do
gem 'pdf-reader'
end
When /^I follow the PDF link "([^"]+)"$/ do |label|
click_link(label)
temp_pdf = Tempfile.new('pdf')
temp_pdf << page.source.force_encoding('UTF-8')
temp_pdf.close
pdf_text = PDF::PdfToText.new(temp_pdf.path)
page.driver.response.instance_variable_set('@body', pdf_text.get_text)
end
Scenario: Check printable PDF
When I follow the PDF link "Print"
Then I should see "My name"
And I should see "Something else"
module PDF
class PdfToText
def initialize(pdf_file)
@receiver = PDF::SimplePageTextReceiver.new
pdf = PDF::Reader.file(pdf_file, @receiver)
end
def get_text
@receiver.content.inspect
end
end
end
module PDF
class SimplePageTextReceiver
attr_accessor :content
def initialize
@content = []
end
# Called when page parsing starts
def begin_page(arg = nil)
@content << ""
end
# record text that is drawn on the page
def show_text(string, *params)
@content.last << string.strip
end
# there's a few text callbacks, so make sure we process them all
alias :super_show_text :show_text
alias :move_to_next_line_and_show_text :show_text
alias :set_spacing_next_line_show_text :show_text
# this final text callback takes slightly different arguments
def show_text_with_positioning(*params)
params = params.first
params.each { |str| show_text(str) if str.kind_of?(String)}
end
end
end
@chrisbloom7

This comment has been minimized.

Copy link

chrisbloom7 commented Feb 28, 2012

Thank you for the page.driver.response.instance_variable_set bit, I was trying to figure that out for the last 2 hours. I was able to avoid using any temp files or extra modules by using pdf-inspector instead of pdf-reader:

require "pdf/inspector"

Then /^I should be served the referral 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 referral 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
@chalmagean

This comment has been minimized.

Copy link

chalmagean commented Jun 4, 2014

If you happen to get this error:

undefined method `join' for #<String:...> (NoMethodError)

you can fix it by converting the text to an array like this:

page.driver.response.instance_variable_set('@body', [pdf_text.get_text])
@theotherzach

This comment has been minimized.

Copy link

theotherzach commented Nov 22, 2016

Thanks for the inspiration. I used StringIO to grab the contents of my pdf response and turn it into an io stream for PDF::Reader

 And the pdf file should contain:
          | Subtotal      | $10.00     |
          | Shipping      | $20.00     |
          | IN Sales Tax  | $2.00      |
          | Total         | $32.00     |
Then(/^the pdf file should contain:$/) do |table|
  pdf_io = StringIO.new(page.source.force_encoding('UTF-8'))
  reader = PDF::Reader.new(pdf_io)
  contents = reader.pages.map(&:to_s).join("\n")

  table.rows.each do |cells|
    cells.each do |cell|
      expect(contents).to include cell
    end
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.