Do you want to test a PDF download with capybara, but don’t know how to do it?
Here I will how you can doing it are using the default driver (not the javascript driver).
The first thing that you are going to need, is knowing what do you want to test, here I will show you how you can test…
content
filename
content_type
disposition
is the one that you actually want… but maybe some of them are not important for your specific use case, so you can change the code to fit your needs.
You can compare the page.body
with the content of the file that you want to send.
For example if you are using carrierwave
and have a Receipt
record like this…
class Receipt < ApplicationRecord
belongs_to :user
mount_uploader :pdf, PdfUploader
end
You can send the pdf like this…
class ReceiptsController < ApplicationController
def show
receipt = Receipt.find(params[:id])
send_data receipt.pdf.read,
type: receipt.pdf.content_type,
filename: "Receipt-#{receipt.id}.pdf",
disposition: "inline"
end
end
You can write a test like this…
RSpec.describe "User downloads receipt pdf" do
scenario "download from the receipts page" do
user = create :user
create :receipt, user: user
login_as user, scope: :user
visit receipts_path
click_on "Download"
expect(page.body).to eq receipt.pdf.read
end
end
To test the filename
you can check the Content-Disposition
header, because it has the form…
#{disposition}; filename=#{filename}
RSpec.describe "User downloads receipt pdf" do
scenario "download from the receipts page" do
user = create :user
receipt = create :receipt, user: user
login_as user, scope: :user
visit receipts_path
click_on "Download"
expect(page.response_headers["Content-Disposition"]).to match "Receipt-#{receipt.id}.pdf"
end
end
To test content_type
you can check the Content-Type
header, like this…
RSpec.describe "User downloads receipt pdf" do
scenario "download from the receipts page" do
user = create :user
receipt = create :receipt, user: user
login_as user, scope: :user
visit receipts_path
click_on "Download"
expect(page.response_headers["Content-Type"]).to eq "application/pdf"
end
end
To test the disposition
you also can check the Content-Disposition
header, because it has the form…
#{disposition}; filename=#{filename}
RSpec.describe "User downloads receipt pdf" do
scenario "download from the receipts page" do
user = create :user
receipt = create :receipt, user: user
login_as user, scope: :user
visit receipts_path
click_on "Download"
expect(page.response_headers["Content-Disposition"]).to match "inline"
end
end
If you want to test the four things together (or some of them), you can write a helper function to express that you want a download with some characteristics. You can do something like this…
RSpec.describe "User downloads receipt pdf" do
scenario "download from the receipts page" do
user = create :user
receipt = create :receipt, user: user
login_as user, scope: :user
visit receipts_path
click_on "Download"
expect_download(
content: receipt.pdf.read,
filename: "Receipt-#{receipt.id}.pdf",
content_type: "application/pdf",
disposition: "inline"
)
end
def expect_download(content:, filename:, content_type:, disposition:)
expect(page.response_headers['Content-Type']).to eq content_type
expect(page.response_headers['Content-Disposition']).to eq "#{disposition}; filename=\"#{filename}\""
expect(page.body).to eq content
end
end
… and that’s all for now. I hope it helps =)
Here I try to share knowledge and fixes to common problems and struggles for ruby on rails developers, like How to fetch the latest-N-of-each record or How to test that an specific mail was sent or a Capybara cheatsheet. You can see more examples on Most recent posts or all posts.