Puppeteer(パペティア)とは、スクリプトプログラム上からヘッドレス(GUI が起動しない状態)でブラウザを制御できる Node.js ライブラリです。
Web サイトのスクレイピングツールや Web システムの E2E テストプログラムを作成することができます。
テストを自動化したい場合に最適です。
開発言語は JavaScript で、Google Chrome の元となっている Chromium というブラウザプログラムが同梱されています。
参考: Webシステムにおける結合テスト
Puppeteer の公式サイト
https://developers.google.com/web/tools/puppeteer
Puppeteer のインストール
Puppeteer は Node.js のパッケージなので、npm でインストールします。
今回は npm のローカルインストールにて例示します。
>cd C:\NodeJS\local # インストール先ディレクトリ
>npm init # パッケージ情報を初期化する場合
>npm install puppeteer
カレントディレクトリのnode_modules
に実体がコピーされ、package.json
、package-lock.json
ファイルにパッケージ情報が追記されます。
これでインストールは完了です。
参考: Node.js のパッケージ管理ツール npm とは
npmjs.com
https://www.npmjs.com/package/puppeteer
テストの実行
まずは、Puppeteer をインストールしたディレクトリに、NODE_PATH
環境変数を通します。
通常、require
する対象が見つからなかった場合、Node.js はnode_modules
ディレクトリを探しに親階層を辿っていきます。
したがって参照先パッケージがインストールされているディレクトリ配下に参照元ソースファイルがあれば問題ありませんが、異なるディレクトリにソースファイルを置くと、cannot find module
になってしまいます。NODE_PATH
環境変数を設定しておくことで、ソースファイルを置く場所を意識せずにすみます。
>set NODE_PATH=C:\NodeJS\local\node_modules
テストの実行は、node
コマンドで行います。
テストコードはどこに存在していても構いません。
>cd C:\tests # テストコードの存在するディレクトリ
>node example.js # example.js を実行
テストプログラムの作成
以下、Puppeteer 公式サイトのサンプルコードを例にとって説明します。
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({path: 'example.png'});
await browser.close();
})();
1行目
Puppeteer パッケージをrequire
します。let
とconst
は、ES2015 から採用されたブロックスコープを持つ変数の宣言キーワードです。const
は再宣言・値の変更が不可であり、ここでは安全のためrequire
された値をconst
変数に代入しています。
ちなみにlet
は、再宣言は不可ですが値の変更は可能です。
3行目
Puppeteer のソースコードでは、慣例的にプログラム本体をasync
修飾子を付けたアロー関数(や無名関数)内に記述し、即時関数で囲みます。
もちろん異なる書き方もできますし、当該関数外のトップレベルに別のクラスやメソッドを定義することもできます。
async(非同期)なメソッド内では、処理完了を待つよう指定するawait
演算子を利用することができるようになります。
4~5行目
ブラウザを起動し、新しいページを開きます。
Node.js は、非同期型のイベント駆動モデルのアーキテクチャを採用しています。
したがって基本的に非同期的な動作が前提となっていますので、処理完了を待ちたい場合はawait
演算子を指定する必要があります。
テストプログラムでは、処理のほとんどにawait
を付けるような感じになるでしょう。
少々面倒ですね。
参考: 非同期型のイベント駆動モデル
6行目
は URL を引数にとり、指定された URL へページ移動します。
goto()
処理完了を待ちたいので、await
演算子が指定されています。
7行目screenshot()
はファイル名を引数にとり、現在ブラウザが開いているページのキャプチャ画像を出力します。
処理完了を待ちたいので、await
演算子が指定されています。
9行目
ブラウザを閉じます。
以下、テストコードの例です。
const puppeteer = require("puppeteer");
(async function(){
// ブラウザの起動にはいくつかのオプションがある
const browser = await puppeteer.launch({
headless: false, // ブラウザが立ち上がらない(defalut: true)
slowMo: 5, // Puppeteerの動作を遅延させる [ms]
devtools: true, // Chrome DevToolsを開く(default: false)
args: [
'--window-size=1600,950', // ウィンドウサイズ
'--window-position=100,50' // ウィンドウポジション
]
});
// ページ移動
const page = await browser.newPage();
await page.setViewport({width:1200, height:800}); // ビューポート指定
await page.goto("https://dev.softwarenote.info/test/test_exp01.php");
// 要素の取得にはCSSセレクタが使えます
const div = await page.$("#id"); // Object
const divs = await page.$$(".class"); // Array
// フォームの操作
await page.type('input[type="text"][name="post_textbox"]', "cypress.io") // テキストボックス
await page.type('textarea[name="post_textarea"]', "cypress.io"); // テキストエリア
await page.click('input[name="post_checkbox"]'); // チェックボックス
await page.click('input[name="post_radio"][value="val2"]'); // ラジオボタン value="val2"を選択する
await page.select('select[name="post_select"]', "val2"); // プルダウン value="val2"を選択する
await page.$eval('input[name="post_checkbox2"]', check => check.checked=true);
await page.click('[type="button"]'); // ボタンをクリックする
await page.type('input[name="post_textbox"]', "cypress.io") // 「cypress.io」と入力し
await page.keyboard.press("Enter"); // エンター
// その他の操作
await page.screenshot({path:"capture.png"}); // スクリーンショット
console.log("test log"); // ログ出力
await browser.close(); // ブラウザのクローズ
})();
コメント