PuPHPeteerでE2Eテスト

PuPHPeteerとは

Puppeteerは、なんて発音するの?

Wikiには「パペッティア」と書いてあるけど、発音は「パペティア」に聞こえるわね

PuPHPeteerは、なんて発音するの?

ピィエイチペッティアかしら?

話すときは「ピー・ユー・ピー・エイチ・ピー・ティア」のほうがわかりやすいかもね

WebアプリケーションのE2Eテストフレームワークの一つに、Puppeteer(パペッティア)があります。Puppeteerはブラウザを起動し、ブラウザを操作してE2Eテストをします。

Puppeteerは、npmでインストールして、Node.jsで記述します。素でSelenium WebDriverを使うよりも導入が簡単なので、人気が高いようです。

Puppeteer | Puppeteer
Build status

PuPHPeteerは、PHPからPuppeteerを使うためのライブラリです。

npmとcomposerでインストールします。npmでPuPHPeteerをインストールすると、Puppeteerもインストールされます。続けて、composerでもPuPHPeteerをインストールします。

PuPHPeteerのAPIドキュメントはありませんので、puppeteerのAPIドキュメントを調べます。

GitHub - rialto-php/puphpeteer: A Puppeteer bridge for PHP, supporting the entire API.
A Puppeteer bridge for PHP, supporting the entire API. - rialto-php/puphpeteer

PuPHPeteerで書いたE2Eテストのサンプルを見ていきましょう。初期化処理は省略します。

URLを指定して、表示します。

$page->goto('https://example.jp');Code language: PHP (php)

リンクやボタン、ラジオボタン、チェックボックスをクリックします。

$page->click('#button');Code language: PHP (php)

<input type="text"><textarea>の入力欄に入力します。

$page->type('#username', 'taro');Code language: PHP (php)

DOM要素の内容を取得します。$elがnullかどうかで、そのDOM要素があるかどうかを判断できます。

$el = $page->querySelector('.error-message');
if ($el !== null) {
    $text = $el->getProperty('textContent')->jsonValue();
    $text = ltrim(rtrim($text));
}Code language: PHP (php)

DOM要素の指定は、CSSセレクターを指定します。DOM idがあれば確実です。

DOM idを指定していない場合、Google ChromeのDeveloper toolで、HTML要素を探して、右クリック>コピー>CSSセレクターでわかります。

このように、人間がブラウザで操作することを、コツコツとプログラムとして記述していきます。

そして、ブラウザ操作やアサーションを書いていくと、すぐに数百行のメソッドになってしまいます。

そこで、E2Eテストのデザインパターンとして、Page Object Modelが考え出されました。

E2Eテストツールの元祖であるSeleniumのサイトに、E2Eテストのデザインパターンとして、Page Object Modelが紹介されています。

/ja/documentation/test_practices/encouraged/page_object_models/

インストール

まず、npmでPuPHPeteerをインストールします。

$ npm init

$ npm install @nesk/puphpeteerCode language: Bash (bash)

次に、composerでPuPHPeteerをインストールします。

$ composer init

$ composer require nesk/puphpeteerCode language: Bash (bash)

Puppeteerオプション

コンストラクタオプションは、PuPHPeteer独自のオプションです。APIドキュメント

<?php

$puppeteer = new Puppeteer(
    [
        'idle_timeout' => 600,
    ]
);Code language: PHP (php)

idle_timeout: 長時間放置してもブラウザを閉じないようにする

例えば「1分間操作をしなかったら、メッセージを表示をすること」を検証したいとき、次のように sleep(); で待ちたいのですが、

$page->click('#foo');
sleep(61);

$el = $page->querySelector('#help-message');
$this->assertTrue(el !== null);
Code language: PHP (php)

デフォルトでは30秒間ブラウザ操作をしないと、例外をスローしてブラウザを閉じてしまいます。

そこで、Puppeteerのコンストラクタオプションに、

        'idle_timeout' => 600,

を追加します。この例では、600秒、10分に設定しています。

launchオプション

$launchOptions = [
    'executablePath'    => '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
    'headless'          => false,
    'ignoreHTTPSErrors' => true,
    'slowMo'            => 50,

    'args' => [
        '--no-sandbox',
        '--disable-setuid-sandbox',
        "--window-size=1280,1024",
    ],
];

$puppeteer->launch($launchOptions);Code language: PHP (php)

executablePath: ブラウザの実行パス

Puppeteerは、Chromiumをnode_modules下にダウンロードして、デフォルトのブラウザとしてChromiumを使います。

macOS
node_modules/puppeteer/.local-chromium/mac-818858/chrome-mac/Chromium.app

Ubuntu 18
node_modules/puppeteer/.local-chromium/linux-818858/chrome-linux/chrome

ところが、macOSで実行すると、PuPHPeteerがブラウザを起動するたびに、次のダイアログが表示されました。

アプリケーション"Chromium.app"へのネットワーク受信接続を許可しますか

Google Chrome.app?

似ているけど、Chromium.app よ

許可をクリックしても、また表示されます。

システム環境設定>セキュリティ>ファイヤーウォールの一覧にはChromium.appがあるので、許可されていると思うのですが...

Chromium.appが/Applications/下ではないからなのでしょうか。

解決方法がわからず、macOSの場合は、インストール済みのGoogle Chromeを使うことにしました。

    'executablePath'    => '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',

次のコードは、macOSかどうかの判別ではなく、Chrome.appがあるかどうかで判別する例です。

$macosChromePath = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
if (file_exists($macosChromePath)) {
    $launchOptions['executablePath'] = $macosChromePath;
}Code language: PHP (php)

headless: ブラウザの表示/非表示

デフォルトは、'headless' => true で、ブラウザを表示しません。

ブラウザを表示しないことには、E2Eテストを作成するのは難しいので、

    'headless'          => false,

を追加して、ブラウザを表示します。

環境変数や .env (dotenv)の設定で切り替えられるようにしておくと便利です。

vlucas/phpdotenv - Packagist
Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.

ignoreHTTPSErrors: 証明書エラーの無視

テスト用サーバの証明書期限が切れていたり、オレオレ証明書だったりすると、証明書エラーでページを開けません。

net::ERR_CERT_AUTHORITY_INVALID

launchオプションに、

    'ignoreHTTPSErrors' => true,

を追加します。

slowMo: 操作速度の調整

デフォルトでは、いきおいよくタイプしたり、クリックして、次々に画面が変わっていきます。

いきおいがよすぎて、期待通りの操作をできないとき、clickやtypeの後に usleep(100000); をいれて調整してもいいのですが、slowMoでも設定できます。

// usleepで調整するよりも
$page->click('#fooButton');
usleep(100000);

slowMoを50〜100にすると、人間の操作感に近いそうです。

// slowMoで設定できるよ
    'slowMo'            => 50,

テストに通りやすくなったけど、時間もかかるようになるよ

args.--window-size: ブラウザ外枠のウィンドウサイズ

args は、Chromium/Chromeの起動オプションです。

ブラウザ外枠のウィンドウサイズを設定します。

    'args' => [
        "--window-size=1280,1024",

これとは別に、ブラウザウィンドウ内の各タブ($pageが該当)のViewport設定もします。

$pages = $browser->pages();
$page = $pages[0];
//または
$page = $browser->newPage();

$size = [
    'width'  => 1280,
    'height' => 1024,
];
$page->setViewport($size);

Code language: PHP (php)

widthもheightも0にすると、ウィンドウ内を最大に使います。

$size = [
    'width'  => 0,
    'height' => 0,
];
$page->setViewport($size);
Code language: PHP (php)

つづく

タイトルとURLをコピーしました