Cypress によるメールテスト:E2E テストでメールを検証する
Cypress はブラウザを操作するのが得意ですが、認証メールはその外側にあります。本ガイドでは、使い捨て受信トレイを払い出して API 経由で読むカスタムコマンドを用意し、Cypress でのメールテストを実現します。開発者のためのメールテストガイドの一部で、Playwright 版や Selenium 版と並ぶ内容です。
アプローチ
受信トレイをテストごとにひとつ作り、フローを進め、受信トレイ API をメッセージが届くまでポーリングします。これをカスタムコマンドに包めば、spec がきれいに読めます。
カスタムコマンド
// cypress/support/commands.js
Cypress.Commands.add('createInbox', () => {
return cy.request({
method: 'POST',
url: API + '/emails/generate',
headers: { 'X-API-Key': Cypress.env('MAIL_KEY') },
}).its('body')
})
Cypress.Commands.add('waitForEmail', (id, tries = 20) => {
const poll = (n) => cy.request({
url: API + '/emails/' + id + '/messages',
headers: { 'X-API-Key': Cypress.env('MAIL_KEY') },
}).then((res) => {
if (res.body.messages.length) return res.body.messages[0]
if (n === 0) throw new Error('no email arrived')
cy.wait(1500)
return poll(n - 1)
})
return poll(tries)
})
テスト本体
it('verifies the signup email', () => {
cy.createInbox().then((inbox) => {
cy.visit('/signup')
cy.get('#email').type(inbox.address)
cy.contains('Sign up').click()
cy.waitForEmail(inbox.id).then((msg) => {
const code = msg.text.match(/[0-9]{6}/)[0]
cy.get('#code').type(code)
})
cy.contains('Welcome').should('be.visible')
})
})
再帰的な poll は、固定タイマーの場当たり的な cy.wait に頼らずに Cypress のコマンドキューと折り合いをつけます。同じコマンドはパスワードリセットメールのテストにも使えます。コードの代わりにリンクをマッチさせるだけです。
ヒント
テストごとに固有のアドレスを与え、可能なときは webhook を優先し、CI のタイムアウトは短めに保ちましょう。メールボックスを作成し、OpenAPI ドキュメントを読んでつなぎ込んでみてください。