返回博客
QA测试
Playwright
邮件测试
自动化
如何使用 Playwright 测试邮件验证码(2026 完整指南)
·
阅读约 8 分钟
涉及邮件验证的端到端测试向来是 QA 工程师的噩梦。用户点击"注册"后,系统发出一封邮件,而测试脚本必须以自动化、可重复的方式读取该邮件、提取 6 位验证码,并将其填入表单。如果你曾经尝试过解决这个问题,就一定深有体会。
传统方案的困境
大多数团队在测试邮件流程时会遭遇以下几个死胡同:
- 共享测试账号(Gmail):本地可用,但在 CI 环境中会因 Google 检测到机器人登录而失败。多个并行测试还会产生 OTP 交叉污染。
- Mailinator 免费版:公开收件箱且免费版无 API 接口。任何人都能读取你的测试邮件。部分服务(包括亚马逊和 Stripe)会主动屏蔽 Mailinator 域名。
- 自托管 MailHog / MailDev:需要修改应用的 SMTP 配置,对第三方身份验证流程(OAuth 发送真实邮件)无效,还会带来额外的运维负担。
- 完全 mock 邮件:会错过真实的模板渲染错误、失效链接和字符编码问题——这些 bug 只会在真实邮件中出现。
- 一次性邮件服务:没有稳定 API、有速率限制、域名随时变化——是不稳定测试的温床。
你真正需要的是一个私有、可通过 API 访问的专属邮箱——可以通过代码创建、可靠轮询,且完全由你掌控。
第一节:使用真实邮箱 API 进行测试
最干净的解决方案是:在每个测试套件运行前通过 API 创建专用测试邮箱,测试期间使用,之后(可选)清理。GridInbox 正好提供了这套能力:REST API 支持创建邮箱、列出邮件、以及从来信中提取已解析的 OTP 验证码。
相比其他方案的核心优势:
- 每个测试拥有独立收件箱,并行运行时零干扰
- 收件箱是私有的,不像 Mailinator 那样公开可见
- OTP 验证码由服务端解析,以结构化 JSON 字段返回
- 兼容任何邮件提供商——底层接收基础设施为真实 SMTP/SES
- 支持自定义域名,可使用
@test.yourdomain.com
第二节:完整 Playwright 示例
下面演示一个完整的端到端测试:注册新用户 → 接收验证邮件 → 提取 OTP → 提交验证 → 断言账号已激活。
第一步:通过 API 创建测试收件箱
// helpers/email.ts
const API_BASE = 'https://api.gridinbox.com/api/v1';
const API_KEY = process.env.GRIDINBOX_API_KEY!;
export async function createTestInbox(label: string) {
const res = await fetch(`${API_BASE}/mailboxes`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY, // 通过请求头传递 API 密钥
},
body: JSON.stringify({ name: label }),
});
const data = await res.json();
// 返回 { id, address, name, ... }
return data as { id: string; address: string };
}
第二步:轮询等待 OTP 邮件
export async function waitForOtp(
mailboxId: string,
options = { timeoutMs: 30_000, intervalMs: 2_000 }
): Promise<string> {
const deadline = Date.now() + options.timeoutMs;
while (Date.now() < deadline) {
const res = await fetch(`${API_BASE}/mailboxes/${mailboxId}/messages?limit=1`, {
headers: { 'X-API-Key': API_KEY },
});
const { messages } = await res.json();
if (messages?.length > 0) {
const msg = messages[0];
// GridInbox 服务端已解析 OTP
if (msg.otp) return msg.otp as string;
// 兜底:从主题/正文中用正则提取
const match = (msg.subject + ' ' + msg.text_body).match(/\b(\d{4,8})\b/);
if (match) return match[1];
}
// 等待后重试
await new Promise(r => setTimeout(r, options.intervalMs));
}
throw new Error(`${options.timeoutMs}ms 内未收到 OTP,请检查邮件发送逻辑`);
}
第三步:完整 Playwright 测试用例
// tests/auth/email-verification.spec.ts
import { test, expect } from '@playwright/test';
import { createTestInbox, waitForOtp } from '../helpers/email';
test('用户注册后可完成邮件验证', async ({ page }) => {
// 1. 为本次运行创建唯一测试收件箱
const inbox = await createTestInbox(`pw-test-${Date.now()}`);
const testEmail = inbox.address;
// 2. 使用测试邮箱注册
await page.goto('/register');
await page.fill('[name="email"]', testEmail);
await page.fill('[name="password"]', 'TestPass123!');
await page.click('[type="submit"]');
// 3. 断言已进入验证步骤
await expect(page.locator('text=Check your email')).toBeVisible();
// 4. 通过 GridInbox API 获取 OTP
const otp = await waitForOtp(inbox.id);
// 5. 填入验证码
await page.fill('[name="otp"]', otp);
await page.click('[type="submit"]');
// 6. 断言跳转到 dashboard
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('text=Welcome')).toBeVisible();
});
第三节:在 CI/CD 中运行
将 API Key 作为 Repository Secret 添加到 GitHub Actions,并在 workflow 文件中引用:
# .github/workflows/e2e.yml
name: E2E 测试
on: [push, pull_request]
jobs:
playwright:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npx playwright install --with-deps
- name: 运行端到端测试
env:
GRIDINBOX_API_KEY: ${{ secrets.GRIDINBOX_API_KEY }}
run: npx playwright test
由于每个测试都创建了独立的收件箱,Playwright 的并行执行和分片功能(--shard=1/4)可以完美运行,不会出现任何收件箱冲突。
第四节:最佳实践
- 语义化命名收件箱:使用
pw-{testName}-{timestamp}格式前缀,方便在调试时识别收件箱归属。 - 根据 SES 投递速度设置合理的轮询超时:AWS SES 通常在 2–5 秒内投递。30 秒超时足够充裕;对于较慢的 SMTP 中继,可适当增加至 60 秒。
- 测试后清理收件箱:在
test.afterAll钩子中调用 API 删除测试邮箱,保持 GridInbox 面板整洁,避免存储积累。 - 使用 fixture 模式管理收件箱生命周期:Playwright fixture 可在一个测试文件的多个用例间共享同一收件箱,而无需每次重新创建——适合"一次登录、测试多个页面"的场景。
- 永远不要硬编码邮件地址:始终为每次运行生成唯一地址。硬编码地址在 CI 矩阵并发时会产生竞态条件。
总结
邮件验证测试不必再是那个让团队头疼、需要人工干预的不稳定环节。借助真实邮箱 API,你可以让邮件流程成为 Playwright 测试套件中的一等公民——确定性、并行安全、CI 就绪。
本文描述的模式——创建收件箱 → 触发邮件 → 轮询 API → 提取 OTP → 断言结果——适用于所有基于邮件的流程:注册验证、密码重置、Magic Link 登录、通知邮件等。