mailosaurを使ったE2Eテストにおけるメール認証の自動化
開発部のねこたんです.ニャン(=^・^=)
私の担当しているmila-e申請というプロダクトでは,Playwrightを使ったE2Eテストの自動化を推進しています.
画面操作だけであればPlaywright単体でよいのですが,ユーザ登録やパスワードリセットに伴うメール認証は工夫が必要です.そこで,mailosaurというサービスを利用してメール認証をE2E自動テストに組み込んでみました.
mailosaurとは
mailosaurとはイギリスにある同名の会社が提供している,メールやSMSをAPIで操作できるサービスです.
ロゴが恐竜っぽいので,"dinosaur"を文字っているのでしょうか.
このサービスを使うことで,mailosaurに用意したテスト用のメールアドレスに送られたメールの本文や添付ファイルなどをプログラムで読み取ったり,転送したり返信したりすることができます.
同様のサービスにはMailSlurpなどもあり,MailSlurpは過去に使ったことがあったのですが,チームでの利用(メンバアカウントの管理)においてmailosaurのほうが料金が安くなりそうだったので,やりたいことができそうかどうかの検証として,まずはトライアルで試してみました.
ちなみに今回試したのはメール受信だけで,SMSは試していません.
mailosaurのセットアップ
トライアルをしたかったので,トップページのStart for freeからサインアップしました.

サインアップの最後で最初のinboxを作る画面が出てきました.
ここではEmail testingを選択し,Email Valification(誤字)と名前を付けました.

メール受信の確認
サインアップが完了するとメーラ画面のようなダッシュボードが表示されました.

作成したinbox用にサブドメイン(あとでAPIで使うSERVER_IDが付いたもの)が作成されて,anything@<SERVER_ID>.mailosaur.netというようなメールアドレスが右のペインに表示されています.
このinboxはどんなユーザIDのメールアドレスでも受信できるので,以下のようなアドレスはすべて受信できます.
- anything@<SERVER_ID>.mailosaur.net
 - hoge@<SERVER_ID>.mailosaur.net
 - piyo+fuga@<SERVER_ID>.mailosaur.net
 
とりあえず手動でanything@<SERVER_ID>.mailosaur.netとthenewuser@<SERVER_ID>.mailosaur.netにメールを送ってみたところ,inboxにメールが届きました.

E2E自動テストへの組み込み
APIを利用して届いたメールを操作する方法は,以下にドキュメントがあります.
当プロダクトではPlaywrightを使っているので,公式のnpmのライブラリをインストールし,以下のようにE2E自動テストに組み込みました.
APIキーの発行
まずはAPI Keysメニューを表示し,Create standard keyボタンからAPIキーを発行します.

以下のようにAPIキーが発行されました.(ここでは名前をe2e-testとしました.)
Reveal Keyを押すことでAPIキーを参照できます.

ライブラリのインストール
yarn add mailosaur
Playwrightのテストコード内での利用
作成したinboxのSERVER_IDと発行したAPIキーを使って,受信した認証メール中にある認証コードを取得するサンプルコードです.なお,環境変数のMAILOSAUR_SERVER_IDやMAILOSAUR_API_KEYを環境変数ファイルなどでローカルファイルに置くのはリスクがあるので,先日書いた記事のように1password CLI等からセットすることを推奨します.
import { test } from '@playwright/test'
import MailosaurClient from 'mailosaur'
const mailosaur = new MailosaurClient(process.env.MAILOSAUR_API_KEY)
test('認証用メール送信を受けて,認証コードを抽出する例', async ({ page }) => {
  const emailAddress = `thenewuser@${process.env.MAILOSAUR_SERVER_ID}.mailosaur.net`
  // 認証コードを送信する画面処理
  await page.getByRole('textbox').nth(0).fill(emailAddress)
  await page.getByRole('button', { name: '送信' }).click()
  // メールの受信
  const email = await mailosaur.messages.get(process.env.MAILOSAUR_SERVER_ID, {
    sentTo: emailAddress,
    subject: '認証', // 受信するメールのタイトルに含まれる文字列でフィルタする
  });
  // メール本文にある「認証コード: 012345」といった文字列から認証コードを抽出する
  const codeMatch = email.text?.body?.match(/認証コード: ([0-9]{6})/)
  if (!codeMatch) {
    throw new Error(`送付されたメールから認証コードが抽出できません: ${email.text?.body}`)
  }
  const verificationCode = codeMatch[1]
  // 認証コードを使った処理
  await page.getByRole('textbox').nth(1).fill(verificationCode)
})
npm以外にもJava, Ruby, Python, .NET, PHP, Goなどのライブラリが用意されており,各テストフレームワークへのインテグレーションもドキュメントにあるので,簡単に組み込めるようになっています.
注意事項(クォータ)
プランによって,一日に送受信できるメールの数やチームに追加できるメンバ数などに制限があります.特にCIでE2E自動テストを実行する場合は,どの程度利用するのか概算してからプラン選択するのがよさそうです.
詳しくはPricingのページを参照してください.
感想
どんなユーザIDのメールアドレスでも受け取れるinboxになっているので,テストごとにinboxを作成する必要がなく,メールアドレスを都度変えるだけ済むのはとても便利でした!今もそうであるかわかりませんが,以前使ったMailSlurpではそれができず,テスト実行ごとにinboxを作成していた記憶があるので,この点はmailosaurのほうが使いやすいと感じました.(私が知らないだけで,MailSlurpにもそういった機能がある場合はご容赦ください.)
また,メール本文中にあるURLリンクが自動検出されて,email.text?.links?のように取得できるのも,わざわざ実装を書かなくて済むので便利でした.
E2E自動テストでは手動の操作が必要な部分がネックになることがありますが,メールの受信とメールの内容から情報を取得する部分に関しては,こういったツールが役に立ちますね.
Viva! 自動化 🎉
Discussion