Behat3/Mink Extension で複数のウェブドライバーを目的に応じて切り替える


Behat の Mink Extension を使うとリモートのウェブサイトに対する E2E テストを実行することができます。

Mink Extension では、以下の URL に書いてある通り複数の WebDriver をサポートしています。

http://mink.behat.org/en/latest/guides/drivers.html

多くの場合、Selenuim2 を使えば、テスト先のウェブサイトの JavaScript や CSS のテストも可能で、スクリーンショットを自動的に取ったりすることもできます。

また、ウインドウサイズを変更することもできますのでレスポンシブデザインのテストも自動化することができます。

https://github.com/vccw-team/wordpress-extension/blob/master/features/

ただし、Selenium2 ドライバーではレスポンスヘッダーへのアクセスができません。

これについては、Selenium2 の開発チームもそれはサポートしないよという旨のことを GitHub でたびたび発言していて、その理由をいろいろ読んでみると仕方なさそうですね。。。

https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/141

## Goutte ドライバーを使ってレスポンスヘッダーにアクセスする

上述のように Selenium2 では レスポンスヘッダーにアクセスできませんが、Goutte ドライバーを使えばそれが可能になります。

```php
// HTTP ステータスコードを取得
$this->getSession()->getStatusCode();
```

ただし、Goutte ドライバーでは、JavaScript の実行やウインドウサイズの変更、スクリーンショットの取得等ができません。

そこで、実行したいテストの内容によって WebDriver を切り替えるようにしてみます。

### behat.yml に複数のウェブドライバーを追加する

まず、`behat.yml` に複数の今回使用したい Selenium2 ドライバーと、Goutte ドライバーを追加します。

```behat.yml
default:
  suites:
    default:
      paths:
        - %paths.base%/features
      contexts:
        - FeatureContext
        - Behat\MinkExtension\Context\MinkContext
  extensions:
    Behat\MinkExtension:
      base_url: http://127.0.0.1:8080
      default_session: default
      sessions:
        default:
          selenium2:
            wd_host: http://127.0.0.1:4444/wd/hub
        goutte:
          goutte: ~

```

重要な項目は以下です。

* `default` > `extensions` > `Behat\MinkExtension` > `default_session`
* `default` > `extensions` > `Behat\MinkExtension` > `sessions`

ひとつめの `default_session` はデフォルトのウェブドライバーを指定します。 この値には `sessions` 以下の要素のうちの一つを入れる必要があります。

Behat では、`@mink:selenium2` のようなタグを記述することで、そのシナリオで使用する WebDriver を切り替えることができます。

`default_sessions` を記述すると、このタグが指定されていない時に、ここで指定したドライバーが使用されます。

ふたつめの `sessions` という項目には使用したい WebDriver を記述します。ここで項目名を `default` って書けばそれがデフォルトになるのかと思ってましたが、上述の `default_session` を記述しないとダメみたいで、それに気がつくまでにかなりハマりました。

それぞれの WebDriver は、`composer require` することを忘れないこと。

あと、`base_url` ってやつはテスト先のサイトのURLですね。

### テストを書く

テストは以下のように記述します。

```
Feature: HTTP response

  @mink:goutte
  Scenario: Check http status code

    When I am on "/"
    Then the HTTP status should be 200

    When I am on "/the-page-not-found"
    Then the HTTP status should be 404

```

このテストのためのコンテキストは以下のような感じ

```
	/**
	 * Check http status code.
	 *
	 * @param string $expect The HTTP status code.
	 * @then /^the HTTP status should be (?P<expect>[0-9]+)$/
	 */
	public function the_http_status_should_be( $expect )
	{
		$status = $this->getSession()->getStatusCode();
		$this->assertSame( intval( $status ), intval( $expect ), sprintf(
			'The HTTP status is %1$s, but it should be %2$s',
			$status,
			$expect
		) );
	}
```

この例の場合 `@mink:goutte` というタグがあれば、Goutte ドライバーが使用され、レスポンスヘッダー等にアクセスすることができます。

このタグがないと以下のようにエラーとなります。

```
Status code is not available from Behat\Mink\Driver\Selenium2Driver (Behat\Mink\Exception\UnsupportedDriverActionException)
```

## WordPress 用エクステンションについて

この記事で説明した内容は以下のリポジトリでみることができます。

https://github.com/vccw-team/wordpress-extension

このプロジェクトでは、WordPress に対する E2E テストのための Mink エクステンションに取り組んでいます。