Robot Framework + Selenium2Libraryで、静的HTMLをテストする

以前、Robot FrameworkとSelenium2Libraryを使ってみました。

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

 
2017/9/2追記

Selenium2Libraryですが、バージョン3からは SeleniumLibrary へと名称が変更されています。詳しくはこちらに書きました。
RobotFrameworkのSelenium2Libraryの名前が、SeleniumLibraryへと変更されてた - メモ的な思考的な

なお、本文はSelenium2Libraryのままにしてあります。

2017/9/2追記ここまで

 
目次

 

環境

  • 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アプリ用

 
Selenium2LibraryをGitHubからインストールする方法は以下と同様ですので、今回は省略します。
Robot Framework + Selenium2Library + ImageMagickで、スクリーンショットの差分を確認する - メモ的な思考的な

 

ブラウザの起動・移動・終了

起動

が使えます。

Crate Webdriverだと起動時のオプションを利用できます。

通常のChromeを起動する方法です。

create webdriver  Chrome

 
HeadlessなChromeを起動する方法です。オプションとして--headlessを使います。

${options} =  evaluate  sys.modules['selenium.webdriver'].ChromeOptions()  sys
call method  ${options}  add_argument  --headless
create webdriver  Chrome  chrome_options=${options}

 

移動

Go Toを使います。
Go To | Selenium2Library

以下の例では、localhostの8084ポートへ移動しています。

go to  http://localhost:8084

 
なお、URIスキームの有無で動作の違いがあります。詳しくは以下に書きました。
Robot Framework + Selenium2Libraryで、「Go To」を使う時はURIスキームを付ける - メモ的な思考的な

 

終了

などが使えます。

close all browsers

 

ページに文字やElementが存在するか確認する

いわゆるassert系のキーワードです。キーワードの条件を満たさない場合、テストが失敗します。

ページに文字が存在するか

Page Should Containを使います。
Page Should Contain | Selenium2Library

# ページに「Hello, world!」の文字列が含まれるか
page should contain  Hello,${SPACE}world!

 
他に

  • ページに画像が存在するか(Page Should Contain Image)
  • ページに文字が存在しないか(Page Should Not Contain)

などのキーワードがあります。詳しくはドキュメントを見てください。

 

ページにElementが存在するか

Page Should Contain Elementを使います。
Page Should Contain Element | Selenium2Library

# ページにid=helloのelementが含まれるか
page should contain element  id=hello

 
なお、キーワードの後ろにあるid=helloの部分はlocatorと呼ばれるものです。詳しくは次で説明します。

 

locatorについて

locatorとは、ページのElementを探す時のキーとなるものです。

いくつか種類があるため、今回は主なものだけ記載します。詳細は以下のドキュメントを確認してください。
Locating or specifying elements | Selenium2Library

 

id

Elementのid属性を使って検索します。

<button id="locator_id" name="locator_name" class="locator_class">
    locator_text1
</button>

に対し、

page should contain element  id=locator_id

と使います。

 

name

Elementのname属性を使って検索します。

<button id="locator_id" name="locator_name" class="locator_class">
    locator_text1
</button>

に対し

page should contain element  name=locator_name

と使います。

 

identifier

Elementのidもしくはname属性を使って検索します。

<button id="locator_id" name="locator_name" class="locator_class">
    locator_text1
</button>

に対し、

page should contain element  identifier=locator_id
page should contain element  identifier=locator_name

と使います。

 

XPath

XPathを使うこともできます。

<button id="locator_id" name="locator_name" class="locator_class">
    locator_text1
</button>

に対し、

page should contain element  xpath=/html/body/button[@class="locator_class"]
page should contain element  xpath=//button[@class="locator_class"]

と使います。
参考:xpathまとめ - Qiita

 
また、

<button class="locator_class" data-hoge="ham spam" disabled>
    locator_text2
</button>
<button class="locator_class_foo" data-hoge="ham egg">
    locator_text3
</button>
<button class="locator_class_foo" data-hoge="ham spam">
    locator_text4
</button>

のような場合は、

# andを使う
element text should be  xpath=//button[@class="locator_class" and @disabled]  locator_text2

# containを使う(第二引数は文字列をクォートで囲む)
element text should be  xpath=//button[@class="locator_class" and contains(@data-hoge, "spam")]  locator_text2

# notを使う
element text should be
...  xpath=//button[@class="locator_class_foo" and not(contains(@data-hoge, "egg"))]  locator_text4

のような、 andcontainnotなども使えます。

 

CSS

CSSセレクタもlocatorとして使えます。

<div id="locator_css">
    <ul><li>1-1</li></ul>
    <ul>
        <li>2-1</li>
        <li>2-2</li>
        <li><p>対象</p></li>
    </ul>
    <ul><li>3-1</li></ul>
