PuPHPeteerでE2Eテスト

PuPHPeteerとは

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

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

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

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

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

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

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

https://pptr.dev/

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

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

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

rialto-php/puphpeteer
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が紹介されています。

ページオブジェクトモデル :: Seleniumドキュメント
Documentation for Selenium

インストール

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

$ npm init $ npm install @nesk/puphpeteer
Code language: Bash (bash)

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

$ composer init $ composer require nesk/puphpeteer
Code 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をコピーしました