Robot Framework + Selenium2Libraryで、HTML + JavaScriptまわりをテストする

前回、Robot Framework + Selenium2Libraryで、HTMLのフォームまわりをテストしてみました。
Robot Framework + Selenium2Libraryで、HTMLフォームまわりをテストする - メモ的な思考的な

 
今回は、Robot Framework + Selenium2Libraryで、HTML + JavaScriptまわりをテストしてみます。

 
目次

 

環境

  • Mac OS X 10.11.6
  • Python 3.6.2
  • Google Chrome 60.0.3112.78 (stable)
  • ChromeDriver 2.31 (stable)
  • RobotFramework 3.0.2
  • Selenium2Library 1.8.1dev1
    • GitHubから現在の最新版をインストール
    • PyPIにある1.8.0では、Python3系だとエラーが出てインストールできない
  • Selenium 3.4.3
  • Bottle 0.12.13
    • Webアプリ用

 

Elementが出てくるまで待つ

<div id="show_delay"></div>

というHTMLに対し、

window.addEventListener("load", function () {
    setTimeout(function(){
        document.getElementById('show_delay').innerHTML = '<p id="hello">Hello, world!</p>'
    }, 3000);
});

と、3秒後にp要素を追加するJavaScriptがあるとします。

 
この場合、Wait Until Page Contains Elementを使い、p要素が出てくるまで待機します。
Wait Until Page Contains Element | Selenium2Library

# p要素が出てくるまで待つ
wait until page contains element  id=hello

# 出てきたら、p要素のテキストが正しいかを確認
element text should be  id=hello  Hello, world!

 

マウスオーバーすると出てくるElementをクリックする

<div id="on_mouse_area">このあたりをマウスオーバーするとボタンが見える
    <button id="mouse_target" style="display: none;">
        mouseoverのみ見える
    </button>
</div>

というdisplay: noneなHTMLがあり、

var on_mouse_area = document.getElementById('on_mouse_area');
on_mouse_area.onmouseover = function () {
    document.getElementById('mouse_target').style.display = 'block';
};
on_mouse_area.onmouseout = function () {
    document.getElementById('mouse_target').style.display = 'none';
};
var mouse_target = document.getElementById('mouse_target');
mouse_target.onclick = function () {
    window.location.href = '/'
};

と、マウスオーバー時に表示するJavaScriptがあるとします。

 
この場合、Mouse Overを使いマウスオーバーした後、Click Elementします。
Mouse Over | Selenium2Library

# マウスオーバーする
mouse over  id=on_mouse_area

# クリックする
click element  id=mouse_target

 

スクロールしてクリックする

JavaScriptでスクロールする
<div class="bottom" style="padding-top: 1200px">
    <button id="bottom_button">下にあるボタン</button>
</div>

と、縦長のページの一番下にボタンがあるとします。

 
この場合、JavaScriptを実行するExecute Javascriptを使い、JavaScriptwindow.scrollTo()などを使います。

# スクロールする
Execute JavaScript  window.scrollTo(0, 1200)

# クリックする
click element  id=bottom_button

 

画面サイズを変更する

スクロールするとは関係ないですが、画面サイズについて、

などがあります。

# 現在の画面サイズを取得する
${幅}  ${高さ} =  get window size

# 画面サイズを変更する
set window size  10  10

# 画面サイズを元に戻す
set window size  ${幅}  ${高さ}

 

display:noneなボタンをクリックする

<button id="display_none" style="display: none;">見えない</button>

という、display:noneなStyleのボタンがあるとします。

この場合、JavaScriptを使うことで、強引にクリックすることができます。
Example to click on element which is hidden using Execute Javascript? - Google グループ

execute javascript  document.getElementById('display_none').click();

 

JavaScriptによるリロードがあったことを確認する

Assign Id To Elementを使う
<button id="run_reload" class="reload_element">リロード</button>

というHTMLがあり、このボタンを押すと

var reload = document.getElementById('run_reload');
reload.onclick = function () {
    location.reload();
};

と、リロードするJavaScriptがあるとします。

 
この場合、Assign Id To Elementを使って

  • リロード前にタグを設定
  • リロード後にタグが存在しないことを確認

を行います。

Assign Id To Elementで設定したidはリロードすると消えてしまう特性を利用します。
Assign Id To Element | Selenium2Library

# id="run_reload"をid="not_reload"に付け替える
assign id to element  run_reload  not_reload

 

Assign Id To Elementの注意点
assign id to element  id=reload_dummy  not_reload

