Selenium IDEで検索機能をテストしてみる

## 概要
Selenium IDEはFirefoxのアドオンです。
手軽にブラウザ操作を記録＆再生できるため、使用したことがある方も多いと思われます。
ただ、条件分岐やループなどの制御文を使うには少し工夫が必要です。

弊社ではサイト内検索に<a href="https://cse.google.co.jp/" target="_blank">Googleカスタム検索エンジン</a>(以下GCSE)を使っていて、頻度は低いのですがGCSE側の不具合で動いていないことがあったため、監視できないものかと、下記のスクリプトを個人的に試作してみました。

## スクリプト
あくまでページのテストを目的とし、キーワードに対する検索結果を収集するような用途では使用しないようお願いします。

```html
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head profile="http://selenium-ide.openqa.org/profiles/test-case">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="selenium.base" href="http://search.allabout.co.jp" />
<title>aa_search_test</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">aa_search_test</td></tr>
</thead><tbody>

<!-- (1)検索キーワード設定 -->
<tr>
	<td>getEval</td>
	<td>delete storedVars['keywords']</td>
	<td></td>
</tr>

<tr><td>push</td><td>なべ</td><td>keywords</td></tr>
<!-- <tr><td>push</td><td>洗濯機</td><td>keywords</td></tr> -->
<!-- <tr><td>push</td><td>アイロン</td><td>keywords</td></tr> -->

<tr>
	<td>storeEval</td>
	<td>storedVars['keywords'].length</td>
	<td>keywordsLength</td>
</tr>
<tr>
	<td>store</td>
	<td>0</td>
	<td>indexKeywords</td>
</tr>

<!-- (1)ループ開始 -->
<tr>
	<td>while</td>
	<td>${indexKeywords} < ${keywordsLength}</td>
	<td></td>
</tr>
<tr>
	<td>storeEval</td>
	<td>storedVars['keywords'][storedVars['indexKeywords']]</td>
	<td>currentKeyword</td>
</tr>

<tr>
	<td>echo</td>
	<td>KEYWORD:${currentKeyword}</td>
	<td></td>
</tr>
<!-- キーワード検索、ページを開く -->
<tr>
	<td>open</td>
	<td>/?q=${currentKeyword}</td>
	<td></td>
</tr>

<!-- (2)ループカウンタ設定 (適当に数ページ分の結果を確認) -->
<tr>
	<td>store</td>
	<td>1</td>
	<td>index</td>
</tr>
<tr>
	<td>store</td>
	<td>2</td>
	<td>end</td>
</tr>

<!-- (2)ループ開始 -->
<tr>
	<td>while</td>
	<td>${index} <= ${end}</td>
	<td></td>
</tr>

<!-- (3)スリープ -->
<tr>
	<td>pause</td>
	<td>3000</td>
	<td></td>
</tr>

<!-- ページ指定 -->
<tr>
	<td>storeEval</td>
	<td>parseInt(storedVars['index']) -1</td>
	<td>indexForPager</td>
</tr>
<tr>
	<td>click</td>
	<td>document.getElementsByClassName('gsc-cursor-page')[${indexForPager}]</td>
	<td></td>
</tr>
<tr>
	<td>waitForText</td>
	<td>css=div.gsc-cursor-page.gsc-cursor-current-page</td>
	<td>${index}</td>
</tr>

<!-- (4)URL取得 -->
<tr>
	<td>storeEval</td>
	<td>this.page().getDocument().getElementsByClassName('gsc-url-top')[0].getElementsByTagName('div')[1].innerHTML</td>
	<td>t1</td>
</tr>
<tr>
	<td>storeEval</td>
	<td>this.page().getDocument().getElementsByClassName('gsc-url-top')[1].getElementsByTagName('div')[1].innerHTML</td>
	<td>t2</td>
</tr>
<tr>
	<td>storeEval</td>
	<td>this.page().getDocument().getElementsByClassName('gsc-url-top')[2].getElementsByTagName('div')[1].innerHTML</td>
	<td>t3</td>
</tr>
<tr>
	<td>storeEval</td>
	<td>this.page().getDocument().getElementsByClassName('gsc-url-top')[3].getElementsByTagName('div')[1].innerHTML</td>
	<td>t4</td>
</tr>
<tr>
	<td>storeEval</td>
	<td>this.page().getDocument().getElementsByClassName('gsc-url-top')[4].getElementsByTagName('div')[1].innerHTML</td>
	<td>t5</td>
</tr>
<tr>
	<td>storeEval</td>
	<td>this.page().getDocument().getElementsByClassName('gsc-url-top')[5].getElementsByTagName('div')[1].innerHTML</td>
	<td>t6</td>
</tr>
<tr>
	<td>storeEval</td>
	<td>this.page().getDocument().getElementsByClassName('gsc-url-top')[6].getElementsByTagName('div')[1].innerHTML</td>
	<td>t7</td>
</tr>
<tr>
	<td>storeEval</td>
	<td>this.page().getDocument().getElementsByClassName('gsc-url-top')[7].getElementsByTagName('div')[1].innerHTML</td>
	<td>t8</td>
</tr>
<tr>
	<td>storeEval</td>
	<td>this.page().getDocument().getElementsByClassName('gsc-url-top')[8].getElementsByTagName('div')[1].innerHTML</td>
	<td>t9</td>
</tr>
<tr>
	<td>storeEval</td>
	<td>this.page().getDocument().getElementsByClassName('gsc-url-top')[9].getElementsByTagName('div')[1].innerHTML</td>
	<td>t10</td>
</tr>

<!-- (5)URL出力 -->
<tr>
	<td>echo</td>
	<td>URL:${t1}</td>
	<td></td>
</tr>
<tr>
	<td>echo</td>
	<td>URL:${t2}</td>
	<td></td>
</tr>
<tr>
	<td>echo</td>
	<td>URL:${t3}</td>
	<td></td>
</tr>
<tr>
	<td>echo</td>
	<td>URL:${t4}</td>
	<td></td>
</tr>
<tr>
	<td>echo</td>
	<td>URL:${t5}</td>
	<td></td>
</tr>
<tr>
	<td>echo</td>
	<td>URL:${t6}</td>
	<td></td>
</tr>
<tr>
	<td>echo</td>
	<td>URL:${t7}</td>
	<td></td>
</tr>
<tr>
	<td>echo</td>
	<td>URL:${t8}</td>
	<td></td>
</tr>
<tr>
	<td>echo</td>
	<td>URL:${t9}</td>
	<td></td>
</tr>
<tr>
	<td>echo</td>
	<td>URL:${t10}</td>
	<td></td>
</tr>

<!-- (2)ループカウンタインクリメント -->
<tr>
	<td>storeEval</td>
	<td>parseInt(storedVars['index']) +1</td>
	<td>index</td>
</tr>

<!-- (2)ループ終了 -->
<tr>
	<td>endWhile</td>
	<td></td>
	<td></td>
</tr>


<!-- (1)ループカウンタインクリメント -->
<tr>
	<td>storeEval</td>
	<td>parseInt(storedVars['indexKeywords']) +1</td>
	<td>indexKeywords</td>
</tr>

<!-- (1)ループ終了 -->
<tr>
	<td>endWhile</td>
	<td></td>
	<td></td>
</tr>


</tbody></table>
</body>
</html>
```

