Capybaraでiframe内の要素を取得/操作する方法(Rails)
【結論】
・iframeタグ配下の要素は、そのままでは直接操作することが出来ない
・iframe内の要素を取得/操作するにはwithin_frame
で、iframeを明示的に呼び出す必要がある
・within_frame
のブロック内であれば、通常のCapybaraの処理でiframe内の要素を取得/操作できる
【目次】
【本題】
経緯:CKEditorで画像アップロードするテストコードを実装したい
以下の様な、CKEditorで画像をアップロードする際の挙動をテストするコードを実装しようとした時の話です。
問題:iframe内の要素が操作出来ない
一先ず以下の様なテストコードを書きましたが、問題箇所でコケてしまいます・・・
it '画像アップロード', js: true do visit new_path expect(page).to have_css('.cke_button__image') page.first('.cke_button__image').click expect(find('.cke_dialog_body')).to have_content('アップロード') click_link('アップロード') expect(find('.cke_dialog_body')).to have_content('サーバーに送信') file_path = Rails.root.join('spec', 'fixtures', 'test_image.png') # ここが問題箇所 page.attach_file('upload', file_path) click_link('サーバーに送信') expect(find('.cke_dialog_body')).to have_content('URL') click_link('OK') expect(page).to have_content('保存') click_button('保存') expect(all('img')[1][:src]).to include('/uploads/image/') end
以下がエラーメッセージです。
Campaigns 画像アップロード Failure/Error: page.attach_file('upload', file_path) Capybara::ElementNotFound: Unable to find file field "upload"
該当箇所にsave_and_open_page
を設置してみると、ファイル選択のアイコンが表示されていないことが分かりました
↓テスト中にダイアログ
↓本来のダイアログ
デベロッパーツールで確認してみると、このファイル選択の部分だけ、iframeで生成されていることが分かりました。
つまりiframeで後から生成される部分は、そのままでは直接操作することが出来ないという事です。
対応:within_frame
でiframeを呼び出す
調べてみると、iframeで生成される箇所は、within_frame
で明示的に呼び出す事で、テスト環境でも取得/操作が可能になる様です。
それを受けて、改修したコードがこちらです。
it '画像アップロード', js: true do visit new_path expect(page).to have_css('.cke_button__image') page.first('.cke_button__image').click expect(find('.cke_dialog_body')).to have_content('アップロード') click_link('アップロード') expect(find('.cke_dialog_body')).to have_content('サーバーに送信') file_path = Rails.root.join('spec', 'fixtures', 'test_image.png') # ここが修正箇所 within_frame(all('iframe')[1]) do file_path = Rails.root.join('spec', 'fixtures', 'test_image.png') page.attach_file('upload', file_path) end expect(find('.cke_dialog_body')).to have_content('URL') click_link('OK') expect(page).to have_content('保存') click_button('保存') expect(all('img')[1][:src]).to include('/uploads/image/') end
これで無事テストが通る様になりました!
参考情報
Method: Capybara::Session#within_frame — Documentation for jnicklas/capybara (master)
Ruby Capybara でiframe内のボタンをクリックしたい
Rspec Capybaraで実際テストを書いて困ったシチュエーションの解消法 - Qiita
TinyMCE redux · Issue #445 · teampoltergeist/poltergeist · GitHub