Capybaraでファイルをダウンロードするテストを書いたので備忘録
Capybaraでファイルをダウンロードすると、デフォルトのダウンロードディレクトリ(~/Downloads)にファイルがダウンロードされるため、テストがしづらい。
設定を追加して、システムテストを実行しやすくする。
まずは、Capybaraで利用するWebDriverにダウンロードディレクトリを設定する
# spec/support/capybara.rb
# frozen_string_literal: true
require 'capybara/rspec'
# 読みこんで、Capybara.current_driverの初期化を済ませる
require 'action_dispatch/system_test_case'
Capybara.register_driver(:pc_headless) do |app|
options = Selenium::WebDriver::Chrome::Options.new
options.headless!
Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end
RSpec.configure do |config|
config.before(type: :system) do |example|
driven_by(:pc_headless)
# ここ。ダウンロード先を指定する
page.driver.browser.download_path = CapybaraDownloadsHelper.path
end
end
続いて、ダウンロードファイルをテストで利用するためのヘルパーを用意する
# spec/support/xxx_helper.rb
# frozen_string_literal: true
# Capybaraでダウンロードしたファイルを管理する
module CapybaraDownloadsHelper
PATH = Rails.root.join('tmp', 'data', 'downloads').to_s.freeze
class << self
# ダウンロード先のディレクトリ
#
# @return [String]
def path
File.join(PATH, Thread.current.object_id.to_s)
end
# ダウンロードしたファイル一覧を返す
#
# @return [Array<String>]
def files
Dir[File.join(path, '*')]
end
# ダウンロードが完了したか
#
# @return [boolean] ダウンロードが完了していればtrue
def downloaded?
files.grep(/\.crdownload$/).none? && files.any?
end
# ダウンロードしたファイルを削除する
#
# @return [void]
def delete_all
FileUtils.rm_f(files)
end
end
end
RSpec.configure do |config|
config.before(:all) do
FileUtils.mkdir_p(CapybaraDownloadsHelper.path)
end
config.after(:all) do
FileUtils.rm_rf(CapybaraDownloadsHelper.path)
end
config.before do
CapybaraDownloadsHelper.delete_all
end
end
これで、簡単にテストを行うことができるようになる。
RSpec.describe 'download', type: :system do
it 'downloads file' do
find('#download_link').click
Timeout.timeout(10.second) do
loop do
break if CapybaraDownloadsHelper.downloaded?
end
end
file = CapybaraDownloadsHelper.files[0]
expect(file).to test_something
end
end