Downloading a CSV using Capybara

2019-04-04 15:16发布

问题:

For a rspec test I need to download a report in a CSV file format and verify the information given.

The report is generated from a web page when a button is clicked. The browsers save dialog box is open giving the options to open or save.

How can I get the the file to be saved to the computer using rspec and Capybara?

回答1:

I have been using MiniTest::Spec for this and did it with the webkit-driver, but it should translate to RSpec without a problem as it is basically just Capybara functionality:

scenario "download overview" do
  within "aside#actions" do
    click_link "Download overview"
  end
  page.status_code.must_equal 200
  page.response_headers['Content-Type'].must_equal "text/csv"
  page.response_headers['Content-Disposition'].must_match /attachment; filename="Übersicht.*\.csv/
  page.must_have_content "Schubidu"
  page.must_have_content "U13"
  page.wont_have_content "5000"
end

I did not go into details about the format of the data, but the records that should have been there were there and the ones that should not have been left out (of course this was just a small dataset to keep the tests swift).



回答2:

Assuming you have a controller action that looks something like this:

require 'csv' # assuming you have this line somewhere

  def download
    @records = MyModel.all
    csv_data = CSV.generate do |data|
      data << ["Field 1", "Field 2"]
      @records.each do |record|
        data << [record.field1, record.field2]
      end
    end
    send_data csv_data, type: "text/csv", filename: "my_file.csv"
  end

I was able to use Capybara to verify that clicking my button would have caused the browser to trigger a download prompt:

click_on 'Download as CSV'
header = page.response_headers['Content-Disposition']
header.should match /^attachment/
header.should match /filename="my_file.csv"$/

Note that page.response_headers is driver specific. I'm using capybara-webkit. A Content-Disposition header should contain attachment rather than inline for it to cause a download prompt. Capybara also displayed the content of the file as the response body (although this may also be driver specific), so it was easy to verify the output:

MyModel.all.each do |record|
  page.should have_content record.field1
  page.should have_content record.field2
end


回答3:

If you are "verify(ing) the information given", then you use DMKE's 2nd answer. You may need to post to a login form to get a session cookie first, and use post rather than get for the form that will result in the file being downloaded.

If the result uses javascript and an iframe to download the file, then parse the returned html, extract the actual url to download the information and download the data from that.

My personal preference is to test my code against a copy of the file checked into source code control, so tests of my own code is not dependent on the foreign site being up and available. I code up a rake task / helper class to grab a fresh copy of the data as appropriate, and have some simple tests to validate I can decode the data file into something that makes sense.

If you tests are validating exactly how the data is decoded then you will want a fixed input file. If you are just validating that it "look reasonable" then you can