読者です 読者をやめる 読者になる 読者になる

capybara + poltergeist でCSVダウンロードを行う際の罠と解決法

capybara + poltergeist でCSVダウンロードを行う際の罠と解決法

GWの中日に出社して初めてのブログ投稿を行っている山口です。

さて、今回はタイトルの通りの内容で、

管理画面におけるCSVダウンロードのE2Eテストをcapybara + poltergeistで実装した際の、罠と解決法を紹介していきます。

なお、以下のコードでは管理画面へのログイン処理は別途実行済みとします。

1. visitでCSV取得を試みる

単純にvisit(またはclick)でCSVダウロードURLにアクセスし、CSVを取得を試みます。

capybara.visit('https://example.com/sample.csv') # => {"status"=>"fail"}

結果は、failとなりました。

どうやらレスポンスとしてCSVが返ってきた場合Capybaraは失敗したとみなすようです。

さて、困りました。そして、ぐぐりました。

すると、以下の記事が見つかったので言われたとおりにexecute_scriptを使ってやってみることにします。

Downloading file to specific folder using Capybara and Poltergeist driver - Stack Overflow

2. execute_scriptを使いCSV取得を試みる

まず、execute_scriptで管理画面のコンテキストでJavaScriptの関数を定義します。

(Chromeの開発者ツールのconsoleで関数定義する感じです)

その後、evaluate_scriptで定義した関数を呼び出して、CSVのデータを受け取る流れとなります。

uri = URI.parse('https://example.com/sample.csv')

js_methods = <<js_methods
window.downloadCSVXHR = function() {
  var url = window.location.protocol + '//' + window.location.host + '/#{uri.path}?#{uri.query}';
  return getFile(url);
};
window.getFile = function(url) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', url, false);
  xhr.send(null);
  return xhr.responseText;
};
js_methods

capybara.execute_script(js_methods)
csv = capybara.evaluate_script('downloadCSVXHR()')

この修正で、大半のテストはうまくいきましたが、一部失敗するものがありました。

原因を探っていくと、下記Qiitaの記事に答えがありました。

どうやら、Content-Disposition: attachement なレスポンスは取得できないみたいです。

(正確には、該当レスポンスでも取得できるケースはありました。)

PhantomJS で Content-Disposition: attachment なレスポンスを取得する方法 - Qiita

記事ではforkされたadd_download_capabilitiesを使用することで対応されたようですが、

CSV取得テストのためだけに、本流からそれるのは避けたいなと考え。考え。考えました。

ひらめきました。単純にcookie取り出して別の方法でCSV取得すればいいじゃないか。

3. Curlを使いCSV取得を試みる

というわけで、capybaraからcookie情報を取り出し、CurlでCSV取得することにしました。

curl = Curl::Easy.new

curl.headers = curl.headers.merge(capybara.driver.headers)
curl.headers["Cookie"] = capybara.driver.cookies.each_with_object([]) { |(key, value), array| array.push("#{key}=#{value.value}" }.join('; ')

curl.url = 'https://example.com/sample.csv'

curl.http_get

csv = curl.body_str

この方法で、すべてが失敗するケースはなくなり、山口に平和が訪れました。

まとめ

  • Capybara + poltergiestでCSVダウンロードするなら、cookie取り出してCurlにたのめ。
  • CSVダウンロードのテストに、Capybaraを使うべきかそもそもちゃんと考えよう。

それでは、残り少なくなってきましたが、よりよいGWをお過ごしください。