site logo

Marico's space

如何使用 Playwright 对 Supabase Auth Email 流程进行 E2E 测试(不使用 Docker,也不使用 InBucket)

前端技术 2026-06-26 11:28:06 134

最近折腾 Supabase Auth 的 E2E 测试,踩了一个很经典的坑:邮件验证。

Supabase 的注册流程会发送一封验证邮件,测试需要点击邮件里的链接或填写 OTP(一次性密码)。但问题是——邮件发出去了,你的测试脚本根本够不着它。

官方的建议是用 InBucket——Supabase 本地开发的邮件拦截工具。但这玩意儿依赖 Docker,得在 CI 流水线里跑一个完整的 Supabase 本地实例,GitHub Actions 里还得配置 Docker 服务块,CI 构建时间蹭蹭往上涨。

其实有更简单的方案。

现有方案的痛点

InBucket / 本地 Supabase: InBucket 在本地开发挺好用,supabase start 就带上了,邮件抓得飞快。但它需要 Docker、需要跑一整套 Supabase 本地栈、而且测试的不是你真实的 Supabase 项目。在 CI 里,这意味着 Docker 服务块、更慢的构建、以及一个可能和线上环境不一致的本地实例。

Mock Supabase: 你根本没在测真实的流程。测试全绿,但线上认证可能早就挂了。

数据库触发器设置可预测的 OTP: 思路巧妙,但增加了复杂度,还需要在 CI 里直接访问数据库。

共享 Gmail 收件箱: 并行测试跑起来到处都是竞态条件。

ZeroDrop 方案

ZeroDrop 提供的是云端真实临时邮箱,在 Cloudflare 边缘接收邮件。不需要 Docker、不需要本地 Supabase、不存在共享收件箱的冲突问题。

你向真实的 Supabase 项目发起真实的注册请求,只是邮箱地址用 ZeroDrop 的临时收件箱。验证邮件不到一秒就到达。你的测试直接读取 email.otp 或 email.magicLink——自动提取,不需要正则匹配。

你的应用 → Supabase → 发送验证邮件 → ZeroDrop 接收 → 测试读取 email.otp

安装配置

安装 SDK:

npm install zerodrop-client

不需要 API Key,不需要注册账号。

测试 Supabase 邮箱验证(OTP 流程)

Supabase 默认的注册流程用 6 位数字 OTP 做邮箱验证。下面是完整的 E2E 测试写法:

import { test, expect } from '@playwright/test';
import { ZeroDrop } from 'zerodrop-client'; const mail = new ZeroDrop(); test('Supabase signup with email verification', async ({ page }) => { // 为这次测试生成一个独立的收件箱 const inbox = mail.generateInbox(); // 打开注册页面 await page.goto('/signup'); // 用 ZeroDrop 收件箱填写注册表单 await page.fill('[name="email"]', inbox); await page.fill('[name="password"]', 'TestPassword123!'); await page.click('[type="submit"]'); // 等待 Supabase 发送验证邮件 // ZeroDrop 在边缘接收 — 不到 1 秒到达 const email = await mail.waitForLatest(inbox, { timeout: 15000 }); // OTP 自动提取 — 不需要正则 expect(email.otp).toBeTruthy(); // 在验证页面输入 OTP await page.fill('[name="otp"]', email.otp!); await page.click('[type="submit"]'); // 验证用户已完成认证 await expect(page).toHaveURL('/dashboard');
});

测试 Supabase 魔法链接流程

如果你用的是免密码的魔法链接登录:

import { test, expect } from '@playwright/test';
import { ZeroDrop } from 'zerodrop-client'; const mail = new ZeroDrop(); test('Supabase magic link login', async ({ page }) => { const inbox = mail.generateInbox(); // 请求魔法链接 await page.goto('/login'); await page.fill('[name="email"]', inbox); await page.click('button:has-text("Send magic link")'); // 接收魔法链接邮件 const email = await mail.waitForLatest(inbox, { timeout: 15000 }); // magicLink 从邮件正文中自动提取 expect(email.magicLink).toBeTruthy(); // 直接访问魔法链接 await page.goto(email.magicLink!); // 用户应该已经登录 await expect(page).toHaveURL('/dashboard');
});

测试密码重置

test('Supabase password reset flow', async ({ page }) => { const inbox = mail.generateInbox(); // 先创建一个用户(或使用已有的测试账号) // 然后发起密码重置 await page.goto('/forgot-password'); await page.fill('[name="email"]', inbox); await page.click('button:has-text("Send reset email")'); // 接收重置邮件 const email = await mail.waitForLatest(inbox, { timeout: 15000 }); // 访问重置链接 await page.goto(email.magicLink!); // 设置新密码 await page.fill('[name="password"]', 'NewPassword123!'); await page.fill('[name="confirmPassword"]', 'NewPassword123!'); await page.click('[type="submit"]'); await expect(page).toHaveURL('/login');
});

在 GitHub Actions CI 中运行

不需要 Docker。只要把 ZeroDrop 的 GitHub Action 加进去,为每次测试生成隔离的收件箱:

name: E2E Tests on: [push, pull_request] jobs: test: 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 - run: npx playwright test env: NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.SUPABASE_URL }} NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }}

就这么简单。不需要 supabase start,不需要 Docker 服务块。ZeroDrop 收件箱在客户端生成——没有网络请求,没有额外配置。

并行测试——无冲突

因为 generateInbox() 每次调用都在本地生成一个唯一的收件箱,不走网络,并行 CI 运行天然安全:

// 每个 worker 拿自己的收件箱 — 没有共享状态,没有冲突
test.describe.configure({ mode: 'parallel' }); test('user A signup', async ({ page }) => { const inbox = mail.generateInbox(); // 属于这个测试的独立收件箱 // ...
}); test('user B signup', async ({ page }) => { const inbox = mail.generateInbox(); // 不同的收件箱,零碰撞风险 // ...
});

50 个并行 worker,50 个隔离收件箱。零竞态条件。

InBucket vs ZeroDrop——何时用哪个

InBucket 适合本地开发——它集成在 Supabase 本地栈里,在本地跑很顺手。ZeroDrop 适合 CI 流水线、测试真实的 Supabase 项目。

InBucket ZeroDrop
最佳场景 本地开发 CI 流水线
需要 Docker ✓ ✗
测试真实 Supabase 项目 ✗ ✓
OTP 自动提取 ✗ ✓
魔法链接自动提取 ✗ ✓
并行安全 ✗ ✓
CI 配置复杂度 高 无

总结

测试 Supabase Auth 流程的 E2E 场景,不一定非要跑一整套本地栈。ZeroDrop 让你对真实的 Supabase 项目做真实的邮件投递验证,不需要 Docker、不需要 InBucket、不存在共享收件箱冲突。

email.otp 和 email.magicLink 在 Cloudflare 边缘自动提取,然后才到达你的测试套件。不需要正则,不需要 HTML 解析,没有竞态条件。

免费使用,无需注册,CI 开箱即用。