この記事はSelenium/Appium Advent Calendar 2014の8日目の記事です。ネタを考えねばといいつつ何も考えてなかったので、小ネタになりました。
Selenium WebDriverによる要素の取得
Selenium WebDriverは、JSON Wire Protocolを介して、表示されている要素の取得や、操作を行うことができます。
表示されている要素の取得は、
/session/:sessionId/elementや/session/:sessionId/elementsに対してPOSTすることで、POSTした条件に当てはまる要素のidが取得できます。elementとなっている方は、当てはまる最初の要素を、elementsは全部を配列として返してきます。
このidは、html上のidとは関係なく、Selenium Serverが内部の管理用に割り当てたものとなります。
また、当てはまるものがなければ、elementはNoSuchElementというエラーを返し、elementsは空の配列を返します。
要素に対する操作
取得した要素に対して操作は、たとえばclickでしたら、/session/:sessionId/element/:id/clickにPOSTをすることでできます。この:id
は先ほどの要素の取得で取得したid
を指定します。
このように、一般的なSelenium WebDriverによるブラウザの操作は、要素を検索し、そのidを取得し、そのidに対して何か操作をするようになっています。
ElementNotVisible エラー
しかし、この要素に対して操作した場合に、ElementNotVisibleエラーが出ることがあります。これが本エントリーの本題です。
ElementNotVisible は文字通り、HTML上にはElementが存在するのだが、ユーザに見えるような状態になっていないので、そんな操作ユーザできないよ!というように、Selenium Serverがその要素に対する操作をブロックするために生じるエラーです。
なら、そもそも取得する際に、visibleでない要素は除外して欲しいとも思うのですが、そうするともろもろ不便な感じもします。
テスト内で、要素がいくつ表示されているというようなassertionを書く時には、かならずその要素がvisibleであるかということをきちんとチェックしておく必要があります。
visible かどうかは、/session/:sessionId/element/:id/displayed によって取得することができます。
visible になる条件
さて、要素がvisibleになるならないはどのような条件でそれが判定されるのでしょうか?
一般的な場合、あまりvisibleとならなかった原因を追う必要はなく、「○○が表示されない」というようなバグチケットを切るだけでよいとは思います。ですが、一見表示されているように見えるんだけど ElementNotVisible エラーになる場合とか、特にファイルアップロードをサポートするようなJSライブラリが内部的にもっている要素に対して無理やり操作を行なってファイルアップロードしたい(細かすぎるw)というような場合がたまにあるので知っていて損はないと思います。
先ほどのJSON Wire Protocolの仕様のElementNotVisibleでは、
If the referenced element is not visible on the page (either is hidden by CSS, has 0-width, or has 0-height)
と単純に書いてあるのですが、JSON Wire Protocolをちゃんと整形したWebDriver APIの仕様としては、もうちょっと細かく書いてあります。
各htmlタグそれぞれに関して細かいことはありますが、簡単に要約するとたいてい以下のどれかに該当するような場合にvisibleではないと判定されます。
- 表示位置が、負の値になっている場合
- css的に、hiddenやdisplay:none になっている場合
- width や height が 0より大きくない場合
これは、現在の実装をコードとして読んだ方が、逆にどういうのかわかりやすかったりするかもしれないですね。
まとめ
基本的に、ユーザの操作を自動化するようなテスト等においては、visibleかどうかを気にする必要はないのですが、たまに必要になることはあります。その際何がどうだからvisibleではないのかということを特定すると、何が間違っているかというような対応も素早くなります。
それでは楽しいSeleniumライフを。
明日は @isaac-otao さんです。