Nightwatch.js の E2E テストでメールの配信をテストする

 English

Screenshot

Nightwatch.js で書いた E2E テストプロジェクトで、MandrillRequestBin を使ってメールの配信もテストするサンプルプロジェクトを公開しました。

ngs/nightwatch-mail-example on GitHub

このサンプルプロジェクトは Hacker News Letter を購読・購読解除を行うユーザーの操作を実行しています。

テストコードは以下の様な書き方です:

page
  .navigate()
  //
  // Mandrill のメールルートを作成する
  .createEmailRoute(email)
  //
  // フォーム入力
  .waitForElementVisible("@form")
  .clearValue("@email")
  .setValue("@email", email)
  .click("@submit")
  //
  // 完了画面に遷移
  .waitForElementNotPresent("@form")
  .assert.urlEquals(page.url + "almostfinished.html")
  //
  // 指定した件名のメールの受信を確認
  .assert.receivedEmailSubjectEquals(
    email,
    "Hacker Newsletter: Please Confirm Subscription"
  )
  //
  // 指定した文字列が HTML 本文に含まれるメールの受信を確認
  .assert.receivedEmailHTMLBodyContains(
    email,
    '<a class="button" href="https://hackernewsletter.us1.list-manage.com/subscribe/confirm?u='
  );

全てのコードを見る.

動機

弊社では最近 Nightwatch.js を製品の E2E テスト実装に導入し、とても簡単でシンプルに Web アプリケーションのテストコードを記述できるので気に入りました。。

テストコードを書いている最中、メールの受信を介したユーザーフローのテストコードを書こうと思い、Nightwatch.js を拡張して、カスタムアクションとアサージョンを実装しました。

ref: Extending Nightwatch - Nightwatch Developer Guide

導入方法

1. Mandrill の受信ドメイン (Inbound Domain) を設定する

まず、Mandrill のドキュメントを参考にして、受信用のメールドメイン (Inbound Email Domain) を設定します。

ドメインを入力し、Inbound Domains 画面の青い + Add ボタンをクリックするだけです。

Inbound Domains

ドメインを追加したら、MX Setup ポップアップに記載されている DNS レコードを追加します。

MX Setup

2. Mandrill の API キーを取得する

次に、Mandrill の API を設定画面から取得します。

API Key

間違えて実際にメールを誰かに送ってしまわないために、Test Key チェックボックスはオンにすることをお勧めします。

3. (任意) 自身の RequestBin を使う

配信されたメール RequestBin で他の人でも閲覧ができます。もしアプリケーションから配信されるメールを一般から閲覧できることに懸念がある場合には、自身の RequestBinHerokuIBM Bluexixオープンソースの RequestBin をデプロイすることで、利用できます。

git clone git://github.com/Runscope/requestbin.git
cd requestbin

heroku create
heroku addons:add heroku-redis
heroku config:set REALM=prod

git push heroku master

4. 環境変数

サンプルプロジェクトを実行するために、上記の手順で取得した情報を環境変数に書き出します。

自分は direnv をローカル環境変数の管理に使っています:

echo "export MANDRILL_API_KEY=${YOUR_API_KEY_HERE}" >> .envrc
echo "export MAIL_DOMAIN=${YOUR_MAIL_DOMAIN_HERE}" >> .envrc

# If you set up your own RequestBin in Step 3
echo "export REQUEST_BIN_HOST=https://${YOUR_HEROKU_APP}.herokuapp.com" >> .envrc

# Allow new environment variables
direnv allow

5. NPM!

これで、npm コマンドを使ってサンプルテストスイートを実行できます。

npm install # for first time
npm test

カスタムアサージョンとコマンド

機能拡張のファイルレイアウトは以下の様になっています:

lib
├── custom_assertions
│   ├── receivedEmailHTMLBodyContains.js
│   ├── receivedEmailSubjectContains.js
│   └── receivedEmailSubjectEquals.js
├── custom_commands
│   ├── checkEmails.js
│   ├── createEmailRoute.js
│   └── deleteEmailRoutes.js
├── globals.js
└── page_objects
    └── hackernewsletter.js # example specific file

設定ファイル からそれらを指定します。

{
  "custom_commands_path": "./lib/custom_commands",
  "custom_assertions_path": "./lib/custom_assertions",
  "page_objects_path": "./lib/page_objects",
  "globals_path": "./lib/globals.js",
  // snip ...
}

もっとアサージョンを追加する

サンプルプロジェクトでは receivedEmailHTMLBodyContains, receivedEmailSubjectContains, receivedEmailSubjectEquals を実装しました。

もし from_emailattachments などの他のフィールドをテストしたい場合には、既存の実装をフォークして、アサージョンを追加することができます。 (一覧を見る)

const util = require("nightwatch/lib/util/utils");

exports.assertion = function receivedEmailSubjectEquals(
  address,
  expected,
  msg
) {
  const DEFAULT_MSG = 'Testing if <%s> received with subject equals to "%s".';
  this.message = msg || util.format(DEFAULT_MSG, address, expected);

  this.expected = function () {
    return expected;
  };

  this.pass = function (value) {
    const expected = this.expected();
    return (
      value.filter(function (email) {
        return email.subject === expected;
        // use indexOf(expected) !== -1 for *contains* implementation.
      }).length > 0
    );
  };

  this.value = function (result) {
    return result || [];
  };

  this.command = function (callback) {
    return this.api.checkEmails(address, callback);
  };
};

もし、便利なアサージョンを実装したら、是非 リポジトリをフォーク してプルリクエストを送って頂けると幸いです!

Happy testing!

comments powered by Disqus