はじめに
本記事はテストを書かれていないプロダクトに比較的簡単にテストを導入するための記事になります。
また、本記事ではSPAでのテスト導入になります。
ソースコードはすべて公開しています。
テストツール
プラグインなど使用せずに標準で非同期通信に対応しているava
puppeteer
を採用しました。
また、テストブラウザはchromium
なのでIEなどでは別途検証が必要になります。
テスト説明
E2Eテストディレクトリ構造
test
└── e2e
├── config.js
├── index.js
└── specs
└── memberRegister.js
config.js
config.js
はブラウザの設定などを記述します。
module.exports = {
URL: "http://localhost:8080",
browser: {
ignoreHTTPSErrors: true,
headless: true,
slowMo: 0,
args: ["--no-sandbox", "--disable-setuid-sandbox"]
},
basicAuth: {
userName: 'YOUR_USER_NAME',
password: 'YOUR_PASSWORD',
},
};
URL
テストを実行する環境を変更したい場合はURLを変更します。
URL: 'http://localhost:8080'
ブラウザ設定
ベーシック認証の情報もconfig.jsにまとめてあげると良いでしょう。
ヘッドレスモードはGUIベースではなくてCLIベースでのテストになります。
headless: true
の場合はバックグラウンドでCLIベースのテストが実行されます。
ブラウザが立ち上がらないため、テスト時間が短縮されます。
headless: false
の場合は実際にブラウザが立ち上がり自動操作が行われます。
基本的にはheadless: true
とし、ヘッドレスモードでテストを行います。
テストに失敗したり、実際に流れを確認したい場合にのみfalse
に変更します。
index.js
index.js
は実行するテストファイルを記述します。
/*
会員登録フローテスト
・入力
・入力不備によるエラーの出力チェック
・項目をすべて入力
・会員登録確定
*/
import memberRegister from "./specs/memberRegister";
(() => {
memberRegister();
})();
コメントの記述
どの部分のテストか、どのような流れで操作を行うか
についてコメントを書くと良いでしょう。
※ テストフローなどを修正した場合は必ずコメントも修正するよう心掛けます。
specs
specs
ディレクトリにはテストしたいフロー毎にファイルを作成し格納します。
ava puppeteerでのテスト記述方法
モジュールなどの読み込み
const puppeteer = require('puppeteer');
const test = require('ava');
const config = require('../config');
ava
puppeteer
及びconfig.jsを読み込みます。
テストしたいフローを記述
- ブラウザのセットアップ
- エラー出力のチェック
- 項目をすべて入力
- 会員登録確定
module.exports = function() {
test.serial("Setup", async t => {
// ここに操作を記述
});
test.serial("Show error", async t => {
// ここに操作を記述
});
test.serial("Input", async t => {
// ここに操作を記述
});
test("Completion", async t => {
// ここに操作を記述
});
};
入力 → エラー出力 → 入力 → 確定
順番通りに実行したい場合には上記のようにtest.serial(){ }
と記述します。
順番は関係なく並列実行したい場合はtest(){ }
と記述します。
操作を記述
事前準備
操作するためにはE2Eテスト用に新しくクラスまたはidをそれぞれのタグに付与します。
今回はわかりやすくするためにidを付与していきます。
<input type="text" />
↓
<input id="e2e-input-name" type="text" />
ページにアクセス
await page.goto(`${config.URL}/login`, {
waitUntil: 'networkidle2',
});
非同期通信のため、waitUntil: 'networkidle2',
オプションを記述します。
フォームに入力
await page.type('セレクタを指定','入力したいテキスト');
例
await page.type("#e2e-input-name", "Caroline");
クリック
await page.click('セレクタを指定');
ラジオボタン
await page.evaluate(() => {
const element = document.querySelectorAll('セレクタを指定')[0];
element.click();
});
ラジオボタンが複数ある場合は同じセレクタ名を付与し、配列のindexを指定して取得します。
セレクトボックス
await page.select('セレクタを指定', 'valueを指定');
注意点
SPAなのでDOMの描画はJSで処理されるので、ページ遷移には注意が必要です。
await page.goto(`${config.URL}/login`, {
waitUntil: 'networkidle2',
});
// 画面描画待ち
await page.waitForSelector('#e2e-input-name');
page.goto
メソッドを使用した直後はpage.waitForSelector
メソッドを使用して
ページが描画されるまで待機する処理を記述します。
さらに、ローディング画面などを画面に重ねて表示している場合にはpage.waitFor
メソッドを使用して、
ローディング画面が外れるまで待機する処理も記述すると良いでしょう。
await page.waitFor(1000);
テスト実行方法
package.json
に下記スクリプトを追加
"test": "ava test/e2e/index.js --verbose"
下記コマンドを実行します。
npm run test
(テスト数) passed
と表示されるとテスト成功になります。
ソースコードの公開
テスト対象サイト: https://member-register.herokuapp.com/
ソースコード: https://github.com/Ut0n69/e2e-testing
おわりに
E2Eテストは比較的容易に導入できるため、テストが書かれていないプロダクトには導入をお勧めします。
デメリットとしてはメンテナンスが大変であること、またE2Eテストは壊れやすいことが考えられます。
さらに、導入した人がメンテナンスを続けなければいけない状況にもなりかねません。
しかし、テストが全くないことに比べると有益であるはずです。
修正による予期せぬ不具合にいち早く気付けることもあります。
E2Eテストの導入を検討してみてはいかがでしょうか。
以上