seleniumer’s diary

「手動でExcelにスクショ貼付け」地獄からきました。テスト自動化しか望みがありません。java + selenium(since 2015/5)

webdriverで子画面を扱う

テストあるあるなのが子画面のオペレーション。
ボタンからjavascriptで起動する子画面でデータをあれして、親画面も更新してあれして、みたいな。

webdriverではメソッドswichTo()とgetWindowHandle()、またはgetWindowHandlesを使って制御します。
String currentWindow = driver.getWindowHandle();
for (String popUpHandle : Driver.getWindowHandles()) {         if(popUpHandle.equalsIgnoreCase(currentWindow))
            continue;
        Driver.switchTo().window(popUpHandle);
        String sTitle = Driver.getTitle();
あらかじめデフォルトのwindowHandleを格納しておいて、getwindowHandlesを展開してデフォルトじゃないヤツがおそらく子画面だろつってことでswitchToする、って行き当たりばったりですねぇ。
子画面が二つ以上表示されていたらどーするのだろう。
ちなみに複数子画面がある状態で下記コードでforループさせた場合、chromeと他ブラウザだとループ順が違います。
現場は大混乱になります(笑)
私の場合は一度配列に変換して、Chromeならばreverseして、とかやってました。
とほほ。

あと、子画面を閉じた後は
driver.switchTo(currentWindow) 
とかで、親ウィンドウにスイッチするのを忘れずに。No such windowとか悲しいエラーで落ちます。

引用元:

MacOSでChromeが立ち上がらない

これは悩みました。
selenium Gridでノードもハブも立ち上がっていて、firefoxなら動くのにChromeは動かない。
UnknownError: unknown error: cannot find Chrome binary
Chromeのバイナリーファイル、つまりアプリケーション本体が見つからないって。
MacOSChromeインストールパスをノード側のjsonに書いても、shellのjarファイル呼び出しコマンドに引数で書いてみてもうまくいかない。
フルパスで書いてるのに。
$ java -jar selenium-server-standalone-2.44.0.jar -Dwebdriver.chrome.driver=chromedriver
 -Dwebdriver.chrome.bin={フルパス}
結局、javaのテストプログラム側で
ChromeOptionsに書いてCapabitiesにぶっこんでなんとか動くという美しくない顛末になりました。
こんな感じ。
Map<String, Object> chromeOptions = new Map<String, Object>();
chromeOptions.put("binary", "{Chromeアプリフルパス}");
DesiredCapabilities capabilities = DesiredCapabilities.chrome();
capabilities.setCapability(ChromeOptions.CAPABILITY, chromeOptions);
〜 capabilitiesでRemoteWebDriverを初期化
これだと、ノード端末のChromeのフルパスをあらかじめ知っておかないと駄目なので、どうもやりにくい。Gridをうまく活用してるっぽくない。
jsonに書く方法がシンプルが良いのだろうけどお作法がわからないなぁー。

引用元

WebElementの親ノードをつかまえたい

WebElementの親ノードをつかまえたい。
どうするんだっけ?
意外に簡単でした。
WebElement myElement = driver.findElement(By.id("myDiv"));
WebElement parent = myElement.findElement(By.xpath(".."));
By.xpathで「..」するだけ。
二つ上なら「../..」だそうです。

SafariDriverがalertその他に対応してくれないので自分的措置(書きかけ)

(以下、書きかけです)

SafariDriverはポップアップ(alert / cofirm / prompt)には非対応で、エラーとなってしまいます。

これではMac OS+Safariでは必ず手動テストをやる羽目になります。

それは絶対に避けたい!

ということで、なんとか思案。

code.googleさんに良い記事がありました。

Issue 3862 - selenium - SafariDriver cannot handle alerts - Browser automation framework - Google Project Hosting

 

Best solution I found for to handle Selenium safari alert workaround is

Inject this javascript into browser before alert will occur, and you will found alert will automatically accepted.

((JavascriptExecutor)browser).executeScript("confirm = function(message){return true;};");
((JavascriptExecutor)browser).executeScript("alert = function(message){return true;};");
((JavascriptExecutor)browser).executeScript("prompt = function(message){return true;}");

 

ページロード時にJavascriptExcecutorでalert その他のfunctionをオーバーライドしてしまえば、ということらしいです。しかも強制的に「TRUE」を返す、と。

テストではポップアップメッセージの確認が多いのでこれではちょっと乱暴です。

そこで、ポップアップのメッセージをDom内にこっそり格納してテストメソッドに呼び出させて取得する手法を考えました。(苦しいですが。。。)

 

まず、ページロード時にこいつを読み込むようにして。

alert = function(m){a(m);return true;};
confirm = function(m){a(m);return true;};
prompt = function(m){a(m);return true;};
function a(m){
d=document.body;
e=document.getElementById('%$9e%');
if(e!=null){e.parentNode.removeChild(e)};
c=document.createElement('div');
c.id='%$9e%';
c.style.display = 'none';
c.innerHTML=m;
d.appendChild(c);
}

テストメソッドでよくあるアラートの制御処理

例えば

Alert alert = driver.switchTo().alert()

String message = alert.getText();

で、ブラウザがSafariだったらかわりに

String message = ((JavascriptExecutor)driver).executeScript({次のスクリプト});

m='';
e=document.getElementById('%$9e%');
if(e!=null){m=e.innerHTML;e.parentNode.removeChild(e)};
return m;

とします。かなり、苦しいですが。。。。この特殊処理のバリデーションはどうなってるんだって言われたら、ごめんなさい。しか言えないけど。

あと、Domロード時にポップアップがいきなり表示されるページではこれはオーバーライドが間に合わず使えません。うーむ、改良したい。Safari Extention側でInjectionScriptとかすればいけるかもだけど。私には敷居が高いです。とほほ。

こちらのページでも見ながら研究したいと思います。

時間があれば。

 

os0x.hatenablog.com

 

seleniumテストコードを書く

テストコードを書いてみます。

って公開用コードを書くのもなんなので、こちらのサイトがとても詳しく解説されています。

quesqa.com

 

段取りとしては

DesiredCapabilitiesを設定してから、WebDriverを起動

WebDriver driver = new RemoteWebDriver(new URL("{ノードURL}"), capability);

URLにアクセス

driver.get({行き先URL});

findElementでロケータを指定してWebElement(コントロールっすね)を取得。

WebElement element = driver.findElement(By.cssLocator("input#hoge"));

んで、そのElementにアクセス

element.sendKeys("こんにちは");

とか

element.click();

ってな感じです。

Webブラウザの自動化テストあるあるで待機時間のおきかたが悩ましいところなのですが、httpリクエスト後の画面表示は、いちおうWebDriverの方で待機してくれるみたいです。Ajax非同期通信的なやつは難しいみたいですが

待機条件の指定とかはこの記事がとても参考になりました。

softwaretest.jp

 

さらに深いところだとこのページがとても参考になりました。

ExpectedConditionsクラスは、待機条件をピンポイントで指定できるので便利なのですが、これだけでは足りない場合は自分で条件を書いたりしました。

WebDriver Wait Commands | Assert Selenium

 

ここまでで、基本的なブラウザ・アクセスはできるようになったので

次にちょっと踏み込んだところに言ってみたいと思います。

 

 

selenium webdriver セットアップ

OSやWebブラウザの種類は日々増えていくばかりでなく、そのシェアは日によって変わり続けている。やっぱりテストは自動化だよね、

ってことでseleniumを導入したいのだけど、簡単なTipsが公開されていないので、どうせなら自分で書いてみようと。

seleniumでブラウザテストの自動化環境を整えるための初歩の初歩からのメモ

 

構築環境

対象のブラウザ

Internet ExplorerFirefoxChrome

Mac / Safariとかも必要。とりあえずWindows環境を整える。 


Java JDKをインストール
とりあえず最新版をここからDLしてセットアップ

java.com


Eclipse(日本語版 All in one)をダウンロード

Eclipse 日本語化 | MergeDoc Project

解凍してC:\eclipse とかフォルダを作ってその中に展開。
eclipse.exeを起動。とりあえずは無事に起動すればOK。


Seleniumのコアなプログラムファイル達を手に入れる

http://docs.seleniumhq.org/download/

なんだかいっぱいあってどれをDLしたらよいのか一見わからないですが

Selenium Client」+「Java」ってやつを選びます。

f:id:seleniumer:20150628211833j:plain

ついでに「Internet Explorer Driver Server」も

f:id:seleniumer:20150628212041j:plain

ダウンロードしたファイル達は解凍して次のElipseのJAVAプロジェクト内に配置します。

 

SeleniumJAVAプロジェクトを作成 @ Eclipse
このページが超詳しい。

Selenium WebDriverのインストール~動かしてみる - hifive

Eclipseで、新しいJAVAプロジェクトを作成、さきほどのjarふぁいるなどなどを、このページの指示通りの場所にコピーします。

実行はソースファイルの好きなところ、右クリック→デバッグJUnitで。

パースペクティブ→ビュー→JUnitウインドウも便利なのでおわすれなく。

 

InternetExplorDriver(IEdriver)でよくハマるネタ。

インターネットオプション→セキュリティ→各ゾーンの保護モードが異なると、ゾーンエラーが起こる。

FireFoxでよくはまる?

ブラウザ起動時にプロキシの認証子画面が表示される。

これが邪魔をしてスクリプトが進まないってことがある。

解決策としてはあらかじめプロキシは使用しない設定にしておくこと。

Seleniumでは別のドライバーが無くても動いてくれるFirefoxですが、バイナリーパス(firefox.exeの格納パス)でエラーが起こる場合もあるのでご注意を。

By.linktext("リンク文字")が効かないときがある。xpathが確実だとか。

 

Chromeでよくハマること。

何しろ表示速度が早いChromeなのでスクショの取得タイミングが早すぎてあとで画像を見ると真っ黒でびっくりしたりすることも。なのでChromeの場合は、スクショ取得をコンマ数秒だけ遅らせるとか、すると良いかも。

 

Selenium GRID

さてさて次は「Selenium GRID」または「Selenium Remote Contorol」

とよばれるリモートテスト自動化の環境構築。

マスター(HUB)端末から複数のスレーブ(NODE)端末に対して同時にテストスクリプトを実行することが出来る。

理論上は同一のスクリプトで、他の端末に対して同時に並行テストを実行することが出来る。というものだ。

ほんとにそんな便利なこと出来るかねぇ、っていうことで

初めての環境構築です。

 

手順メモを書こうと思ったけど
長いので諦めた。

こちらをご覧ください。

Selenium Gridで複数の実機ブラウザで自動テスト

www.techscore.com

 

ざっくりというと
まずはハブ端末の設定

この辺りのサイトでSelenium Standalone Serverののjarファイルをダウンロード。

http://www.seleniumhq.org/download/

ハブ端末上で

java -jar selenium-server-standalone-2.48.2.jar -role hub 

とCMDを叩いて、立ち上げておきます。

記事執筆時点では2.48.2でした。

(新しめのブラウザだと動かない場合があるのでバージョンには要注意っぽいです。)

 

次にノード端末の設定

同じくjarファイルをダウンロードして

上述のサイトのように書くブラウザのインスタンス設定をjsonファイル(ここではnode.json)に書いておいて

java -jar selenium-server-standalone-2.xx.jar -role node -nodeConfig node.json -Dwebdriver.ie.driver={パス}\IEDriverServer.exe  -log {パス}\node.log

とかでCMDを叩いて立ち上げ。

-logオプションでログ出力させているのはseleniumやっていると謎の動作が多くてログ解析が必要になるから。ここのログはWebDriverの制御がすべて出力されるみたいです。デバッグには欠かせません。

ここではIEDriverServerをオプションで指定していますが、chromedriverも指定するなら

-Dwebdriver.chrome.driver={パス}\chromedriver.exe

とかします。

ブラウザ本体firefox.exeのパスがデフォルトじゃない場合もここで指定したほうが良いですね。

たぶん -Dwebdriver.firefox.bin={firefox.exeのフルパス} みたいな感じだったと思う。

webdriverオプションはjson内でも指定できるんだろうけどよく知りません。

更に言うとMacOS/ChromeではChrome本体のパスを渡すのがうまくいかなかった(力不足です)ので、テストコードにCromeアプリのパスをChromeOptionに定義していました。(コレが結構面倒でした。。。)

sites.google.com 

さて、これでハブとノード端末は立ち上がったのを見てみます。

上述のサイトのGrid Consoleってやつです。

これでハブ/ノードが正常に立ち上がっているかを確認できます。

 

ではいよいよテストコードですね。

次に続きます。