と、locatorにidを指定すると、

Keyword 'Selenium2Library.Assign Id To Element' got positional argument after named arguments.

というエラーになります。

一方、locatorがclassやxpathであればエラーは出ません。

assign id to element  class=reload_element  not_reload

どうしてもlocatorにidを指定したい場合は、id=を省略すると、デフォルトの挙動であるidnameで検索してくれます。

assign id to element  run_reload  not_reload

 
また、Assign Id To Elementはidを付け替えるため、

<button id="run_reload" class="reload_element">リロード</button>

というHTMLの場合、

# idの割り当て
assign id to element  run_reload  not_reload

# not_reload なidは存在する
page should contain element  id=not_reload

# run_reload なidが存在しない
page should not contain element  id=run_reload

という挙動となります。

idの付け替えが困る場合には、idがないElementなど、他の適当なElementを指定します。

 

JavaScriptのalertまわり

alertのOKボタンを押す
<button id="show_alert">警告</button>

というHTMLに対し、

var show_alert = document.getElementById('show_alert');
show_alert.onclick = function () {
    alert('OKのみです');
};

とOKのみのalertを表示するJavaScriptがあるとします。

 
この場合、Dismiss Alertを使い、alertのOKボタンを押します。
Dismiss Alert | Selenium2Library

# alertを表示する
click element  id=show_alert

# alertでOKを押す
dismiss alert

 

alertのメッセージを取得してOKを押す

同じく、

<button id="show_alert">警告</button>

というHTMLに対し、

var show_alert = document.getElementById('show_alert');
show_alert.onclick = function () {
    alert('OKのみです');
};

というJavaScriptがあった場合、メッセージの内容を取得してからOKを押したいとします。

 
この場合、Get Alert Messageを使い、alertのメッセージを取得します。
Get Alert Message | Selenium2Library

# alertを表示する
click element  id=show_alert

# alertのメッセージを取得する
${アラートメッセージ} =  get alert message

# alertのメッセージを確認する
should be equal  ${アラートメッセージ}  OKのみです

 

alertが表示されていることを確認してからOKを押す

同じく、

<button id="show_alert">警告</button>

というHTMLに対し、

var show_alert = document.getElementById('show_alert');
show_alert.onclick = function () {
    alert('OKのみです');
};

というJavaScriptがあった場合、alertが表示されていることを確認してからOKを押したいとします。

 
この場合、Alert Should Be Presentを使い、alertが表示されていることを確認してからOKを押します。
Alert Should Be Present | Selenium2Library

# alertを表示する
click element  id=show_alert

# alertが表示されていることを確認してからOKを押す
alert should be present

 

alertの表示とメッセージの一致を確認してからOKを押す

同じく、

<button id="show_alert">警告</button>

というHTMLに対し、

var show_alert = document.getElementById('show_alert');
show_alert.onclick = function () {
    alert('OKのみです');
};

というJavaScriptがあった場合、alertが表示され、メッセージも一致していることを確認してからOKを押したいとします。

 
この場合、Alert Should Be Presentで引数を使い、alert表示とメッセージ一致の確認後にOKを押します。
Alert Should Be Present | Selenium2Library

# alertを表示する
click element  id=show_alert

# alertが表示され、メッセージも一致していることを確認してからOKを押す
alert should be present  OKのみです

 

alertの表示に時間がかかった場合でもOKを押す
<button id="wait_alert">2秒後に警告</button>

というHTMLに対し、

var wait_alert = document.getElementById('wait_alert');
wait_alert.onclick = function () {
    setTimeout(function(){
        alert('2秒後のアラート');
    }, 2000);
};

と、2秒後にalertを表示するJavaScriptがあるとします。

 
この場合、Wait Until Keyword Succeedsとalertを処理するキーワードを併用します。
Wait Until Keyword Succeeds | BuiltIn

 
Wait Until Keyword Succeedsの引数は

  • 第一引数は、リトライ時間
  • 第二引数は、リトライ間隔
  • 第三引数は、実行するキーワード

です。

# 5秒の間、1秒ごとに、「Get Alert Message」キーワードを実行する
${アラートメッセージ} =  wait until keyword succeeds  5 sec  1 sec  get alert message

# alertに「2秒後のアラート」というメッセージがあったことを確認
should be equal  ${アラートメッセージ}  2秒後のアラート

 

JavaScriptのconfirmまわり

confirmのOKを押す
<button id="show_confirm">確認</button>

というHTMLに対し、

