前回Google検索で作ったクラスを利用して、Jpostalで郵便番号から住所を自動入力するテストプログラムを作ります。
PuPHPeteerとは
WebアプリケーションのE2Eテストフレームワークの一つに、Puppeteer(パペッティア)があります。Puppeteerはブラウザを起動し、ブラウザを操作してE2Eテストをします。
PuPHPeteerは、PHPからPuppeteerを使うためのライブラリです。
前回
npm installやcomposer init、Google検索するテストプログラムを作りました。
郵便番号から住所を自動入力する
Jpostalをテストするテストプログラムを作ります。Jpostalは郵便番号から住所を自動入力するjqueryプラグインです。Jpostalは弊社が公開しています。
まず、手で操作します。
- 住所入力フォーム 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メソッドを使います。
プロパティ、メソッド | 説明 |
---|---|
$page | PuPHPeteerの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)
今回のまとめ
Jpostal100Test.php
BasePuppeteerTestCase.php