LoginSignup
1
0

More than 5 years have passed since last update.

【フロントエンド】テストが書かれていないプロダクトにE2Eテストを導入する

Posted at

:point_up: はじめに

本記事はテストを書かれていないプロダクトに比較的簡単にテストを導入するための記事になります。
また、本記事ではSPAでのテスト導入になります。

ソースコードはすべて公開しています。

:keyboard: テストツール

プラグインなど使用せずに標準で非同期通信に対応しているava puppeteer を採用しました。
また、テストブラウザはchromiumなのでIEなどでは別途検証が必要になります。

:page_facing_up: テスト説明

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 ディレクトリにはテストしたいフロー毎にファイルを作成し格納します。

:hammer_pick: 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);

:pick: テスト実行方法

package.json に下記スクリプトを追加

"test": "ava test/e2e/index.js --verbose"

下記コマンドを実行します。

npm run test

(テスト数) passed と表示されるとテスト成功になります。

:earth_africa: ソースコードの公開

テスト対象サイト: https://member-register.herokuapp.com/
ソースコード: https://github.com/Ut0n69/e2e-testing

:pray: おわりに

E2Eテストは比較的容易に導入できるため、テストが書かれていないプロダクトには導入をお勧めします。

デメリットとしてはメンテナンスが大変であること、またE2Eテストは壊れやすいことが考えられます。
さらに、導入した人がメンテナンスを続けなければいけない状況にもなりかねません。
しかし、テストが全くないことに比べると有益であるはずです。
修正による予期せぬ不具合にいち早く気付けることもあります。
E2Eテストの導入を検討してみてはいかがでしょうか。

以上

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0