やりたいこと
- E2EテストツールであるCypress上でメールフォーム等からメールを送信
- MailHogを使ってメールの受信を確認
- さらにメール本文内のURLを取得したい
Mailhog本体の導入は省略します。
package | version |
---|---|
cypress | 10.0.7 |
cypress-mailhog | ^1.6.0 |
cypress-wait-until | 1.7.2 |
導入
パッケージをインストール
npm install cypress-mailhog
Cypress内のcommand.jsで読み込む
import 'cypress-mailhog';
mailHogUrlをCypressConfigで設定
export default defineConfig({
env: {
mailHogUrl: "http://localhost:8025/"
},
e2e: {
baseUrl: 'http://localhost:8080'
}
})
実装
例:「パスワード再設定画面で、メールアドレスを入力し送信ボタンを押すと手続きを進めるURLが記載されたメールが届く」 という流れ。
<form>
<input type="text" name="email">
<button type="submit" data-test="btn-reset-password">送信</button>
</form>
次はE2Eテスト。画面遷移とform入力、ボタンクリック。
// reset-password.htmlに遷移
cy.visit('/reset-password');
// メールアドレスを入力
cy.get('input[name="email"]').type('test@aaa.com');
//再設定ボタンを押す
cy.get('[data-test="btn-reset-password"]').click();
そしてcypress上でメールを取得。
cypress-mailhogにはコマンドが用意されており、今回は主に以下を使用する。
コマンド一例
// 全件取得(最大50)
cy.mhGetAllMails()
// 取得したうちの最新のメールを取得
cy.mhGetAllMails().mhFirst()
// MailHog上のメールを全件削除
cy.mhDeleteAll()
// 最新のメールの本文を取得
cy.mhGetAllMails().mhFirst().mhGetBody()
実際に使ってみる
// 取得した一覧のうち、1件目(最新)のメール本文を取得
cy.mhGetAllMails().mhFirst().mhGetBody().then((body) => {})
mailparser
が使えるのを後から知る。
参考: https://github.com/SMenigat/cypress-mailhog/issues/25
mailparser でメール本文を取得
npm install mailparser -D
const parser = require('mailparser').simpleParser;
module.exports = (on, config) => {
on('task', {
'parse-mail': ({ mail }) => parser(mail),
})
}
command.jsに登録
Cypress.Commands.add('mhParseMail', { prevSubject: true }, (mail) => {
return cy.task('parse-mail', { mail: mail.Raw.Data })
})
cy.mhGetAllMails().mhFirst().mhParseMail().then((res) => {
//本文を取得しデコード
const mailText = decodeURIComponent(escape(window.atob(_body)))
//URLを抽出
const urlArr = mailText.match(/((h?)(ttps?:\/\/[a-zA-Z0-9.\-_@:/~?%&;=+#',()*!]+))/g)})
})
cypress-wait-until
また、mailhogはメールが届くまでタイムラグがある可能性があるので cypress-wait-until
を合わせて使用することに。
30秒間、1秒ごとに sender
宛のメールを確認し、届いていたら true
が返る。(タイムアウトしたらエラーメッセージが返される。)
npm install cypress-wait-until -D
これもcommand.jsに登録
Cypress.Commands.add('mhGetMailsBySender', (sender, wait=true) => {
if(wait) {
//Wait until there is at least one email from sender
cy.waitUntil(() => cy.mhGetAllMails(10).then((mails) =>
mails.filter((mail) => mail.Raw.From === sender).length > 0
), {
errorMsg: `${sender} からのメールはありませんでした`,
timeout: 30000,
interval: 1000
})
}
cy.mhGetAllMails().then((mails) => {
return mails.filter((mail) => mail.Raw.From === sender);
})
})
参考:https://github.com/SMenigat/cypress-mailhog/issues/11
mailparserとwait-utilを組み合わせると、こう。
const userEmail = "test@aaa.com"
cy.mhGetMailsBySender(userEmail).mhFirst().then((res) => {
const fromEmail = res.Raw.From
//メールアドレスが一致しているかチェック
expect(fromEmail).to.eq(_userEmail)
//本文からURLを抽出
const _body = res.Content.Body
if(!_body) return
let mailText = decodeURIComponent(escape(window.atob(_body)))
const urlArr = mailText.match(/((h?)(ttps?:\/\/[a-zA-Z0-9.\-_@:/~?%&;=+#',()*!]+))/g)
//以下略
})
})
終わり
Cypressに苦戦を強いられ続けていますが、もっと効率よく上手に調べて使う力をつけなくてはと反省する日々です。先人方に圧倒的感謝。