SeleniumでJavaScriptを使う方法いろいろ(変数・関数などの利用)
Selenium(Selenium Core, Selenium IDE, Selenium RC など)でテストケースを書く場合、かゆいところに手を届かせたい時に是非とも利用したいのがJavaScriptです。
しかし、まだまだその情報が気軽に手に入らないのが残念なところ。 「ないなら書いてしまえ!」ということでSeleniumでJavaScriptを利用したい場合に使える方法をまとめてみることにしました。
逆引き辞典にしたいのかリファレンスにしたいのかわけがわからんカテゴライズになっていますが、少しづつ増やしていくので気長にお待ちください。 使用バージョンはSelenium 1.0です。
目次
JavaScript基本編
- Selenium空間とページ空間の違いによるJavaScriptの使い分け
- JavaScriptによるDOM指定でエレメント(要素)を特定する
- 各種コマンドの入力欄にJavaScriptを使う「javascript:{式}」
- Selenium内JavaScript実行用コマンド「getEval」
- ページ内JavaScript実行用コマンド「runScript」
変数・情報の取得
- JavaScriptでSelenium内に変数を保存する
- JavaScriptでSelenium内に保存した変数を参照する
- seleniumオブジェクトの参照は「this」でもOK?
- ページ管理オブジェクトを取得する
- JavaScriptでページ内のwindowオブジェクトを取得する
- JavaScriptでページ内のdocumentオブジェクトを取得する
- JavaScriptでページ内の変数を参照する
- JavaScriptでページ内の変数を参照してSelenium内に保存する
- JavaScriptでページ内の要素を参照してSelenium内に保存する
条件判断・待機
- JavaScriptの実行結果と指定した値を比較する「assertEval」
- JavaScriptの実行結果が指定した値になるまで待つ「waitForCondition」
- if文(条件分岐)で特定のテスト範囲をスキップする「flowControl」
関数
ログ
サードパーティー製品との連携
JavaScript小技編
JavaScript基本編
Selenium空間とページ空間の違いによるJavaScriptの使い分け
SeleniumでJavaScript命令を利用する場合、実行されるスクリプトがどのオブジェクトを基準に実行されているかを知っておくことは重要です。
実際は、以下のようにテスト開始時にはseleniumオブジェクトインスタンスの中にいます。 このseleniumオブジェクトインスタンスの中(以下:selenium空間と呼びます)からは基本的にテストするページウィンドウなどは見えません。
ただ、seleniumオブジェクトにはページウィンドウやテストページ内の要素を参照したりコントロールしたりする専用の関数がたくさん入っていますので、関数を利用してページをテストしていくことができます。 関数の中には、seleniumオブジェクト内でJavaScriptを実行させるものから、ページ管理オブジェクトであるbrowserbotオブジェクトを参照したり、テストページ内に直接<script>タグを埋め込んでJavaScriptを実行したりできる命令もありますので、多彩な機能をもったテストケースの作成が可能になります。
以下の図は、SeleniumでJavaScriptを利用する際にJavaScriptでアクセス可能な領域とアクセス方法を簡単なイメージにまとめたものです。 実体験からイメージしたものなので、正確さは保証できかねますが、理解しやすくするための基本図として見ておいていただけたらと思います。
JavaScriptによるDOM指定でエレメント(要素)を特定する
Seleniumの要素指定(Element Locator)では、ID指定、XPath指定、DOM指定など、さまざまな方法が使えます。JavaScript式は以下のようにdocumentやdom=で書き始めることでDOM指定になります。
コマンド | 対象 | 値 |
---|---|---|
type | document. |
鈴木太郎 |
assert |
document. |
regexp:.+の写真$ |
click | dom=function foo() { return document.links[0]; }; foo(); //最初のリンクをクリック |
各種コマンドの入力欄にJavaScriptを使う「javascript:{式}」
ドキュメントマニュアルにもあるように「全てのSeleniumコマンドのパラメータには完全なJavaScriptの記述も使えるし、代わりに簡単な方法でも指定することができます」。 要素を指定するところは重要な部分なので、例えば’click’コマンドでは要素指定をJavaScriptでどうやるんだろう?と悩んでいらっしゃると思います。
簡単な方法として、入力欄に’javascript{式}‘を使って、正式なSeleniumの要素指定文字列を生成することができます。 これには要素のID指定、CSS指定、XPath指定を対象にすることができます。 例えば、コマンドの対象欄に要素をIDで指定するための「id=myButton」をJavaScriptを使って行いたい場合は、JavaScriptでどんな方法を使ってもいいから「id=myButton」という文字列を生成すれば良いということになります。 極端に書くと「javascript{[“id=”,”my”,”Button”].join(”)}」という書き方でもOKです。
以下の4つはどれも同じ動作(ID属性にmyButtonが指定してある要素をクリック)をします。
コマンド | 対象 | 値 |
---|---|---|
click | myButton | |
click | id=myButton | |
click | javascript{[‘id=’,’my’, |
|
click | javascript{var a = ‘id=’; var b = ‘myButton’; var c = a + b;} |
ワンポイント講座
- JavaScriptの記述が複数の処理記述を含む場合は、最後に実行された処理の値が使われます(上の4番目がそれです)。
- JavaScript記述のデバッグを行いたい場合は「getEval」コマンドを使ってください。
Selenium内JavaScript実行用コマンド「getEval」
getEvalコマンドはテスト中のブラウザウィンドウやページとは異なる、seleniumオブジェクト内でJavaScriptを実行させるコマンドです。ですので、このコマンドを使って「hoge= 100;」とした場合、seleniumオブジェクト内にhoge変数が定義されたことになります。
以下のように複数の処理を一度に書くこともできます。
コマンド | 対象 | 値 |
---|---|---|
getEval | myMoney = 10000; yourMoney = 200; |
(肝心の「テスト中のwindowオブジェクト」や「テスト中のdocumentオブジェクト」を参照して利用したい場合は、getCurrentWindow()やgetDocument()を使って取得する必要があります。)
getEvalコマンドの使いどころとしては、変数や関数をseleniumオブジェクト内に作成して利用したり、windowオブジェクトを取得して自作のオブジェクトをコントロールしたり、store系のコマンド(storeValue, storeEvalなど)で格納された変数を再利用したりと、多彩な使い方ができます。
コマンド | 対象 | 値 |
---|---|---|
getEval | myName = ‘鈴木太郎’; |
ページ内JavaScript実行用コマンド「runScript」
runScriptコマンドは、現在テスト中のウィンドウのbody内に新しく<script>タグを生成します。このコマンドを利用することでgetEvalコマンドを使ったスクリプト実行よりも簡単にテストページ内の状態をデバッグすることができます。
注意点として、runScriptによって生成された<script>タグ内の例外処理はSeleniumで管理することができないので、スクリプトが例外を投げる可能性がある場合は、そのスクリプトをtry/catchブロックで囲って独自に処理してください。 また、runScriptコマンドは使うたびにページ内に<script>タグが追加されていくので、ご利用は計画的に。
コマンド | 対象 | 値 |
---|---|---|
runScript | var elem = document. |
変数・情報の取得
JavaScriptでSelenium内に変数を保存する
何はなくとも変数の保存!ということで、JavaScriptでselenium空間内に変数を保存する場合は基本的にgetEvalコマンドが利用できます。
varなし
varをつけずに保存すると永続的な変数保存になり、コマンドをまたいで利用できるのはもちろん、テストスイートにおいてもテストケースをまたいで利用することもできます。
コマンド | 対象 | 値 |
---|---|---|
getEval | hoge = 100; |
varあり
varを使うと一時的な変数保存になり、実行しているコマンド内では有効ですが、次のコマンドに移ると消えてしまうので注意してください。
以下のテストケースでは、1つめのコマンドは正常に実行されますが、2つめのコマンドはaがすでに消えているためエラーになります。
コマンド | 対象 | 値 |
---|---|---|
getEval | var a = 100; var b = a; | |
getEval | c = a; //エラーになります |
storedVarsを使わせてもらう
テスト実行時に生成されるグローバルオブジェクトstoredVarsはstore系のコマンド(storeText, storeValueなど)で取得した情報を格納しておくことができます。 このstoredVarsにJavaScriptを使って情報を格納することができるコマンドがstoreEvalコマンドです。 storeEvalコマンドでは、最後に実行された処理結果が情報として格納されます。
以下の例は名前の文字列を「myname」というキーでstoredVarsオブジェクトに格納するテストケースです。
コマンド | 対象 | 値 |
---|---|---|
storeEval | var sei = ‘鈴木’; var mei = ‘太郎’; sei + mei; | myname |
以下の処理と同等に考えてもらうと良いかと思います。
var sei = '鈴木'; var mei = '太郎'; storedVars['myname'] = sei + mei;
store系のコマンドはJavaScriptを活用しないぶんには便利な命令ですが、varあり、varなし変数定義の例のようにJavaScriptを使って直接変数に格納できる方法を知ってしまうと、あまり使わなくなってくるコマンドかもしれません。
保存した変数を参照する
getEvalコマンドやstoreEval、その他store系のコマンドで保存された変数を利用する場合もgetEvalコマンドが有効です。
以下の例は、事前にあいさつ文を用意しておいて(1)、ページ内のOKボタンをクリック後(2)、姓名入力欄の情報を取得して一時保存し(3)(4)、入力された姓名文字列とあいさつ文を組み合わせて再度変数に格納(5)するテストケースです。 storeValueコマンドを強引に使っているように見えますが、説明を分かりやすく表現してみた結果です。
コマンド | 対象 | 値 |
---|---|---|
getEval | footer = ‘です。 よろしくお願いします。’; | |
click | ok-button | |
storeValue | last-name | lname |
storeValue | first-name | fname |
getEval | greeting = storedVars[‘lname’] + storedVars[‘fname’] + footer; |
seleniumオブジェクトの参照は「this」でもOK?
runScriptコマンドのような例外は除いて、通常はselenium空間の中でJavaScriptが実行されていますので、thisはseleniumオブジェクトのことを指します。 ですのでgetEvalコマンドなどでJavaScriptを実行する場合やassertEvalコマンドでチェックしたりする場合はthisが使えます。(runScriptコマンドでthisを使うと、テスト中のページのwindowオブジェクトを参照していることになるので注意してください。 場合によっては便利なこともありますが。)
以下の例はgetEvalコマンドでseleniumオブジェクトを取得するテストケースです。
コマンド | 対象 | 値 |
---|---|---|
getEval | seleniumObj = this; |
ページ管理オブジェクトを取得する
seleniumオブジェクト内には、テストするページを監視するbrowserbotオブジェクトがあります。 このbrowserbotオブジェクトの中にはテスト中のページのwindowオブジェクトを取り出したりdocumentオブジェクトを取り出したりできる便利な命令が入っているので、JavaScriptをテストケースに利用したい場合は事前に取得しておくと良いでしょう。 以下の例はbrowserbot取り出し専用命令「selenium.page()」と、直接指定して取り出す「selenium.browserbot」指定方法の2種類を実行しているテストケースです。
コマンド | 対象 | 値 |
---|---|---|
getEval | bot = selenium.page(); | |
getEval | sameBot = selenium.browserbot; |
もちろん、getEvalコマンドの中では「seleniumオブジェクト == this」ですから、thisに置き換えても動作は変わりません。
コマンド | 対象 | 値 |
---|---|---|
getEval | bot = this.page(); | |
getEval | sameBot = this.browserbot; |
JavaScriptでページ内のwindowオブジェクトを取得する
Selenium実行中の空間では現在テスト中のページのwindowオブジェクトを「this.page().getCurrentWindow();」で取得することができます。 selectWindowコマンドでテスト中のウィンドウを切り替えた場合は、変更後のwindowオブジェクトを返します。何度も使いそうな場合はgetEvalコマンドで事前に変数に入れておくと良いでしょう。
以下の例は、現在テスト中のページのwindowオブジェクトを変数に格納しているテストケースです。
コマンド | 対象 | 値 |
---|---|---|
getEval | win = this.page(). |
JavaScriptでページ内のdocumentオブジェクトを取得する
テスト中のdocumentオブジェクトを取得する場合は、selenium空間内で「this.page().getDocument();」を使います。 また、windowオブジェクトをgetCurrentWindow()で取得した後、通常通りdocumentオブジェクトを参照する方法もあります。 以下の例ではdocumentオブジェクトを2種類の異なる方法で取得しています。
コマンド | 対象 | 値 |
---|---|---|
getEval | doc1 = this.page(). |
|
getEval | doc2 = this.page(). |
条件判断・待機
JavaScriptの条件文と指定した値を比較する「assertEval」
SeleniumでJavaScriptを使って条件判断を行う場合はassertEvalコマンドを使います。 かなり便利な命令で、事前に取得しておいた変数と現在の状況を比較する場合など、使いどころも多いかと思います。
以下の例は、現在テスト中のdocumentオブジェクトを2通りの方法で取得して、同じものかどうかチェックするテストケースです。 このテストケースは問題なく通ります。
コマンド | 対象 | 値 |
---|---|---|
getEval | doc1 = this.page(). |
|
getEval | doc2 = this.page(). |
|
assertEval | doc1 == doc2 | true |
JavaScriptの実行結果が指定した値になるまで待つ「waitForCondition」
waitForConditionコマンドはJavaScriptで条件を指定しておいて、それが指定しておいた値になるまで待機します。 これも様々な場面で活躍してくれるコマンドで、例えば非同期データ通信のAjaxでデータを送信した場合に、受信が完了して画面が変わるまで待機させたり、自分が作成しておいたページ内のオブジェクトがある状態になるまでテストを待機させておいたりすることができます。
以下のテストケースは、windowオブジェクトを取得(1)後、自作しておいたページ内のメッセージ管理オブジェクトにメッセージリストを読み込ませて(2)、読み込みが完了するのを待って(3)、メッセージが入っているかどうか(4)をテストする例です。
コマンド | 対象 | 値 |
---|---|---|
getEval | win = this.page(). |
|
getEval | win.messenger. |
|
waitFor |
win.messenger. |
10000 |
assertEval | win.messenger. |
true |
関数
JavaScriptでページ内の関数を実行する
ページ内に作成しておいたJavaScriptカスタム関数を実行するには、ページのwindowオブジェクトを取得すれば簡単です。
例えば、windowオブジェクトに事前に定義しておいた、データの数を取得する関数を呼び出すには以下のようにします。
コマンド | 対象 | 値 |
---|---|---|
getEval | win = this.page(). |
|
getEval | var dCount = win. |
テストケース実行中に関数を作って実行する
例えば、データを新規追加したあとで、本当に追加されたのかを確認したい場合など、処理実行前と実行後で結果がどう変わったかをテストしたいケースがありますね。
こういうときには事前にカスタム関数を作っておいてすぐに実行できるようにしておくと便利です。 以下の例は、自作のデータコントローラーオブジェクトからデータの数を取得するための関数をテスト中に定義して、データ追加前と追加後で1増えたかどうかを確認するテストケースの例です。
コマンド | 対象 | 値 |
---|---|---|
getEval | win = this.page(). |
|
getEval | //データ数取得関数 dc = function(){ return win. |
|
getEval | count = dc(); | |
getEval | win.myDataController. |
|
assertEval | dc() == count + 1 | true |
Seleniumに外部JavaScriptファイル(.js)を読み込んで関数を実行する
外部JavaScriptファイルをSelenium内で利用する場合は以下の2つの方法があります。
- 「user-extensions.js」というファイルを作成して、そのファイルをSeleniumに指定する方法
- Selenium IDEの設定画面で「Selenium IDE拡張スクリプトのパス」欄に任意の外部JavaScriptファイルを指定する方法
「user-extensions.js」というファイルを作成して、そのファイルをSeleniumに指定する方法
これは、selenium coreの指定フォルダの中にuser-extensions.jsファイルを配置する方法です。 Cドライブ直下にselenium coreをインストールした場合は「C:selenium-corecorescripts」が該当フォルダになります。
selenium coreをインストールすると自動的に空っぽのファイルができていますので、これを編集するか、あるいは自分で独自に作成して置き換えればOKです。
Selenium IDEの設定画面で「Selenium IDE拡張スクリプトのパス」欄に任意の外部JavaScriptファイルを指定する方法
selenium IDE上でテストを行っている場合は、テスト実行時に任意のJavaScriptファイルを利用することができます。
selenium IDEの「オプション」メニューから「設定…」を選び「一般」タブを選択すると、任意のJavaScriptファイルを指定することができる欄と、user-extensions.jsファイルを任意の場所から指定することができる欄がありますので、ここで自作のJavaScriptファイルやuser-extensions.jsファイルを指定すると良いでしょう(selenium
IDEには、すでにselenium coreが含まれています)。
user-extensions.js
/** * ページ内のリンクテキストを全て太字にする */ function setAllLinksToBold() { var win = selenium.page().getCurrentWindow(); //現在のページウィンドウを取得 var links = win.document.getElementsByTagName('a'); var len = links.length; for (var i=0; i<len; i++) { links[i].style.fontWeight = 'bold'; } }
コマンド | 対象 | 値 |
---|---|---|
getEval | setAllLinksToBold(); |
ログ
JavaScriptでログウィンドウにログを出力させる
自分でもログウィンドウにログを出力させることができます。 seleniumではテスト実行時にグローバルオブジェクト「LOG」が生成されます。 この中にdebug(), info(), warn(), error(), exception()という関数群が用意されていますので、状況に応じて使ってみると良いでしょう。
出力するログのレベルを調節できるsetBrowserLogLevelコマンドですが、テストケースに組み込んでもエラーが発生したので、どなたか調節方法がお分かりになればお教えくださいませ。
LOG.exception()については何らかの例外処理と併せてぐらいでしか使わないかと思いますが、引数には文字列や数値、オブジェクトなど何でも指定できます。では何が出力されるかというと、その引数が持つプロパティ(内部変数、内部関数など)が全て出力されます。ですので大抵、膨大な量のメッセージが出力されます。
サードパーティー製品との連携
Selenium内でPrototype.jsを使う
まず、テストページに事前にPrototype.jsが読み込まれている場合はwindowオブジェクトを取得して命令を実行することができます。
<script type="text/javascript" src="path/to/js/prototype.js"></script>
以下の例はIDが「myText」の要素をPrototype.jsの「Element.hide()」関数を使って非表示にし、実際非表示になっているかどうかを確認するテストケースです。
コマンド | 対象 | 値 |
---|---|---|
getEval | win = this.page(). |
|
getEval | win.Element. |
|
assertNot |
myText |
また、Seleniumにはprototype.jsが組み込まれているので、selenium空間内で直接Prototype.jsの命令を呼び出すこともできます。 しかし、$()などの要素参照命令についてはエラーになりますので、事前に「this.page().findElement()」関数などで要素を取得してから行うと良いでしょう。
以下の例は、IDが「ok-button」のボタン要素を表示させて、実際に見える状態になっているかを確認するテストケースです。
コマンド | 対象 | 値 |
---|---|---|
getEval | buttonElem = this.page(). |
|
getEval | Element. |
|
assertVisible | ok-button |
FireBugのコンソールウィンドウに変数内容を出力する
FireBugのコンソールウィンドウに変数の内容などを出力する場合は、windowオブジェクトを取得して「console.log()」を使います。 このconsole.log()関数はSeleniumに備わっている命令ではなく、FireBugをインストールすることで使えるようになる命令なので混同しないようにしてください。 以下の例はページ内のJavaScriptで作成しておいたmyObjectインスタンスの内容をFireBugコンソールウィンドウに出力するテストケースです。
コマンド | 対象 | 値 |
---|---|---|
getEval | win = this.page(). |
|
getEval | win.console. |
2008-04-05