cypressを使ったE2Eテストの自動化〜iframeの要素取得とTinyMCEへの文字入力編〜
2018/12/04
Table of Contents
Cypressでのiframe要素の取得方法
iframeは、インラインフレーム要素を作る際に使用されるタグのことです。
HTMLの中にHTMLを入れ子で埋め込むことができます。
今回、テスト対象にiframeが使われいたため、その要素を取得しようとしていました。
すると…
Iframes
Issue #136
You cannot target elements or interact with anything in an iframe – regardless of it being a same domain or cross domain iframe.
なんと!Cypressではiframeの要素取得についてはサポートしていないとのこと。。。
これは詰んだと思いながらもとりあえず#136のissueを見てみると。
Cypress actually injects to forcibly enable it to access same domain
and even sub-domain but there is an artificial limitation in the driver code where it get’s confused when elements are returned and they’re not bound to the top frame of your application.
とのことで、一応同じDomainの場合は動かせるとのことでした。
CypressではChromeを使っている都合上難しい問題みたいですね。
CypressでTinyMCEを使う
TineMCEとは?
TinyMCE | The Most Advanced WYSIWYG HTML Editor
TinyMCEとは、プラットフォームに依存しないウェブベースのエディターです。
↑の公式サイトで、実際に動作を確認することができます。
TinyMCEをWebページで使う場合、iframeで埋め込むそうです。
Cypressでiframeを使うことができるのは先程確認しましたが、TinyMCEのEditorに文字を入力するのが個人的に悩んだポイントでした。
CypressでTinyMCEに文字入力するには?
実装したコードは以下です。
※ 以下を参考にしました。
E2E tests: Cypress not using type() properly on contenteditable elements · Issue #4089 · WordPress/gutenberg · GitHub
cy.get('iframe').then(($iframe) =>{
const doc = $iframe.contents();
cy.wrap(doc.find('#tinymce')).click();
cy.wrap(doc.find('#tinymce')).invoke('text','hoge');
});
cy.get('iframe')
でiframeの要素を取得し、
その要素のidがtinymceのものをクリックしたあと、そのidに対してhogeを入力しています。
※ idについては、TineMCEのDefaultのbody idが’tinymce’になってるので、変更した場合はそのbody idを記述してください。
TinyMCEにテキストを入力するための2つのポイント
.type()
が使えない。- テキスト入力する前に1度要素をクリックしたほうが良い
1つ目: .type()が使えない
TinyMCEはEditorにテキストを入力すると、<p>hoge</p>
といったかんじで、HTML要素が追加されていくしようになっているようです。
<input>
ではないので、.type()
が使えないです。
なので、4行目のようにinvoke()
でHTML Contentとして入力したいデータを追加する必要があります。
※ 参考
invoke | Cypress Documentation
type | Cypress Documentation
2つ目: テキスト入力する前に1度要素をクリックしたほうが良い
上記コードでは、3行目にあるcy.wrap(doc.find('#tinymce')).click();
の部分ですね。
別にこのコードがない状態でも、Editorにテキストを入力することができます。
ただ、これだと文字数がうまいことカウントされません。
なので、Editorへの入力が必須というバリデーションがある場合は、その先に進むことができなくなります。
また、ユーザーが実際にEditorを使う場合は、必ずTinyMCEを一度クリックするので、このコードのほうがよりユーザの操作に合致しているとも思います。
おまけ id: tinymce
が複数ある場合
本当はid変更したほうが良いと思うんですけどね。
もし#tinymce
というidが複数ある場合は以下のようにthenの部分をeachに変えると解決します。
(全部の要素にhogeが入力されます)
cy.get('iframe').each(($iframe) =>{
const doc = $iframe.contents();
cy.wrap(doc.find('#tinymce')).click();
cy.wrap(doc.find('#tinymce')).invoke('text','hoge');
});
おわりに
以上です。
iframeとTinyMCEへの入力ができて、業務的にもとても助かりました。
もし他にもっといいやり方があれば教えていただけると嬉しいです。
ありがとうございました。