PuPHPeteerでE2Eテスト(3) Jpostalで郵便番号から住所を自動入力

前回Google検索で作ったクラスを利用して、Jpostalで郵便番号から住所を自動入力するテストプログラムを作ります。

PuPHPeteerとは

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

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

前回

npm installやcomposer init、Google検索するテストプログラムを作りました。

郵便番号から住所を自動入力する

Jpostalをテストするテストプログラムを作ります。Jpostalは郵便番号から住所を自動入力するjqueryプラグインです。Jpostalは弊社が公開しています。

J-POSTAL

まず、手で操作します。

  • 住所入力フォーム https://jpostal-1006.appspot.com/sample_1.html を表示します。
  • 郵便番号の最初の3桁に「100」を入力します。
  • 都道府県が「東京都」になるはずです。
  • 市区町村が「千代田区」になるはずです。
  • 郵便番号の次の4桁に「0001」を入力します。
  • 町域が「千代田」になるはずです。

最初のテスト

まず、必ず合格する単純なテストを書いて、テストが動くことを確認します。

study_puphpeteer ├── composer.json ├── node_modules ├── package.json ├── phpunit.sh ├── phpunit.xml ├── tests │   ├── BasePuppeteerTestCase.php │   ├── GoogleSearchTest.php │   └── Jpostal100Test.php // ★コレ └── vendor
Code language: plaintext (plaintext)

tests/Jpostal100Test.php

tests/Jpostal100Test.phpを新規作成します。必ず合格する単純なテストを書きます。

<?php namespace Ninton\Test; use PHPUnit\Framework\TestCase; class Jpostal100Test extends TestCase { public function testSmoke(): void { $this->assertTrue(true); } }
Code language: PHP (php)

テスト実行

ターミナルでテスト実行します。最後にグリーンで「OK (1 test, 1 assertion)」と表示されたら、テスト合格です!

$ ./phpunit.sh tests/Jpostal100Test.php + ./vendor/bin/phpunit --configuration=phpunit.xml tests/Jpostal100Test.php PHPUnit 8.5.14 by Sebastian Bergmann and contributors. . 1 / 1 (100%) Time: 121 ms, Memory: 4.00 MB OK (1 test, 1 assertion)
Code language: Bash (bash)

tests/BasePuppeteerTestCase.php

前回、共通部分をリファクタして、tests/BasePuppeteerTestCase.phpを作りました。このクラスの$pageプロパティ、スクリーンショットを保存するscreenShotoメソッド、次のページ表示を待つwaitForPageLoadメソッドを使います。

study_puphpeteer/BasePuppeteerTestCase.php at main · ninton/study_puphpeteer
study PuPHPeteer. Contribute to ninton/study_puphpeteer development by creating an account on GitHub.
プロパティ、メソッド説明
$pagePuPHPeteerのPageオブジェクト
setUp()ブラウザを起動します
tearDown()ブラウザを終了します
waitForPageLoad()次のページの表示を待ちます
screenShot()スクリーンショットを保存します

tests/Jpostal100Test.phpを編集します。BasePuppeteerTestCaseをextendsします。

<?php namespace Ninton\Test; use PHPUnit\Framework\TestCase; class Jpostal100Test extends BasePuppeteerTestCase { public function testSmoke(): void { $this->assertTrue(true); } }
Code language: PHP (php)

テスト実行

この段階で、ターミナルでテスト実行します。数秒かかってブラウザが起動し、すぐに閉じるはずです。

最後にグリーンで「OK (1 test, 1 assertion)」と表示されたら、テスト合格です!

$ ./phpunit.sh tests/Jpostal100Test.php + ./vendor/bin/phpunit --configuration=phpunit.xml tests/Jpostal100Test.php PHPUnit 8.5.14 by Sebastian Bergmann and contributors. . 1 / 1 (100%) Time: 5.03 seconds, Memory: 6.00 MB OK (1 test, 1 assertion)
Code language: Bash (bash)

郵便番号から住所を自動入力する

testSmokeメソッドは削除します。コメントで残しておいてもかまいません。

新しく、次のメソッドを追加します。

public function test_1000001は東京都千代田区千代田(): void { }
Code language: PHP (php)

手で操作した手順にしたがって、プログラムを書いていきます。

  • 住所入力フォーム https://jpostal-1006.appspot.com/sample_1.html を表示します。
  • 郵便番号の上3桁に「100」を入力します。
  • 都道府県が「東京都」になるはずです。
  • 市区町村が「千代田区」になるはずです。
  • 郵便番号の下4桁に「0001」を入力します。
  • 町域が「千代田」になるはずです。

