Top View


Author yoshitake

cypressを使ったE2Eテストの自動化〜iframeの要素取得とTinyMCEへの文字入力編〜

2018/12/04

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つのポイント

  1. .type()が使えない。
  2. テキスト入力する前に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) =&gt;{
 const doc = $iframe.contents();
 cy.wrap(doc.find('#tinymce')).click();
 cy.wrap(doc.find('#tinymce')).invoke('text','hoge');
 });

おわりに

以上です。
iframeとTinyMCEへの入力ができて、業務的にもとても助かりました。
もし他にもっといいやり方があれば教えていただけると嬉しいです。

ありがとうございました。

yoshitake

yoshitake

Twitter X

主にテストをしています。