質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Capybara

Capybaraは、 Rubyで開発されているWebアプリケーションテストフレームワークです。Webブラウザ不要でブラウザ上のユーザー操作及びJavaScriptの挙動を自動化することができます。

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

RSpec

RSpecはRuby用のBDD(behaviour-driven development)フレームワークです。

Q&A

1回答

3454閲覧

RSpec + CapybaraでのE2EテストにてCKEditor部のfill_inでエラーが発生する

sanezane

総合スコア91

Capybara

Capybaraは、 Rubyで開発されているWebアプリケーションテストフレームワークです。Webブラウザ不要でブラウザ上のユーザー操作及びJavaScriptの挙動を自動化することができます。

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

RSpec

RSpecはRuby用のBDD(behaviour-driven development)フレームワークです。

0グッド

0クリップ

投稿2019/05/29 14:12

編集2019/05/29 15:27

#####■環境情報
ruby on rails:5.2.3
ruby:2.6.1
rspec-rails:3.8.2
capybara:3.18.0
CKEditor(cdn):https://cdn.ckeditor.com/ckeditor5/12.1.0/classic/ckeditor.js
※一旦この状態のソースをgithubへあげています。
Q&A_githubリンク

###現状の説明
Q&Aサービス風ポートフォリオを作成中。
RSpec(Capybara)でのE2EテストでCKEditorで実装しているフォームにfill_inで値を入れてもテストが失敗してしまう。以下エラーが発生
######エラー内容

Failure/Error: fill_in 'question[content]', with: question_content Capybara::ElementNotFound: Unable to find visible field "question[content]" that is not disabled

以下specファイルのfill_in 'question[content]', with: question_content部で落ちる。

ruby

1 2describe 'QandA管理機能', type: :system do 3 # ユーザAを定義 4 let(:user_a) { FactoryBot.create(:user, name: 'ユーザA', email: 'a0@email.com') } 5 6 describe '質問新規投稿機能' do 7 #ユーザAでログイン 8 let(:login_user) { user_a } 9 10 before do 11 visit new_question_path 12 fill_in 'question[title]', with: question_title 13 fill_in 'question[content]', with: question_content #ココ!!!!!!!!!!!!!!!!!!!!!!!!!!!1 14 click_button 'Save' 15 end 16 17 context '質問新規作成画面で質問を投稿する' do 18 let(:question_title) { 'test question title' } 19 let(:question_content) { 'test question content' } 20 21 it '投稿が失敗する' do 22 expect(page).to have_selector '.alert-danger', text: '質問の投稿に失敗しました。' 23 end 24 end 25 end 26 27end

#気になっているところ
CKEditorの実装が間違っているのではないか。。。というのも、ディベロッパーツールで確認してみるとCKEditorは実装できているがid:'editor'部分が別でtextareaとして残っている。そこに追加される形でCKEditorが実装されており、CKEditor部にはidは付与されていない。(しかもtextareaはdisplay:noneで隠れている)
言葉ではわかりにくいので以下にキャプチャを示します。

###現状(隠れている状態)
イメージ説明

###display:noneを外すと「質問内容」の下になんか出る!!textareaとCKEditor部は別々で表示されるもの??コレ合ってる??
イメージ説明

###現状のCKEditorの実装方法
cndを読み込んでjsファイルを作成しCKEditorを適用させたい部分にidを付与してjsを呼ぶ。
以下、jsとCKEditor適用部分のソース。

javascript

1$(function(){ 2ClassicEditor 3 .create( document.querySelector( '#editor' ) ) 4 .catch( error => { 5 console.error( error ); 6 } ); 7 config.width = 500; 8 config.height = 400; 9});

######view(slimで記述)
id:'editor'部がCKEditorを実装している部分。

html

1= form_with model: @question, local: true do |f| 2 = f.hidden_field :user_id, { value: current_user.id} 3 = f.hidden_field :author, { value: current_user.name} 4 .form-group 5 label 6 | Title 7 = f.text_field :title, class: "form-control" 8 .form-group 9 label 10 | 質問内容 11 = f.text_area :content, class: "form-control",id:'editor' 12 / = f.text_area :content, class: "form-control" 13 .text-center 14 = f.submit "Save", class: "btn btn-primary mt-3" 15div 16 = link_to '> Home', root_path, class: 'btn btn-outline-primary mb-3 ml-3'

####「CKEditor RSpec」でググっても私と同じ事象で困っている記事が出てこないためご指摘頂ければ幸いです。

5/29追記
teratailのCKEditor見たらちゃんとtextareaになっている。。。やはりCKEditorの実装に問題があるぽい。質問のタイトルも変えるべきか。。
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

こんにちは。
ちょっと間違っているかもしれませんが、同じようにCKEditorの動きを確認する機会があったので、それを踏まえてコメントしますね。

アプリケーションがRailsの前提でお話します。

id="editor" に対しての操作ができない理由

本来のtextareaに対して、確かCKEditorは以下のように働きます。

  1. 本来のフォームを描画(RailsのViewでのレンダリング)
  2. 非同期であとからCKEditor用のJSの処理が呼び出される

 (私の手元のではiframeを使っていましたが、そうではないかもしれません)
3. 本来のフォームはdisplat: noneで非表示にする(CKEditor側がそのように変更する)
4. CKEditor側のメニュー・入力フォームを差し替えて有効な状態にする

Seleniumは要素が非表示だと、セレクタで指定しようとしても操作ができなくなります。
なので、<textarea id='editor'></textarea> はHTML上では存在しているけれど、Seleniumから操作ができないということになります。

一方で、じゃあCKEditorの入力したデータはなぜサーバ側に正しく渡るのかというと、Submitの時にCKEditorのテキストエリアの入力値を、本来の id="editor" のデータに差し替えて送信しているからです。

