Playwright Email 測試:端對端教學
這篇教學示範如何在 Playwright 裡端對端測試一個真實的 email 流程——完全不靠 mock。我們替每個測試開一個拋棄式收件匣,跑完註冊,再透過 API 讀驗證信並取出代碼。它建立在拋棄式 email API 之上,也是我們開發者 email 測試指南的一部分。
做法
每個測試開一個收件匣(不是每個測試套件一個——共用又會把舊狀態問題帶回來)。在瀏覽器裡觸發流程,輪詢收件匣 API 抓訊息,用簡單的比對取出代碼,再把它填回頁面。
一個可重用的 fixture
把收件匣相關呼叫包進一個 Playwright fixture,這樣每個測試都會自動拿到一個新地址,測試本體也能專注在行為、而不是傳輸細節:
// inbox.ts — talks to your MoeMail-style API
export async function createInbox() {
const res = await fetch(API + '/emails/generate', {
method: 'POST',
headers: { 'X-API-Key': process.env.MAIL_KEY },
})
return res.json() // { id, address }
}
export async function waitForMessage(id, timeoutMs) {
const deadline = Date.now() + (timeoutMs || 30000)
while (Date.now() < deadline) {
const res = await fetch(API + '/emails/' + id + '/messages', {
headers: { 'X-API-Key': process.env.MAIL_KEY },
})
const list = await res.json()
if (list.messages && list.messages.length) return list.messages[0]
await new Promise(r => setTimeout(r, 1500))
}
throw new Error('no email arrived in time')
}
測試本體
import { test, expect } from '@playwright/test'
import { createInbox, waitForMessage } from './inbox'
test('verifies signup email', async ({ page }) => {
const inbox = await createInbox()
await page.goto('/signup')
await page.getByLabel('Email').fill(inbox.address)
await page.getByRole('button', { name: 'Sign up' }).click()
const msg = await waitForMessage(inbox.id, 30000)
const code = msg.text.match(/[0-9]{6}/)[0]
await page.getByLabel('Verification code').fill(code)
await expect(page.getByText('Welcome')).toBeVisible()
})
注意 Date.now() 守住了輪詢迴圈,而比對抓的是一組六位數代碼;若要改抓連結,就比對 URL 再對它呼叫 page.goto()。
讓它更不容易閃爍
能用 webhook 就別用輪詢,可以省掉延遲;給每次執行一個獨一無二的地址,平行測試才不會撞在一起;CI 逾時也要設緊一點。同一套寫法也能涵蓋 OTP 與 2FA 登入,而同一個 fixture 在 Cypress 和 Selenium 裡照樣能用。
開始動手
到個人頁面拿一把 API 金鑰,讀讀 OpenAPI 文件,把上面的 fixture 丟進你的測試套件就行。第一次接觸這套想法?先從開發者 email 測試看起。