日本語ドキュメントがなく、えらい苦労したので記録しておく事にする
クラス定義
behat --init
で生成されるクラス定義に何をextendするか。まずここで迷う
class FeatureContext implements Context, SnippetAcceptingContext
これは、Behat+Selenium Webdriverで受け入れテストの自動化をやってみたでのクラス定義
単純にPHPでアレするだけならこれで構わないのだけど、WebUIのテストでは必須とも言える、要素をクリックする、だとか、ドコドコにナニナニを入力する、といった記述をしたい
結果だけ言うと、behat/mink-extension
から、RasMinkContext
をみんなextendしてたので、それをやったらやりたかった事が出来るようになった
<?php
use Behat\Behat\Context\Context;
use Behat\MinkExtension\Context\RawMinkContext; ←追加
use Behat\Behat\Context\SnippetAcceptingContext;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\TableNode;
/**
* Defines application features from the specific context.
*/
class FeatureContext extends RawMinkContext implements Context, SnippetAcceptingContext ←extends RawMinkContext追加
{
実行中セッションのDOMにアクセスしたい
実行中のセッションに対して何かする場合は、$this->getSession()->getPage()
でDOMにアクセスすることが出来ます
var_dump(get_class_methods($this->getSession()->getPage()));
array(31) {
[0]=>
string(8) "getXpath"
[1]=>
string(10) "getContent"
[2]=>
string(10) "hasContent"
[3]=>
string(8) "findById"
[4]=>
string(7) "hasLink"
[5]=>
string(8) "findLink"
[6]=>
string(9) "clickLink"
[7]=>
string(9) "hasButton"
[8]=>
string(10) "findButton"
[9]=>
string(11) "pressButton"
[10]=>
string(8) "hasField"
[11]=>
string(9) "findField"
[12]=>
string(9) "fillField"
[13]=>
string(15) "hasCheckedField"
[14]=>
string(17) "hasUncheckedField"
[15]=>
string(10) "checkField"
[16]=>
string(12) "uncheckField"
[17]=>
string(9) "hasSelect"
[18]=>
string(17) "selectFieldOption"
[19]=>
string(8) "hasTable"
[20]=>
string(17) "attachFileToField"
[21]=>
string(11) "__construct"
[22]=>
string(10) "getSession"
[23]=>
string(3) "has"
[24]=>
string(7) "isValid"
[25]=>
string(7) "waitFor"
[26]=>
string(4) "find"
[27]=>
string(7) "findAll"
[28]=>
string(7) "getText"
[29]=>
string(7) "getHtml"
[30]=>
string(12) "getOuterHtml"
}
findAll
を使って、DOM内の要素を検索します。(以下はログインボタンを探す例)
$submits = $this->getSession()->getPage()->findAll("css", "*[type='submit']");
$loginButton = false;
foreach($submits as $i => $row)
{
if("ログイン" === $row->getValue())
{
$loginButton = $row;
break;
}
}
cssセレクタがそのまま使えるので、findAll('css', [セレクタ])
が馴染みやすくてとても良いです
返ってきたオブジェクトには、DOM操作のためのメソッドが用意されています
var_dump(get_class_methods($loginButton));
array(55) {
[0]=>
string(11) "__construct"
[1]=>
string(8) "getXpath"
[2]=>
string(9) "getParent"
[3]=>
string(10) "getTagName"
[4]=>
string(8) "getValue"
[5]=>
string(8) "setValue"
[6]=>
string(12) "hasAttribute"
[7]=>
string(12) "getAttribute"
[8]=>
string(8) "hasClass"
[9]=>
string(5) "click"
[10]=>
string(5) "press"
[11]=>
string(11) "doubleClick"
[12]=>
string(10) "rightClick"
[13]=>
string(5) "check"
[14]=>
string(7) "uncheck"
[15]=>
string(9) "isChecked"
[16]=>
string(12) "selectOption"
[17]=>
string(10) "isSelected"
[18]=>
string(10) "attachFile"
[19]=>
string(9) "isVisible"
[20]=>
string(9) "mouseOver"
[21]=>
string(6) "dragTo"
[22]=>
string(5) "focus"
[23]=>
string(4) "blur"
[24]=>
string(8) "keyPress"
[25]=>
string(7) "keyDown"
[26]=>
string(5) "keyUp"
[27]=>
string(6) "submit"
[28]=>
string(8) "findById"
[29]=>
string(7) "hasLink"
[30]=>
string(8) "findLink"
[31]=>
string(9) "clickLink"
[32]=>
string(9) "hasButton"
[33]=>
string(10) "findButton"
[34]=>
string(11) "pressButton"
[35]=>
string(8) "hasField"
[36]=>
string(9) "findField"
[37]=>
string(9) "fillField"
[38]=>
string(15) "hasCheckedField"
[39]=>
string(17) "hasUncheckedField"
[40]=>
string(10) "checkField"
[41]=>
string(12) "uncheckField"
[42]=>
string(9) "hasSelect"
[43]=>
string(17) "selectFieldOption"
[44]=>
string(8) "hasTable"
[45]=>
string(17) "attachFileToField"
[46]=>
string(10) "getSession"
[47]=>
string(3) "has"
[48]=>
string(7) "isValid"
[49]=>
string(7) "waitFor"
[50]=>
string(4) "find"
[51]=>
string(7) "findAll"
[52]=>
string(7) "getText"
[53]=>
string(7) "getHtml"
[54]=>
string(12) "getOuterHtml"
}
このログインボタンをクリックするなら↓このようにclick
メソッドをコールします
$loginButton->click();
今回作ったメソッドは↓こちら
/**
* @When :acount でログインしている
*
* @param string $acount
*/
public function adminLogin($acount)
{
$this->getSession()->getPage()->fillField("login_id", $acount);
switch($acount)
{
case "admin":
$this->getSession()->getPage()->fillField("login_password", "xxxxxxxxxx");
break;
case "guest":
$this->getSession()->getPage()->fillField("login_password", "xxxxxxxxxx");
break;
}
$submits = $this->getSession()->getPage()->findAll("css", "*[type='submit']");
$loginButton = false;
foreach($submits as $i => $row)
{
if("ログイン" === $row->getValue())
{
$loginButton = $row;
break;
}
}
$loginButton->click();
}
これでfeature側に、「前提 ○○○でログインしている」という条件でログインが出来るようになりました
# language: ja
#
フィーチャ: アカウント新規登録
@javascript
シナリオ: アカウント作成
前提 ユーザーは "/login/" を表示している
前提 "admin" でログインしている