CKEditorのテキストエリアにSelenimで値をセットするにはどうするの?

では、CKEditor側のテキストエリアに文字をセットできればきっと大丈夫...というところですが、どう指定するといいのか?

いくつか方法があります。

(1) Seleniumのレコーディング機能を使って、いったん手動で目的の操作を実行する。

その際に、実行記録がテストケースとして自動で書き出されますので、それをもとにどんな操作をしているのかを判定する。

以下のような感じになります。

イメージ説明

CKEDitorのテキストエリアに文字を入力している部分は、Selenium IDEのコマンド的には"edit content" で、セレクタは class=.cke_edittable です。
お手元の環境だと、ここがどれに当たるかは若干違うかもしれないので、同じようにレコーディングをしてみてセレクタがどこにあたるかを特定するといいと思います。

同じようなクラスを持った要素がもしたくさんあったとして、できるだけ絞り込めるようにするといいので、おそらく class=.cke_edittable cke_xxxx cke_xxxxxx みたいなものかと思います。

また、レコーディングした処理はエクスポートが可能です。

https://www.seleniumhq.org/selenium-ide/docs/en/introduction/code-export/
https://chrome.google.com/webstore/detail/selenium-ide/mooikfkahbdckldjjndioackbalphokd (今回キャプチャに利用したもの)

(2) edit content が使えない場合

さて、レコーディングした結果だと、edit content というコマンドを使っているのですが、Capybaraでspecを書く場合、これに対応する操作が見当たらない、実行できないかもしれません。
(細かくAPIドキュメントを読んでいないのですみません)

もしうまくいかない場合は、Capybaraの処理の中で、「HTMLの要素に対しいてキーやマウス入力をさせる」のではなくて、「JavaScriptを実行してCKEditorのテキストエリアに値をセットする」という操作で代用できます。

CKEditorは、CKEDITOR.instances という形でJavaScriptから特定できます
テキストエリアであれば、おそらく CKEDITOR.instances.editor に値を設定できればいいと思います。

Exp. CKEDITOR.instances.editor.setData('なにかの値');

Capybaraの処理の中でここをどう書くかですが、page.execute_script( ... JavaScript ... ); で実行できると思います。

以下も参考になるかと思います。

https://stackoverflow.com/questions/10957869/how-to-fill-ckeditor-from-capybara-with-webkit-or-selenium-driver

長くなりましたが、全く外していましたらご容赦くださいませ...。

追記

CKEditor not definedの件

まず、developmentモードではただしくCKEditorが表示される場合。
testモードでCapybaraでのE2Eテストをする際に、ヘッドレスモードにしていますか?
もしCIではなくローカル開発環境で実行しているようでしたら、可能だったらブラウザが開いて自動で操作が進むなか、CKEditorが描画されるところまでいっているか眺めてみてください。

描画されない場合:CKEditorの設定を確認
描画される場合:テストをwaitさせてみる

自動でテストの場合はブラウザでの読み込みが完了する前にテストのステップが進行してしまうので、「そんな要素は無いよ」といったエラーになることがあります。
CKEditorは上記の通りAjaxで後追いで読み込まれるので、操作をする少し前に、sleep処理を挟んだりAjax処理が完了するのを待つ処理を入れたりするといいのかもしれません。

CKEditorではないのですが、わたしもAjaxの処理を待つ関係で以下のような処理を入れています。

参考:RSpec+Capybaraでajaxとかcssとかを待つ

JSを使わない方法

Capybara + CKEditor + RSpecだと情報が少ないかもしれませんが、CKEditor + Selenium だと、もう少し情報が出てきそうです。
ちょっと探したら以下のようなものがありました。

Pythonのコードですが、page.execute_script() ではなく一般的な「HTMLの要素を見つけてそこにテキストをセットする」方法です。

本来はこちらのほうが自然な気はしますね。
https://bangladroid.wordpress.com/2016/08/20/switch-to-ckeditor-in-selenium-python/

やり方としては、Capybaraでの page が現在のメインのページを表しているので、以下の流れになっています。

  • 念の為CKEditorが描画されるまで少し待つ(ここでもsleepで待っている感じです)
  • CKEditorを描画しているiframe側に操作対象を移す
    • ブラウザで表示の際、CKEditorを描画しているifarmeがありませんか?ターゲットはそこになります
  • 操作対象をiframeに切り替え、その中の body (CKEditorのテキストエリア部分)を特定する
  • editor_body.send_keys("Test Body") を実行
  • 入力後 iframeから外れる場合は操作対象を切り替え

まだ手元では試していないのですが、わたしも知っておいてこれは良さそう!と思いましたので、やってみようと思います。(ソースありがとうございます!)
もしよければ試してみてくださいね。

投稿2019/05/29 23:51

編集2019/05/30 23:41
suama

総合スコア1997

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sanezane

2019/05/30 15:27

まず、とても丁寧に回答していただきまして有り難うございます。感動してます。。 やはりtextareaはdisplay:noneになるんですか!コレは正しかったんですね。 JavaScriptに依存しているんですね。Capybaraでjavascriptを実行するとのことで提示していただいたサンプルを参考に実装してみました。その中で疑問があり、関連記事がなかなか見つからなかったのでお聞きしたいのですが、`CKEDITOR is not defined`というエラーが出ましてエラー内容から読み解くとCKeditorのjsを何かしらの形でspecへ読み込む必要があると思うのですが、suamaさんはどのように解決しましたか?
suama

2019/05/30 23:40

ソースを拝見したら、RailsのSystemTestなんですね。こちらこそ参考になります! JSの読み込みなどで遅延があるかもしれないので、ちょっと追記をしてみました もし外していたらすみません。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問