var show_confirm = document.getElementById('show_confirm');
show_confirm.onclick = function () {
    var answer = confirm('OKとキャンセルです');
    if (answer){
        alert('OKが押されました');
    }
    else{
        alert('キャンセルされました');
    }
};

と、ボタンを押したらconfirmが表示されるJavaScriptがあるとします。

 
この場合、Confirm Actionを使い、confirmでOKを押します。
Confirm Action | Selenium2Library

ちなみに、Confirm ActionのデフォルトではOKを押します。そのため、デフォルトを変更しない限り、Choose Ok On Next Confirmationは不要です。
Choose Ok On Next Confirmation | Selenium2Library

# OKボタンを押して、confirmのメッセージを取得する
${確認メッセージ} =  confirm action

# confirmのメッセージを確認する
should be equal  ${確認メッセージ}  OKとキャンセルです

# OKを押した時にalertが表示され、「OKが押されました」というメッセージがあるかを確認する
${アラートメッセージ} =  get alert message
should be equal  ${アラートメッセージ}  OKが押されました

 

confirmのキャンセルを押す

同じく、

<button id="show_confirm">確認</button>

というHTMLに対し、

var show_confirm = document.getElementById('show_confirm');
show_confirm.onclick = function () {
    var answer = confirm('OKとキャンセルです');
    if (answer){
        alert('OKが押されました');
    }
    else{
        alert('キャンセルされました');
    }
};

と、ボタンを押したらconfirmが表示されるJavaScriptがあるとします。

 
この場合、Choose Cancel On Next ConfirmationConfirm Actionを使い、confirmでキャンセルを押します。

# 次の確認処理ではキャンセルボタンを押す
choose cancel on next confirmation

# confirmが表示され、キャンセルを押す
${確認メッセージ} =  confirm action
should be equal  ${確認メッセージ}  OKとキャンセルです

# キャンセルを押した時にalertが表示され、「キャンセルされました」というメッセージがあるかを確認する
${アラートメッセージ} =  get alert message
should be equal  ${アラートメッセージ}  キャンセルされました

 

JavaScriptのpromptに入力する

<button id="show_prompt">入力</button>

というHTMLに対し、

var show_prompt = document.getElementById('show_prompt');
show_prompt.onclick = function () {
    var input_message = prompt('値を入力します');
    alert(input_message);
};

と、JavaScriptのpromptが表示されるとします。

 
この場合、Input Text Into Promptを使い、promptに入力します。
Input Text Into Prompt | Selenium2Library

また、Input Text Into Promptはpromptに入力するだけなので、Confirm ActionによりOKボタンを押します。

なお、ここまでの処理でChoose Cancel On Next Confirmationが使われていた場合、Confirm Actionしてもキャンセルボタンが押されてしまうため、promptへの入力が成功しません。

そのため、Choose Cancel On Next Confirmationが使われている可能性がある場合は、明示的にChoose Ok On Next Confirmationを実行した後にConfirm Actionを実行するとよいでしょう。

# promptを表示する
click element  id=show_prompt

# ここまででChoose Cancel On Next Confirmationが使われている可能性があるため、
# 明示的にChoose Ok On Next Confirmationを実行し、promptでOKを押すように指定する
choose ok on next confirmation

# promptに入力する
input text into prompt  プロンプトに入力しました

# OKボタンを押す
confirm action

# alertではpromptに入力した値が表示されているはずなので、一致しているかを確認する
${アラートメッセージ} =  get alert message
should be equal  ${アラートメッセージ}  プロンプトに入力しました

 

Headlessブラウザの制限

Headless Chrome v60やPhantomJSの場合、alertやpopup(acceptPopup, cancelPopup)などが未サポートです。
How to run Headless Chrome in Codeception - Codeception / Cookbook - PHP Test Club

そのため、stackoverflowにあるようにモンキーパッチすれば良いかもしれません。
selenium webdriver - chromedriver headless alerts - Stack Overflow

なお、Capybaraでは対応策があるようです。
RSpec + Capybaraでアラート/確認ダイアログを操作する場合は page.driver.browser.switch_to.alert.accept じゃなくて page.accept_confirm を使おう - Qiita

もっとも、Headless Chromeの今後のバージョンでは実装されるかもしれないため、今回はこの部分の対応方法は省略します。

 

ソースコード

GitHubに上げました。tests/の中にあるselenium_js_test.robotファイルが今回のテストファイルです。
thinkAmi-sandbox/RobotFramework-sample