住所入力フォーム https://jpostal-1006.appspot.com/sample_1.html を表示します。

Pageクラスのgotoメソッドを使います。

$this->page->goto('https://jpostal-1006.appspot.com/sample_1.html');
Code language: PHP (php)

郵便番号の上3桁に「100」を入力します。

Pageクラスのtypeメソッドを使います。

上3桁のINPUTタグのHTMLソースを見ると、

<input id="postcode1" name="postcode1" maxlength="3">
Code language: HTML, XML (xml)

なので、DOM idは、"postcode1"です。CSSセレクターに '#postcode1' を指定します。

Jpostalは上3桁を入力したときに、ajaxでデータをダウンロードして、住所欄に自動入力します。多くの場合、0.5秒もかかりませんが、ねんのため2秒待つことにしました。

$this->page->type('#postcode1', '100'); sleep(2); $this->screenShot();
Code language: PHP (php)

ここで、テストを実行してみます。

スクリーンショットを見ると、"100"が自動入力されて、東京都、千代田区になるはずですが...なりましたね!

3桁を入力した時点で、Ajaxでデータをダウンロードしているんだね

仮に、onblur(フォーカスが離れた)イベントで、自動入力していたとするね、

としたら、3桁を入力した時点では、onblurイベントは発生しないよね?どうすればいいのかな?

タブ「\t」をtypeしてみたけど、次の入力欄にフォーカス移動しなかったわ

別の入力欄をクリックしたら、onblurイベントが発生しわ

あとね、決め打ちで2秒待つより、Ajax通信を待ったほうがスマートだよね?

本家のPuppeteerでは、await Promise.allでpage.typeとpage.waitForResponseを待つみたいだけど、同じことをPHPやPuPHPeteerでどうやるのかわからなかったわ

都道府県が「東京都」になるはずです。

PageクラスのquerySelectorメソッドや、ElementHandleのgetPropertyメソッドを使って、value属性を取得します。

都道府県のSELECTタグのHTMLソースを見ると、

<span>都道府県</span> <select id="address1" name="address1">
Code language: HTML, XML (xml)

なので、DOM idは、"address1"です。CSSセレクターに '#address1' を指定します。

$el = $this->page->querySelector('#address1'); $value = $el->getProperty('value')->jsonValue(); $this->assertEquals('東京都', $value);
Code language: PHP (php)

市区町村が「千代田区」になるはずです。

PageクラスのquerySelectorメソッドや、ElementHandleのgetPropertyメソッドを使って、value属性を取得します。

市区町村のINPUTタグのHTMLソースを見ると、

<span>市区町村</span> <input id="address2" name="address2">
Code language: HTML, XML (xml)

なので、DOM idは、"address2"です。CSSセレクターに '#address2' を指定します。

$el = $this->page->querySelector('#address2'); $value = $el->getProperty('value')->jsonValue(); $this->assertEquals('千代田区', $value);
Code language: PHP (php)

郵便番号の下4桁に「0001」を入力します。

Pageクラスのtypeメソッドを使います。

下4桁のINPUTタグのHTMLソースを見ると、

<input id="postcode2" name="postcode2" maxlength="4">
Code language: HTML, XML (xml)

なので、DOM idは、"postcode2"です。CSSセレクターに '#postcode2' です。

上3桁下4桁を入力した時点で、ダウンロード済みのデータから検索して、再度、住所欄に自動入力します。すでにデータはダウンロード済みなので、0.1秒も待てば充分です。

$this->page->type('#postcode2', '0001'); usleep(100000); $this->screenShot();
Code language: PHP (php)

ブラウザ上のJavaScript処理は0.1秒待てば充分ってこと?

Jpostalは0.1秒でもいいけど、

テスト対象のページのJavaScript処理によって調整してね

町域が「千代田」になるはずです。

PageクラスのquerySelectorメソッドや、ElementHandleのgetPropertyメソッドを使って、value属性を取得します。

町域のINPUTタグのHTMLソースを見ると、

<span>町域</span> <input id="address3" name="address3">
Code language: HTML, XML (xml)

なので、DOM idは、"address3"です。CSSセレクターに '#address3' を指定します。

