Selenium の新しいコマンドを作る
Selenium には標準で素晴らしいコマンドが沢山存在している。
なので基本的にはそのコマンドを組み合わせて、
テストを行っていけば良い。
が、当然、標準のコマンドだけでは、
「〜のテストできんー」ってのはある。
つい最近仕事であったのは、
「ある画面にエラーメッセージが出るのだが、
同じメッセージが2個出ることを確認しないといけない。
それを自動化するにはどうしたらいいか?」
ってものだった。
Selenium の標準のコマンドには、
assertTextPresent というコマンドがある。
このコマンドは、html 形式だと
<tr> <td>assertTextPresent</td> <td>hoge</td> <td></td> </tr>
という形で記述し、
第一引数の「hoge」がページ内に存在するか assert (検証)し、
存在しなかったらテストに失敗した状態にするというものである。
「hoge」という文字列がページ内に2回現れることを、
この assertTextPresent では検証できない。
1個だけ存在しても、2個存在しても、3個存在してもエラーにはならないからだ。
というわけで、「hoge」がページ内に2個だけ存在することを確かめるためのコマンドを作った。
(Selenium Recoder をプロジェクトで使ってるので、
Selenium のバージョン0.6 だけで動作確認しました。
多分、Selenium 0.7 でも動くと思いますが)
/* * assertTextPresentCount */ Selenium.prototype.assertTextPresentCount = function(expectedTextReg, count) { var allText = this.page().bodyText(); if (allText.match(expectedTextReg, "g").length != count) { Assert.fail("Page text not adapt"); } };
Selenium.prototype はおまじないと思ってくれ(乱暴w)。
俺のつたない JavaScript の知識から言うと、
Selenium クラスのオブジェクトの prototype フィールドに新しいメソッドを付け加えてる。多分。
この辺りは、JavaScript だなーって感じで、
JavaScript のプロトタイプベースのオブジェクト指向、
動的なメソッド、フィールドの追加の概念を理解してないと
「ハァ???」って感じのコードだろうけど。
まぁ、こういう形でかけばいいと覚えればよいと思ふ。
俺もよくわかってないしwww
このコード書くにあたっては、
Selenium のソースの selenium-api.js の assertTextPresent のコードを参照した。
/* * Asserts that the specified text is present in the page content. */ Selenium.prototype.assertTextPresent = function(expectedText) { var allText = this.page().bodyText(); if(allText == "") { Assert.fail("Page text not found"); } else if(allText.indexOf(expectedText) == -1) { Assert.fail("'" + expectedText + "' not found in page text."); } };
こいつが何してるかっていうと、
function(expectedText)
は、コマンドの引数を expectedText という名前で受け取るという意味。
html のコマンドの
<tr> <td>assertTextPresent</td> <td>hoge</td> <td></td> </tr>
「hoge」という文字列が expectedText に入る。
んで、prototype 君には、page() というメソッドがあって、
これは現在表示中のページの情報が返ってくる(これを CurrentPage オブジェクトと呼ぼう)。
CurrentPage オブジェクト君は、表示されてる html の body 部(多分)を返す
bodyText メソッドを持ってるので、それを呼ぶ事で、
allText 変数にページの text が入る
if(allText == "") { Assert.fail("Page text not found"); } else if(allText.indexOf(expectedText) == -1) { Assert.fail("'" + expectedText + "' not found in page text."); }
Assert.fail は TestRunner で実行中のスクリプトを止めて、
ブラウザ上に赤く表示させるための処理。
else if(allText.indexOf(expectedText) == -1) は、
indexOf メソッドで、
ページの文字列中に expectedText (hoge) が現れる位置を取得。
文字列中に hoge が存在しなかったら、
indexOf メソッドは -1 を返す。
これが true になるってことは、
ページの中に hoge がないってことだから、
次の Assert.fail が呼ばれて、
TestRunner が赤くなるってすんぽー。
翻って、
俺が作った拡張コマンドは
/* * assertTextPresentCount */ Selenium.prototype.assertTextPresentCount = function(expectedTextReg, count) { var allText = this.page().bodyText(); if (allText.match(expectedTextReg, "g").length != count) { Assert.fail("Page text not adapt"); } };
ほぼ assertTextPresent コマンドをパクッってるんだけど
まず、
function(expectedTextReg, count)
で引数を2個取るように定義。
html の書き方としては、
<tr> <td>assertTextPresentCount</td> <td>hoge</td> <td>2</td> </tr>
と書く。
これにより、
expectedTextReg に 「hoge」が入り、
count に 「2」が入る。
ページのテキスト受け取る部分は、assertTextPresent と一緒。
で
if (allText.match(expectedTextReg, "g").length != count)
のところで、
文字列の match メソッドを呼ぶ。
allText に expectedTextReg であらわす正規表現に適合する文字列の配列を
"g" オプションを指定することで、
適合する文字列全てを配列として返す。
そしてその配列の個数が count と合わなかったらエラー。
んで、このコマンド使いたいときは、
このソースを、user-extension.js に書いて、
サーバーで動かすなら、TestRunner.html から見える場所に user-extension.js 置くか、
Selenium Recorder(IDE も) から動かすなら、
File - Opetion の user-extension.js の設定を、
ローカルフォルダの user-extension.js の場所に設定すれば良い。
ま、こんな感じ。
酔っ払ってるわりにはしっかり書けたよね?!wwww
後日、Selenium 公式の拡張の仕方んところの日本語訳でもしてみんよー。