【Rails × Capybara】ファイルじゃないのに「isn't a file」エラーが出た原因と解決法
こんにちは
プログラミングスクールで Ruby on Rails を学習している、りゅうです。
卒業制作でWebアプリを作っている中で、Capybara + RSpec + Selenium (Docker環境) を使ったテスト中に
👇このようなエラーに遭遇しました。
You are trying to upload something that isn't a file
この記事では、実際にエラーが出た状況から、原因の特定、そして解決までの流れを丁寧に解説します。
同じようにCapybaraでハマっている方の参考になれば嬉しいです。
⚠️ 注意
プログラミング初心者のため、誤りがあるかもしれません。
また、環境によっては同じ手順でもうまくいかない場合があります。
もしお気づきの点があれば、コメントなどで教えていただけると嬉しいです!
💡 前提
-
capybara、rspec-rails、selenium-webdriver などのGemを導入済み
-
基本的なRSpecシステムテスト環境が整っている
-
Docker上でRailsを動かしている
🧩 使用環境(バージョン情報)
| ツール | バージョン |
|---|---|
| Ruby | 3.2.3 |
| Rails | 7.2.2.2 |
| PostgreSQL | 17.6 |
| 開発環境 | Docker |
| capybara | 3.40.0 |
| selenium-webdriver | 4.35.0 |
記事の内容
follows_spec.rbのテストが成功するまでの流れになっています。
最初のコード
↓
エラー
↓
原因の特定
↓
変更したコード
↓
結果
最初のコード
Capybara.register_driver :remote_chrome do |app|
options = Selenium::WebDriver::Chrome::Options.new
options.add_argument('no-sandbox')
options.add_argument('headless')
options.add_argument('disable-gpu')
options.add_argument('window-size=1680,1050')
Capybara::Selenium::Driver.new(app, browser: :remote, url: ENV['SELENIUM_DRIVER_URL'], capabilities: options)
end
describe "フォローの確認" do
scenario "フォローした遷移先はその場" do
other_user = create(:user)
visit users_path
within("form") do
fill_in "q_name_cont", with: other_user.name
find_field("q_name_cont").send_keys(:enter)
end
click_link "フォロー"
expect(page).to have_current_path(users_path, ignore_query: true)
end
end
エラー
Failure/Error: fill_in "q_name_cont", with: other_user.name
Selenium::WebDriver::Error::WebDriverError:
You are trying to upload something that isn't a file.
エラー文を読んでいきます
fileではないものをアップロードとしていますよとなっています。何が起きているのでしょうか?
詳しくみていきます
原因の特定
デバッグのために save_and_open_page を追加して、Capybaraが見ている実際の画面を確認します。
describe "フォローの確認" do
scenario "フォローした遷移先はその場" do
+ save_and_open_page
other_user = create(:user)
visit users_path
within("form") do
fill_in "q_name_cont", with: other_user.name
find_field("q_name_cont").send_keys(:enter)
end
click_link "フォロー"
expect(page).to have_current_path(users_path, ignore_query: true)
end
end
すると以下のログが出力されました。
2025-10-13 10:38:18 ERROR Selenium [:file_detector] File detector only works with files. "test" isn`t a file!
Capybaraが fill_in で触ろうとした要素を、Seleniumが <input type="file"> と認識 しています。そのため、"test"(=other_user.name)を入力しようとしても「これはファイルじゃない」と拒否されています。
しかし、type = "file"はテストを実行しようとしているDOM要素にはありません。
なぜ、<input type="file"> と認識しているのでしょうか?これを探りにいきます
Some bindings include a basic local file detector by default, and all of them allow for a custom file detector
— Selenium WebDriver Documentation, “Remote WebDriver”, SeleniumDev
(参照: https://www.selenium.dev/documentation/webdriver/drivers/remote_webdriver/)
「一部バインディングでは基本の Local File Detector をデフォルトで含むすべてのバインディングでカスタムのFile Detectorを設定できる」
- 言語とseleniumの翻訳の役割をしているのがバインディングというイメージで、Rubyの場合は、gem "selenium-webdriver"がバインディングになります。
file_detector が 有効なまま だと、Capybara が普通のテキスト入力をしようとする時でも、内部で「この入力値はファイルパスっぽいな?」と判断してしまうことがあるそうです。
変更したコード
file_detector を無効に設定します。
Capybara.register_driver :remote_chrome do |app|
options = Selenium::WebDriver::Chrome::Options.new
options.add_argument('no-sandbox')
options.add_argument('headless')
options.add_argument('disable-gpu')
options.add_argument('window-size=1680,1050')
+ driver = Capybara::Selenium::Driver.new(app, browser: :remote, url: ENV['SELENIUM_DRIVER_URL'], capabilities: options)
+ driver.browser.file_detector = nil
+ driver
end
結果
うまくいきました
Finished in 1.39 seconds (files took 1.3 seconds to load)
1 example, 0 failures
まとめ
file_detectorがデフォルトで有効になっていました。かつ、SeleniumがCapybaraから送られてきた値をfileと勘違いしてfile_detectorが作動したことが、エラーの原因でした。
file_detector = nilとすることで解決しましたが、どうしてfileだと誤作動を起こすのかはわかりません。詳しい人がいたら教えて頂きたいです
参考になった記事
最後に
noteで卒業制作の進捗を記録しています。
もし興味があれば、こちらも覗いてみてください!
Discussion