前の記事:Behat+Selenium Webdriverで受け入れテストの自動化をやってみた
要素のクリック動作とかを自動でやりたかったので、CakePHPで学ぶ 継続的インテグレーションに載ってた、behatch/contexts
を入れてみた
composer.json
composerで入れます
{
"require-dev": {
"behat/behat": "3.*@stable",
"behat/mink": "1.*@stable",
"behat/mink-extension": "*",
"behat/mink-goutte-driver": "*",
"behat/mink-sahi-driver": "*",
"behat/mink-selenium2-driver": "*",
"behat/mink-zombie-driver": "*",
"behatch/contexts": "*", ←追加
},
"config": {
"bin-dir": "bin/"
}
}
インストール
$ php composer.phar update
behat.yml 編集
基本的には、ここ(Github)に載ってる通りです
$ cat behat.yml
default:
suites:
default:
path: %paths.base%/features
contexts:
- FeatureContext
- Behat\MinkExtension\Context\MinkContext
- behatch:browser ←追加
- behatch:debug ←追加
- behatch:system ←追加
- behatch:json ←追加
- behatch:table ←追加
- behatch:rest ←追加
- behatch:xml ←追加
extensions:
Behat\MinkExtension:
browser_name: firefox
base_url: http://example.com/
sessions:
default:
selenium2:
capabilities: {"browser":"firefox","version":"*"}
Sanpi\Behatch\Extension: ~ ←追加
chrome-via-webdriver:
extensions:
Behat\MinkExtension:
browser_name: chrome
base_url: http://example.com/
sessions:
default:
selenium2:
capabilities: {"browser":"chrome","version":"*"}
ie-via-webdriver:
extensions:
Behat\MinkExtension:
browser_name: internet explorer
base_url: http://example.com/
sessions:
default:
selenium2:
capabilities: {"browser":"internet explorer","version":"*"}
確認
たくさん増えてるか確認
$ ./bin/behat -dl
default | When :time 秒待つ
default | Given /^(?:|ユーザーは )ホームページを表示している$/
default | When /^(?:|ユーザーは )ホームページへ移動する$/
default | Given /^(?:|ユーザーは )"(?P<page>[^\s]+)" を表示している$/u
default | When /^(?:|ユーザーが )"(?P<page>[^\s]+)" へ移動する$/u
default | When /^(?:|ユーザーが )ページをリロードする$/u
default | When /^(?:|ユーザーが )履歴の前のページに戻る$/u
default | When /^(?:|ユーザーが )履歴の次のページヘ進む$/u
default | When /^(?:|ユーザーが )"(?P<button>(?:[^"]|\\")*)" ボタンをクリックする$/u
default | When /^(?:|ユーザーが )"(?P<link>(?:[^"]|\\")*)" のリンク先へ移動する$/u
default | When /^(?:|ユーザーが )"(?P<field>(?:[^"]|\\")*)" フィールドに "(?P<value>(?:[^"]|\\")*)" と入力する$/u
default | When /^(?:|ユーザーが )"(?P<field>(?:[^"]|\\")*)" フィールドに以下の値を入力する:$/u
default | When /^(?:|ユーザーが )"(?P<value>(?:[^"]|\\")*)" という値を "(?P<field>(?:[^"]|\\")*)" に入力する$/u
default | When /^(?:|ユーザーが)次のように入力する:$/u
default | When /^(?:|ユーザーが )"(?P<option>(?:[^"]|\\")*)" という値を "(?P<select>(?:[^"]|\\")*)" から選択する$/u
default | When /^(?:|ユーザーが )"(?P<option>(?:[^"]|\\")*)" という値を "(?P<select>(?:[^"]|\\")*)" から追加で選択する$/u
default | When /^(?:|ユーザーが )"(?P<option>(?:[^"]|\\")*)" にチェックをつける$/u
default | When /^(?:|ユーザーが )"(?P<option>(?:[^"]|\\")*)" のチェックをはずす$/u
default | When /^(?:|ユーザーが)パス "(?P<path>[^"]*)" にあるファイルを "(?P<field>(?:[^"]|\\")*)" に添付する$/u
default | Then /^(?:|ユーザーが )(?P<page>[^\s]+) を表示していること$/u
default | Then /^(?:|ユーザーが )ホームページを表示していること$/u
default | Then /^(?i)url(?-i)が (?P<pattern>"(?:[^"]|\\")*") にマッチすること$/u
default | Then /^レスポンスコードが (?P<code>\d+) であること$/u
default | Then /^レスポンスコードが (?P<code>\d+) ではないこと$/u
default | Then /^(?:|画面に )"(?P<text>(?:[^"]|\\")*)" と表示されていること$/u
default | Then /^(?:|画面に )"(?P<text>(?:[^"]|\\")*)" と表示されていないこと$/u
default | Then /^(?:|画面に )"(?P<pattern>"(?:[^"]|\\")*")" にマッチするテキストが表示されていること$/u
default | Then /^(?:|画面に )"(?P<pattern>"(?:[^"]|\\")*")" にマッチするテキストが表示されていないこと$/u
default | Then /^レスポンスに "(?P<text>(?:[^"]|\\")*)" が含まれていること$/u
default | Then /^レスポンスに "(?P<text>(?:[^"]|\\")*)" が含まれていないこと$/u
default | Then /^"(?P<element>[^"]*)" エレメントに "(?P<text>(?:[^"]|\\")*)" と表示されていること$/u
default | Then /^"(?P<element>[^"]*)" エレメントに "(?P<text>(?:[^"]|\\")*)" と表示されていないこと$/u
default | Then /^"(?P<element>[^"]*)" エレメントに "(?P<value>(?:[^"]|\\")*)" という値が含まれていること$/u
default | Then /^"(?P<element>[^"]*)" エレメントに "(?P<value>(?:[^"]|\\")*)" という値が含まれていないこと$/u
default | Then /^(?:|画面に )"(?P<element>[^"]*)" エレメントが表示されていること$/u
default | Then /^(?:|画面に )"(?P<element>[^"]*)" エレメントが表示されていないこと$/u
default | Then /^"(?P<field>(?:[^"]|\\")*)" フィールドに "(?P<value>(?:[^"]|\\")*)" が含まれていること$/u
default | Then /^"(?P<field>(?:[^"]|\\")*)" フィールドに "(?P<value>(?:[^"]|\\")*)" が含まれていないこと$/u
default | Then /^チェックボックス "(?P<checkbox>(?:[^"]|\\")*)" のチェックがついていること$/u
default | Then /^the checkbox "(?P<checkbox>(?:[^"]|\\")*)" (?:is|should be) checked$/
default | Then /^チェックボックス "(?P<checkbox>(?:[^"]|\\")*)" のチェックがはずれていること$/u
default | Then /^the checkbox "(?P<checkbox>(?:[^"]|\\")*)" should (?:be unchecked|not be checked)$/
default | Then /^the checkbox "(?P<checkbox>(?:[^"]|\\")*)" is (?:unchecked|not checked)$/
default | Then /^(?:|画面に )(?P<num>\d+) 個の "(?P<element>[^"]*)" エレメントが表示されていること$/u
default | Then /^現在のURLを表示$/
default | Then /^最後のレスポンスを表示$/u
default | Then /^最後のレスポンスをブラウザで表示$/u
default | When /^Basic認証を"(?P<user>[^"]*)"と"(?P<password>[^"]*)"で設定する$/u
default | Given /^(?:|私が)下記から構成されるURLに遷移する:$/u
default | When (私が ):index 番目の :element 要素をクリックする
default | When (私が ):index 番目の :link に遷移する
default | When /^(?:|私が)"(?P<field>[^"]*)"に現在の日付を入力する$/u
default | When /^(?:|私が)"(?P<field>[^"]*)"に現在の日付を"(?P<modifier>[^"]*)"で入力する$/u
default | When /^(?:|私が)"(?P<element>[^"]*)"にhoverする$/u
default | When /^(?:|私が)"(?P<field>[^"]*)"の値を"(?P<parameter>[^"]*)"パラメーターに保存する$/u
default | Then /^(?:|私が)"(?P<text>[^"]*)"を見るまで(?P<seconds>\d+)秒間?待つ$/u
default | Then /^(?:|私が)"(?P<text>[^"]*)"を見るまで待つ$/u
default | Then /^(?:|私が)"(?P<element>[^"]*)"要素(?:で|に)"(?P<text>[^"]*)"を見るまで(?P<seconds>\d+)秒間?待つ$/u
default | Then /^(?:|私が)(?P<seconds>\d+)秒間?待つ$/u
default | Then /^(?:|私が)"(?P<element>[^"]*)"要素(?:で|に)"(?P<text>[^"]*)"を見るまで待つ$/u
default | Then (私が):element要素を見るまで待つ
default | Then (私が ):element 要素を見るまで :count 秒(間)待つ
default | Then /^(?P<index>\d+)番目の"(?P<parent>[^"]*)"(?:|要素)が(?P<count>\d+)個の"(?P<element>[^"]*)"(?:|要素)を持つこと$/u
default | Then /^(?P<index>\d+)番目の"(?P<parent>[^"]*)"(?:|要素)が(?P<nth>\d+)個以下の"(?P<element>[^"]*)"(?:|要素)を持つこと$/u
default | Then /^(?P<index>\d+)番目の"(?P<parent>[^"]*)"(?:|要素)が(?P<nth>\d+)個以上の"(?P<element>[^"]*)"(?:|要素)を持つこと$/u
default | Then /^"(?P<element>[^"]*)"(?:|要素)が有効であること$/u
default | Then /^"(?P<element>[^"]*)"(?:|要素)が無効であること$/u
default | Then /^セレクトボックス"(?P<select>[^"]*)"は"(?P<option>[^"]*)"を含むこと$/u
default | Then /^セレクトボックス"(?P<select>[^"]*)"は"(?P<option>[^"]*)"を含まないこと$/u
default | Then /^要素"(?P<element>[^"]*)"は可視であること$/u
default | Then /^要素"(?P<element>[^"]*)"は不可視であること$/u
default | When (私が ):name iframeにフォーカスする
default | When (私が ):name frameにフォーカスする
default | When (私が )メインフレームにフォーカスする
default | Then /^(?:|私が)ブレークポイントを設置する$/u
default | When /^(?:|私が)スクリーンショットを"(?P<filename>[^"]*)"に保存する$/u
default | When /^(?:|私が)ファイル"(?P<file>[^"]*)"を"(?P<field>(?:[^"]|\\")*)"に設定する$/u
default | Given /^(?:|私が)"(?P<command>[^"]*)"を実行する$/u
default | Given /^(?:|私が)"(?P<command>[^"]*)"をプロジェクトルートから実行する$/u
default | Given (私が):filenameというファイルを下記のテキストで作成する:
default | Given (I )create the file :filename contening:
default | Then :filenameというファイルのテキストを表示する
default | Then /^レスポンスがJSON(?:|形式)であること$/u
default | Then /^レスポンスがJSON(?:|形式)でないこと$/u
default | Then /^JSONのノード"(?P<node>[^"]*)"が"(?P<text>[^"]*)"と等しいこと$/u
default | Then /^JSONのノード"(?P<node>[^"]*)"が(?P<nth>\d+)個の要素を持つこと$/u
default | Then /^JSONのノード"(?P<node>[^"]*)"が"(?P<text>[^"]*)"を含むこと$/u
default | Then /^JSONのノード"(?P<node>[^"]*)"が"(?P<text>[^"]*)"を含まないこと$/u
default | Given /^JSONにノード"(?P<name>[^"]*)"が存在すること$/u
default | Given /^JSONにノード"(?P<name>[^"]*)"が存在しないこと$/u
default | Then /^JSONが下記のスキーマに従っていること:$/u
default | Then /^JSONがスキーマファイル"(?P<filename>[^"]*)"に従っていること$/u
default | Then /^JSONが下記と一致すること:$/u
default | Then 最後のJSONレスポンスを表示する
default | Then /^テーブル"(?P<table>[^"]*)"のカラムスキーマが下記と一致すること:$/u
default | Then /^テーブル"(?P<table>[^"]*)"が(?P<nth>\d+)個のカラムを持つこと$/u
default | Then /^(?P<index>\d+)番目のテーブル"(?P<table>[^"]*)"が(?P<nth>\d+)行持つこと$/u
default | Then /^テーブル"(?P<table>[^"]*)"が(?P<nth>\d+)行持つこと$/u
default | Then /^テーブル"(?P<table>[^"]*)"の(?P<nth>\d+)行目のデータが下記と一致すること:$/u
default | Then /^テーブル"(?P<table>[^"]*)"の(?P<rowIndex>\d+)行目(?P<colIndes>\d+)列が"(?P<text>[^"]*)"を含むこと$/u
default | Given /^(?:|私が)(?P<method>[A-Z]+)メソッドで"(?P<url>[^"]*)"へリクエストを送る$/u
default | Given /^(?:|私が)(?P<method>[A-Z]+)メソッドで"(?P<url>[^"]*)"へ下記のパラメーターを伴ったリクエストを送る:$/u
default | Given /^(?:|私が)(?P<method>[A-Z]+)メソッドで"(?P<url>[^"]*)"へ下記のボディを持ったリクエストを送る:$/u
default | Then /^レスポンスが下記と一致すること:$/u
default | Then /^レスポンスが空であること$/u
default | Then /^"(?P<name>[^"]*)"ヘッダが"(?P<value>[^"]*)"と一致すること$/u
default | Then /^"(?P<name>[^"]*)"ヘッダが"(?P<value>[^"]*)"を含むこと$/u
default | Then /^"(?P<name>[^"]*)"ヘッダが"(?P<value>[^"]*)"を含まないこと$/u
default | Then /^"(?P<name>[^"]*)"ヘッダが存在しないこと$/u
default | Then /^レスポンスが将来期限切れになること$/u
default | Then /^(?:|私が)"(?P<name>[^"]*)"ヘッダに"(?P<value>[^"]*)"を追加する$/u
default | Then /^レスポンスが"(?P<encoding>[^"]*)"でエンコードされていること$/u
default | Then /^最後のレスポンスヘッダを表示する$/u
default | Then /^curlコマンドを表示する$/u
default | Then レスポンスがXML(形式)であること
default | Then レスポンスがXML(形式)でないこと
default | Then (この)XML(に)は :element 要素が存在していること
default | Then (この)XML(に)は :element 要素が存在していないこと
default | Then (この)XMLの :element 要素は :text と一致していること
default | Then (この)XMLの :element 要素は :text と一致していないこと
default | Then (この)XMLの :element 要素(に)は :attribute 属性が存在していること
default | Then (この)XMLの :element 要素(に)は :attribute 属性が存在していないこと
default | Then (この)XMLの :element 要素の :attribute 属性は :text と一致していること
default | Then (この)XMLの :element 要素の :attribute 属性は :text と一致していないこと
default | Then (この)XML(に)は :element 要素を :count 個含んでいること
default | Then (この)XMLの :element 要素は :text を含んでいること
default | Then (この)XMLの :element 要素は :text を含んでいないこと
default | Then (この)XMLは名前空間 :namespace を使っていること
default | Then (この)XMLは名前空間 :namespace を使っていないこと
default | Then 最後のXMLレスポンスを表示する
default | Then /^XMLフィードが自身のDTDに従っていること$/u
default | Then /^XMLフィードがXSDファイル"(?P<filename>[^"]*)"に従っていること$/u
default | Then /^XMLフィードが下記のXSDに従っていること:$/u
default | Then /^XMLフィードがrelax NG schemaファイル"(?P<filename>[^"]*)"に従っていること$/u
default | Then /^XMLフィードが下記のrelax NG schemaに従っていること:$/u
default | Then /^atomフィードが妥当であること$/u
default | Then /^RSS2フィードが妥当であること$/u
これで、目的のフィーチャが記述できるようになりました
シナリオ: ログイン失敗[存在しないアカウント]
前提 ユーザーは "/auth/login/" を表示している
ならば "ログイン" と表示されていること
かつ "login_id" フィールドに "admi" と入力する
かつ "login_password" フィールドに "xxxxxx" と入力する
もし 私が 1 番目の "input[type='submit']" 要素をクリックする ←これと
ならば "認証情報が一致しませんでした。" と表示されていること
かつ スクリーンショットを"login_failed.jpg"に保存する ←これ