## セットアップ
* Firefoxに<a href="https://addons.mozilla.org/ja/firefox/addon/selenium-ide/" target="_blank">Selenium IDE</a>を追加します。
* Firefoxの[ツール]-[Selenium IDE]をクリック。
* Selenium IDEの起動後、メニューの[オプション]-[設定]をクリックします。
* <a href="https://github.com/73rhodes/sideflow" target="_blank">sideflowエクステンション</a>をダウンロード後、[一般]-[Selenium Core 拡張スクリプト]でファイルパスを指定。(Selenium IDEの再起動が必要)  
![options.jpg](https://qiita-image-store.s3.amazonaws.com/0/26770/9a69413b-78f9-e112-b079-c45247e25212.jpeg)
* 後はデバッグに役立つ下記エクステンションも入れておきます。(スキップ可)
    * <a href="https://addons.mozilla.org/ja/firefox/addon/file-logging-selenium-ide/">File Logging</a>
    * <a href="https://addons.mozilla.org/ja/firefox/addon/stored-variables-viewer-seleni/">Stored Variables</a>

## 実行方法
* ① 上記スクリプトをUTF-8でファイルに保存。
* ② Selenium IDEのメニューで[ファイル]-[テストケースを開く]からファイル①を選択。
* ③ 左上にある緑色の三角ボタンをクリックしてテストを実行します。

## 処理内容 (スクリプト内の数字に対応)
* (1) 一番外側のループ
    * 複数の検索キーワードをテストしたい場合、その数分だけループします。
* (2) 内側のループ
    * 検索結果が複数ページにわたって表示されますが、確認したいページ数分だけループします。
* (3) スリープ
    * GCSEに必要以上の負荷をかけないよう適当にスリープを設定しましょう。
* (4)(5) 結果を出力
    * 検索結果が表示されているか確認するため、コンソール(またはファイル)に出力します。

## 所感
数ヶ月前にSelenium3がリリースされ、WebDriverシフトが明確になったので、今後はSelenium IDEベースのテストは縮小していくと考えられます。
ただ一方で「ブラウザで手軽にテストを作成する」という面では一定の支持も受けていくのかな、という感じもしています。
ブラウザの操作をWebDriverベースのコードに変換するSelenium Builderというツールもあるので、近いうちにこちらも試してみたいですね。

## 参考
* <a href="http://blog.trident-qa.com/2013/06/selenium-ide-plugins/" target="_blank">Selenium IDEエクステンション一覧</a>