</div>

に対し、

page should contain element  css=#locator_id
page should contain element  css=button.locator_class

と使います。

 
また、CSSのnth-childなども使えます(nth-childは1始まり)。
:nth-childの使い方 | CSSPRO

element text should be  css=#locator_css > ul:nth-child(2) > li:last-child > p  対象

 

jQuery

jQueryもlocatorとして使えます。

ただし、対象のHTMLにてjQueryがロードされていない場合、WebDriverException: Message: unknown error: jQuery is not definedというエラーが発生して使えません。
参考:Document that jQuery is not provided by Selenium2Library · Issue #262 · robotframework/Selenium2Library

<img id="img_200" src="/static/image/a.png" alt="あの字" title="画像タイトル">

に対し、

page should contain image  jquery=img[alt='あの字']
page should contain image  jquery=img[title='画像タイトル']

と使います。

画像のalttitle属性で検索したい時は便利かもしれません。

 

Elementの属性を取得する

Get Element Attributeを使います。
Get Element Attribute | Selenium2Library

 
例えば、

<img id="img_200" src="/static/image/a.png" alt="あの字" title="画像タイトル">

に対し、画像のsrc属性を取得し、比較する例です。

${src} =  get element attribute  css=#img_200@src
${url} =  get location
should be equal  ${src}  ${url}static/image/a.png

 

Elementに対するvisibleとenableとcontainの違い

似たようなキーワードとして、

があります。

 
例えば

<button id="element_display_none" style="display: none">
    None
</button>

<button id="element_visibility_hidden" style="visibility: hidden">
    Hidden
</button>

<button id="element_disabled" disabled>
    Disabled
</button>

があった場合、パスするテストの書き方は

# not be visible / be visible
element should not be visible  id=element_display_none
element should not be visible  id=element_visibility_hidden
element should be visible  id=element_disabled

# be enable / be disable
element should be enabled  id=element_display_none
element should be enabled  id=element_visibility_hidden
element should be disabled  id=element_disabled

# いずれもcontain element
page should contain element  id=element_display_none
page should contain element  id=element_visibility_hidden
page should contain element  id=element_disabled

となります。

そのため、

  • display:nonevisibility:hiddennot visibledisabledvisible
  • display:nonevisibility:hiddenenableddisableddisabled
  • いずれもcontain

という挙動です。

 

Elementが見えている/見えていない時に何かする

例えば、

<button id="visible_button">
    見えてる
</button>

<button id="invisible_button" style="display: none">
    見えてない
</button>

があった時に、見えている/見えていないで処理を分ける場合、

# 見えてる
${visible} =  run keyword and return status  element should be visible  id=visible_button
run keyword if  ${visible}  log to console  見えてます

# 見えてない
${invisible} =  run keyword and return status  element should be visible  id=invisible_button
# 「run keyword unless」を使うことで、第一引数がfalseの時に log to console する
run keyword unless  ${invisible}  log to console  見えてないです

となります。

否定形の処理は、Run Keyword Unlessを使います。

 

テーブルに対する処理

例えば、

<div id="table_search">
    <table>
        <tr>
            <th>key</th>
            <th>value</th>
        </tr>
        <tr>
            <td>一行目のキー</td>
            <td>一行目の値</td>
        </tr>
    </table>
    <table>
        <tr>
            <th>項目</th>
            <th></th>
        </tr>
        <tr>
            <td>項目1</td>
            <td>値1</td>
        </tr>
        <tr>
            <td>項目2</td>
            <td>値2</td>
        </tr>
    </table>
</div>

というテーブルがあった時に、行・列・セルの処理をしたい場合は、

# 行番号(row)にはヘッダ行(th)も含まれていることに注意
# また、「table row should contain」は、指定した行のどこかの列にその文字列があればPASSする
table row should contain  css=#table_search > table:nth-child(2)  3  項目2
table row should contain  css=#table_search > table:nth-child(2)  3  値2

# 行・列の組み合わせで調べたい時は、「table cell should contain」を使う
# 行、列、値の順で指定する
table cell should contain  css=#table_search > table:nth-child(2)  3  2  値2

となります。

他にも、Table Header Should Containなど色々とありますので、ドキュメントを見ると良いかと思います。

 

ソースコード

GitHubに上げました。
thinkAmi-sandbox/RobotFramework-sample

selenium2_library_sampleディレクトリの中にあるものが今回のコードです。

構成は

  • target_app/target.py : Bottleアプリ
  • target_app/views/index.html : 対象のHTML
  • tests/selenium_page_test.robot : Selenium2Libraryを使ったテストコード

です。

python target.pyでBottleアプリを起動した後、RobotFrameworkのテストコードを実行して動作確認できます。