MoeMail
返回博客

Playwright 邮件测试:端到端教程

本教程演示如何用 Playwright 端到端地测试一条真实的邮件流程——不打桩、不 mock。我们为每个用例开一个一次性收件箱,驱动注册流程,再通过 API 读取验证邮件并提取验证码。它建立在一次性邮箱 API 之上,也是开发者邮件测试指南的一部分。

思路

每个用例开一个收件箱(不是每个套件一个——共用会把残留状态的问题又招回来)。在浏览器里触发流程,轮询收件箱 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 在 CypressSelenium 里照样能用。

动手开始

从个人资料里取一个 API 密钥,读一读 OpenAPI 文档,把上面的 fixture 丢进你的测试套件。还不熟悉这套思路?先从开发者邮件测试看起。