site logo

Marico's space

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

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

最近折腾 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.otpemail.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.otpemail.magicLink 在 Cloudflare 边缘自动提取,然后才到达你的测试套件。不需要正则,不需要 HTML 解析,没有竞态条件。

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