【結論】
・iframeタグ配下の要素は、そのままでは直接操作することが出来ない
・iframe内の要素を取得/操作するにはwithin_frame
で、iframeを明示的に呼び出す必要がある
・within_frame
のブロック内であれば、通常のCapybaraの処理でiframe内の要素を取得/操作できる
【目次】
- 経緯:CKEditorで画像アップロードするテストコードを実装したい
- 問題:iframe内の要素が操作出来ない
- 対応:within_frameでiframeを呼び出す
- 参考情報
- 《今日の学習進捗(3年以内に10000時間に向けて)》
【本題】
経緯: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 - Ruby Capybara でiframe内のボタンをクリックしたい|teratail
Rspec Capybaraで実際テストを書いて困ったシチュエーションの解消法 - Qiita
TinyMCE redux · Issue #445 · teampoltergeist/poltergeist · GitHub
《今日の学習進捗(3年以内に10000時間に向けて)》
テストを拡張していたが、JavaScriptが絡むテストコードの実装に苦慮している。
1: まず、CKEditorでの画像アップロードのテストを実装していたが、ダイアログ中の要素を取得する事が出来ない問題が発生した。 調べてみると、どうやら「iframe」で生成されている要素は「within_frame」で明示的に呼び出さす必要がある様で、それで解消した。
2: 次に、何度かテストを繰り返すと、たまにテストが失敗する問題が発生した。 expectでボタンの存在を判定してから次の処理に進む様に記述したが、それでも稀にテストがコケる事があり、最終的にsleepで次の処理に進むタイミングをズラす事で一旦解消した。 しかし、sleepの使用は推奨されていない解説なども散見されたので、他の方法を模索した方が良いかもしれない。
3: ローカルでは正常にテストが通るが、CIでは通らない問題が発生した。 調べてみると、CI環境ではCLI上でテストを実行する必要があるので、ヘッドレスドライバを使用する必要がある様だった。 現状、ChromeDriverをwebdriversでインストールしているが、サポートが終了しているchromedriver-helperでインストールして実装する記事ばかり出てきて、上手く実装することが出来なかった。 これ以上、自分で調査しても解決困難なので、週明けにCTOへ相談したい。 なお、jsのテストが全て落ちるわけではないので、別要因かもしれない。
学習開始からの期間 :252日
今日までの合計時間:2391h
一日あたりの平均学習時間:9.5h
今日までに到達すべき目標時間:2301h
目標との解離:90h
「10,000時間」まで、
残り・・・「7609時間!」