Selenium2.xのちょっとした小技

最近仕事でSeleniumに手を出していて、Selenium2.0以降のAPIを使用している。
ところが、2.0以降についての情報が少なく、こんなことするにはどうすれば?みたいなことを調べると大抵旧バージョンだったりするので、2.xでのコードのサンプルのようなものをメモとして書いてみる。


また職場のブラウザがIE6だったりするので、Selenium IDEはほとんど使ってません。
言語はJavaメインなので、他の言語やブラウザでは使えないかもしれません。
また、旧バージョンのSelenium1.xに触ったことはありません。

  • 導入

ここからダウンロードする。
1.xでは、Selenium-RCと呼ばれていた、各言語のAPIは、WebDriverという名称に変わっているので、
各言語向けのWebDriverをダウンロードして、展開してクラスパスを通せば完了。
ただし、どのWebDriverを使うにしてもPCにはJREの1.5以上がインストールされている必要があります。
IE6は正式には2.xではサポートされていませんが、WinXp + IE6の組み合わせで正常に動きました。

  • 基本的な操作

ブラウザの操作は、WebDriverクラスで行う。
FORM要素なんかは、WebDriverのfindElementメソッドでWebElement要素を見つけて、値を設定していく。
以下に、だらだらとサンプルコードをのせてみる。

    	// ブラウザに応じて生成するdriverのインスタンスを変える。
        WebDriver driver = new InternetExplorerDriver();
        driver.get("http://xxxxxxxx");
        // text,password,textareaなどをname属性で取得して、入力
        driver.findElement(By.name("hoge")).sendKeys("value");
        // checkbox,radioなどはid属性があれば簡単だが、
        // そうでない場合xpathでname属性、value属性を指定して、クリックさせる。
        driver.findElement(By.xpath("//input[@name='hoge' and @value='on']")).click();
        // selectのoption指定は、上記のようなxpathで頑張ることもできるが、Selectクラスで柔軟に指定できる。
        Select select = new Select(driver.findElement(By.id("hoge")));
        select.selectByIndex(1); //Optionタグのインデックスで選択。
        select.selectByValue("01"); //Option要素のvalue属性で選択。
        select.selectByVisibleText("表示文字列"); //Optionの表示文字列で選択。
        // ファイル選択もIE6では有効なファイルを絶対パスで指定すれば選択できる。
        driver.findElement(By.name("FILE_UPLOAD")).sendKeys("c:/temp/hoge.txt");
        // アンカーリンクは、アンカーの表示文字列でも検索可能。
        driver.findElement(By.linkText("リンク")).click();
        // フォームのサブミットは適当なWebElementからでも、要素を囲むFormを探してサブミットできる。
        driver.findElement(By.name("hoge")).submit();
        // onclick属性の実行などを行う場合は、ボタンを選択してクリックする。
        driver.findElement(By.id("hoge_button")).click();
        
        // ブラウザを閉じる。
        driver.close();
  • Javascriptのalertやconfirmなんかのダイアログ

1.xだとできないって記事が相当あるけど、2.xから操作できる。
WebDriverクラスの.switchTo().alert()で、ブラウザ上でポップアップしているJavascriptのダイアログが操作できる。
onloadイベントで実行したalert何かもちゃんと処理できる。

        WebDriver driver = new InternetExplorerDriver();
        Alert alert = driver.switchTo().alert();
        alert.getText(); //ダイアログのメッセージ
        alert.accept(); //alertやconfirmのOKを押す。
        alert.dismiss();// confirmのキャンセルを押す。
  • Windowの切り替え。

window.open()何かで新しく開いたウインドウとかに操作対象を切り替えるには、 WebDriverクラスの、switchTo().window("window_id")を使えばよく、 window_id には、window.open()の第二引数のウインドウIDを渡すみたいに公式ドキュメントに書いてあるのだが、IE6だからか旨くいかない。
解決策として、WebDriverクラスのgetWindowHandlesメソッドから取得できるIDを指定するのだが、
正直言って非常に面倒臭いコードになった。もう少し簡単にできないだろうか。

        // 現在操作しているWindow IDを控える。
        String currentWindowId = driver.getWindowHandle();
        // javascriptで、window.open()が行われるボタンをクリック。
        driver.findElement(By.id("button")).click();
        // ウィンドウ表示までに時間がかかると、seleniumが先走ることがあるのでウィンドウが増えるまで待機。
        (new WebDriverWait(driver, 10)).until(new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver d) {
                return d.getWindowHandles().size() > 1;
            }
        });
        // 増えたウィンドウIDを取得する。
        String newWindowId = null;
        for (String id : driver.getWindowHandles()) {
        	if (!id.equals(currentWindowId)) {
        		newWindowId = id;
        	}
        }
        // ウィンドウ切り替え
        WebDriver newWindowDriver = driver.switchTo().window(newWindowId);
  • スナップショットを取る

WebDriverではできず、以下のようなコードで取得できた。
IEでスナップショットを取るには、SnapsIEというActiveX コンポーネントを入れる必要があるという記事もあったが、2.xでは必要ないようだ。

        // Selenium-RC互換のAPIを取得。
        Selenium selenium = new WebDriverBackedSelenium(driver, "http://xxxx");
        // base64でエンコードされたPNGのスクリーンショットを取得
        String base64png = selenium.captureScreenshotToString();
        // base64デコードして、ファイル等に書き込む。割愛

ちなみに、他にもcaptureScreenShotうんぬんというメソッドはあるのだが、実装されていないため、実行時エラーとなってしまった。

  • できないこと

pdfファイルなんかをダウンロードしたりすると、ファイルの保存なんかを行うダイアログが出てきますが、 このダイアログを操作することは2.xでもできない模様。。。


というわけで、(使ったことはないけど)1.xに比べて色々と便利になったような感じがしました。
今後も、小技的なものがあればまとめていく予定。