$el = $this->page->querySelector('#address3'); $value = $el->getProperty('value')->jsonValue(); $this->assertEquals('千代田区', $value);
Code language: PHP (php)

すでに入力欄に表示されているとき

さきほどのテストに続けて、下4桁に"0002"を入力して、町域が「皇居外苑」になることをテストしてみましょう。

$this->page->type('#postcode2', '0002'); usleep(100000); $this->screenShot(); $el = $this->page->querySelector('#address3'); $value = $el->getProperty('value')->jsonValue(); $this->assertEquals('皇居外苑', $value);
Code language: PHP (php)

テストを実行すると、失敗してしまいました。

$ ./phpunit.sh tests/Jpostal100Test.php + ./vendor/bin/phpunit --configuration=phpunit.xml tests/Jpostal100Test.php PHPUnit 8.5.14 by Sebastian Bergmann and contributors. F 1 / 1 (100%) Time: 10.24 seconds, Memory: 6.00 MB There was 1 failure: 1) Ninton\Test\Jpostal100Test::test_1000001は東京都千代田区千代田 Failed asserting that two strings are equal. --- Expected +++ Actual @@ @@ -'皇居外苑' +'千代田' /home/aoki/projects/personals/study/study_puphpeteer/tests/Jpostal100Test.php:39 FAILURES!
Code language: Bash (bash)

メソッド終了前に sleep(5); などを入れて、ブラウザを見て確認したり、スクリーンショットを確認します。

下4桁が「0001」のままですね。

Pageクラスのtypeメソッドは、すでに入力済みの内容をクリアせずに「追記」します。

手でキーボードから入力するとき、すでに入力済みの内容があるときは、BackSpaceキーやDeleteキーで削除します。

Puppeteerの場合も、すでに入力済みの内容があるときは、クリアしてからタイプします。

ASCIコードの0x08をtypeしてみたけど、削除できなかったわ

残念ながら、Puppeteerには、入力欄をクリアするAPIは用意されていません。開発者の提案する方法は、次のJavaScriptコードです。

await page.$eval(selector, element => element.value = ''); // または await page.evaluate(selector => document.querySelector(selector).value = '', selector);
Code language: JavaScript (javascript)

このコードをPuPHPeteer用に置き換えて、BasePuppeteerTestCase.phpに追加します。

メソッド説明
pageType(string $selector, string $text)入力欄をクリアしてから、入力する
pageTypeClear(string $selector)入力欄をクリアする
use Nesk\Rialto\Data\JsFunction; class BasePuppeteerTestCase extends TestCase { ... /** * @param string $selector */ protected function pageTypeClear(string $selector): void { $jsFunc = JsFunction::createWithBody("document.querySelector('${selector}').value = '';"); $this->page->evaluate($jsFunc); usleep(100000); } /** * @param string $selector * @param string $text */ protected function pageType(string $selector, string $text): void { $this->pageTypeClear($selector); $this->page->type($selector, $text); } }
Code language: PHP (php)

この pageTypeメソッドを使って、"0002"を入力します。

$this->pageType('#postcode2', '0002'); usleep(100000); $this->screenShot(); $el = $this->page->querySelector('#address3'); $value = $el->getProperty('value')->jsonValue(); $this->assertEquals('皇居外苑', $value);
Code language: PHP (php)

テストを実行すると、無事テストが通りました。

$ ./phpunit.sh tests/Jpostal100Test.php + ./vendor/bin/phpunit --configuration=phpunit.xml tests/Jpostal100Test.php PHPUnit 8.5.14 by Sebastian Bergmann and contributors. . 1 / 1 (100%) Time: 14.18 seconds, Memory: 6.00 MB OK (1 test, 4 assertions)
Code language: Bash (bash)
feat: add page.clear method by yanivefraim · Pull Request #3180 · puppeteer/puppeteer
I wasn't sure about implementation (if to use setSelection + backspace or just to clear the value). Setting element.value = '' was the easiest... (:...

今回のまとめ

Jpostal100Test.php

study_puphpeteer/Jpostal100Test.php at main · ninton/study_puphpeteer
study PuPHPeteer. Contribute to ninton/study_puphpeteer development by creating an account on GitHub.

BasePuppeteerTestCase.php

study_puphpeteer/BasePuppeteerTestCase.php at main · ninton/study_puphpeteer
study PuPHPeteer. Contribute to ninton/study_puphpeteer development by creating an account on GitHub.

つづく

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