■環境情報
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
部で落ちる。
describe 'QandA管理機能', type: :system do
# ユーザAを定義
let(:user_a) { FactoryBot.create(:user, name: 'ユーザA', email: 'a0@email.com') }
describe '質問新規投稿機能' do
#ユーザAでログイン
let(:login_user) { user_a }
before do
visit new_question_path
fill_in 'question[title]', with: question_title
fill_in 'question[content]', with: question_content #ココ!!!!!!!!!!!!!!!!!!!!!!!!!!!1
click_button 'Save'
end
context '質問新規作成画面で質問を投稿する' do
let(:question_title) { 'test question title' }
let(:question_content) { 'test question content' }
it '投稿が失敗する' do
expect(page).to have_selector '.alert-danger', text: '質問の投稿に失敗しました。'
end
end
end
end
気になっているところ
CKEditorの実装が間違っているのではないか。。。というのも、ディベロッパーツールで確認してみるとCKEditorは実装できているがid:'editor'
部分が別で
textareaとして残っている。そこに追加される形でCKEditorが実装されており、CKEditor部にはidは付与されていない。(しかもtextareaはdisplay:none
で隠れている)
言葉ではわかりにくいので以下にキャプチャを示します。
現状(隠れている状態)
display:noneを外すと「質問内容」の下になんか出る!!textareaとCKEditor部は別々で表示されるもの??コレ合ってる??
現状のCKEditorの実装方法
cndを読み込んでjsファイルを作成しCKEditorを適用させたい部分にidを付与してjsを呼ぶ。
以下、jsとCKEditor適用部分のソース。
$(function(){
ClassicEditor
.create( document.querySelector( '#editor' ) )
.catch( error => {
console.error( error );
} );
config.width = 500;
config.height = 400;
});
view(slimで記述)
id:'editor'
部がCKEditorを実装している部分。
= form_with model: @question, local: true do |f|
= f.hidden_field :user_id, { value: current_user.id}
= f.hidden_field :author, { value: current_user.name}
.form-group
label
| Title
= f.text_field :title, class: "form-control"
.form-group
label
| 質問内容
= f.text_area :content, class: "form-control",id:'editor'
/ = f.text_area :content, class: "form-control"
.text-center
= f.submit "Save", class: "btn btn-primary mt-3"
div
= link_to '> Home', root_path, class: 'btn btn-outline-primary mb-3 ml-3'
「CKEditor RSpec」でググっても私と同じ事象で困っている記事が出てこないためご指摘頂ければ幸いです。
5/29追記
teratailのCKEditor見たらちゃんとtextareaになっている。。。やはりCKEditorの実装に問題があるぽい。質問のタイトルも変えるべきか。。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
+1
こんにちは。
ちょっと間違っているかもしれませんが、同じようにCKEditorの動きを確認する機会があったので、それを踏まえてコメントしますね。
アプリケーションがRailsの前提でお話します。
id="editor" に対しての操作ができない理由
本来のtextareaに対して、確かCKEditorは以下のように働きます。
- 本来のフォームを描画(RailsのViewでのレンダリング)
- 非同期であとからCKEditor用のJSの処理が呼び出される
(私の手元のではiframeを使っていましたが、そうではないかもしれません) - 本来のフォームはdisplat: noneで非表示にする(CKEditor側がそのように変更する)
- 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 ... ); で実行できると思います。
以下も参考になるかと思います。
長くなりましたが、全く外していましたらご容赦くださいませ...。
追記
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から外れる場合は操作対象を切り替え
まだ手元では試していないのですが、わたしも知っておいてこれは良さそう!と思いましたので、やってみようと思います。(ソースありがとうございます!)
もしよければ試してみてくださいね。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.18%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2019/05/31 00:27
やはりtextareaはdisplay:noneになるんですか!コレは正しかったんですね。
JavaScriptに依存しているんですね。Capybaraでjavascriptを実行するとのことで提示していただいたサンプルを参考に実装してみました。その中で疑問があり、関連記事がなかなか見つからなかったのでお聞きしたいのですが、`CKEDITOR is not defined`というエラーが出ましてエラー内容から読み解くとCKeditorのjsを何かしらの形でspecへ読み込む必要があると思うのですが、suamaさんはどのように解決しましたか?
2019/05/31 08:40
JSの読み込みなどで遅延があるかもしれないので、ちょっと追記をしてみました
もし外していたらすみません。。