首页
/ Supabase Studio E2E 测试实战:基于 Playwright 的自托管与云端平台双模式配置指南

Supabase Studio E2E 测试实战:基于 Playwright 的自托管与云端平台双模式配置指南

2026-09-07 11:35:54作者:邵娇湘

导读:Supabase Studio 拥有超过 30 个功能模块(表编辑器、SQL 编辑器、日志、存储、RLS 策略、定时任务等),其质量保障依赖一套可同时跑在自托管与云端平台上的端到端(E2E)测试体系。本文基于仓库中 e2e/studio/README.md 展开,系统讲解这套 Playwright 测试框架的安装配置、环境变量语义、双模式鉴权流程、运行方式与编写规范,让你能在本地或 CI 中快速复现、扩展 Studio 的 E2E 测试。

一、测试框架全景:从一个目录看懂 Studio 的 E2E 体系

Supabase 仓库将 Studio 的 E2E 测试集中在 e2e/studio 目录下,它与 Playwright 的官方约定略有差异,先理清整体结构再动手更高效:

目录 / 文件 作用
e2e/studio/playwright.config.ts Playwright 主配置:双模式(platform / self-hosted)下自动切换串并行、启动 webServer、浏览器参数与 reporter
e2e/studio/playwright.merge.config.ts 用于 CI 场景下合并多个 blob 测试报告的配置
e2e/studio/env.config.ts 统一读取并规范化 .env.local 中全部环境变量,供配置与测试代码共享
e2e/studio/features/ 全部测试用例(*.spec.ts)与全局 setup(_global.setup.ts
e2e/studio/scripts/ 支撑脚本:setup-platform-tests.ts(平台建项目)、login/email.tslogin/github.ts(两种登录)、common/(平台 API 客户端等)
e2e/studio/utils/ 测试公共工具:自定义 test 实例、数据库/存储操作封装、剪贴板与调试辅助等
e2e/studio/package.json 依赖(@playwright/test@supabase/supabase-jsotpauth 等)与 e2e/e2e:ui 脚本

features 目录 的文件清单可以看出覆盖范围:table-editor.spec.tssql-editor.spec.tslogs.spec.tsstorage.spec.tsrls-policies.spec.tsauth-users.spec.tsdatabase-webhooks.spec.tsedge-functions.spec.tscron-jobs.spec.tswrappers.spec.tsassistant.spec.ts(AI 助手,依赖 OpenAI API Key)、realtime-inspector.spec.tsqueue-integration.spec.ts 等。这基本覆盖了 Studio 仪表盘的主要用户旅程。

需要特别注意的是:这套测试跑在真实的 Supabase 环境之上(自托管 Docker 或平台真实项目),通过 UI 与后台 API 双通道操作数据,而不是用一层 mock 把后端完全替换掉。

二、环境准备与两种运行模式

2.1 两条测试路径:Self-Hosted 与 Platform

测试框架设计了两种截然不同的后端环境,由 IS_PLATFORM 环境变量区分:

  • 自托管模式(Self-Hosted,IS_PLATFORM=false:不需要准备任何账号。直接通过 mise / Docker 拉起本地的 Supabase 与 Studio 即可运行,测试会落在一个本地临时项目上。这是零成本、可并行、最适合日常开发的路径。
  • 平台模式(Platform,IS_PLATFORM=true:针对云端真实部署(如 https://supabase.com/dashboard 或 Vercel staging)的回归测试。必须准备平台账号、组织与 PAT,测试会通过 Management API 自动创建或复用项目(默认项目名 e2e-test-local)。

2.2 Platform 模式的前置条件

README 明确列出三条步骤:

  1. 创建平台账号——二选一:
    • 邮箱 + 密码注册;
    • GitHub OAuth(GitHub 强制 2FA,需要 TOTP)。
  2. 创建组织(organization)——本地通过 mise fullstack 拉起完整开发环境时即可在平台上建组织。
  3. 生成 Personal Access Token(PAT),供 Management API 调用鉴权。

对应源码可以在 scripts/setup-platform-tests.ts 中看到完整校验逻辑:只要 IS_PLATFORM=trueORG_SLUGSUPA_REGIONAPI_URLSUPA_PAT 四个变量缺一不可,否则直接抛出明确的错误提示;随后通过 getProjectRef()(orgSlug, region, projectName) 查找已有项目,找不到就用 PAT 调 Management API 新建。

2.3 安装 Playwright 浏览器

务必在 e2e/studio 目录内执行(README 用 ⚠️ 特别标注了这一点),避免装到错误的包上下文:

cd e2e/studio
pnpm exec playwright install

同时建议先安装依赖:在仓库根目录执行 pnpm install,确保 package.json 中声明的 @playwright/testdotenvotpauth@supabase/supabase-js@faker-js/faker 等依赖就位。其中 otpauth 正是后面 GitHub TOTP 登录环节生成动态验证码所用。

三、环境变量全解析:三种示例文件与每个变量的语义

框架用 dotenvenv.config.ts 中加载 e2e/studio/.env.localoverride: true,优先于进程已有值),因此所有测试配置都收敛到这一个文件。仓库已提供三份模板,按场景复制:

# 自托管测试
cp .env.local.self-hosted.example .env.local

# 平台测试 + 邮箱认证
cp .env.local.email.example .env.local

# 平台测试 + GitHub 认证
cp .env.local.github.example .env.local

3.1 核心配置

变量 说明 默认值(见 env.config.ts
STUDIO_URL Studio 运行地址 http://localhost:8082
API_URL Supabase API 端点(平台模式下为 Management API) http://127.0.0.1:54321
IS_PLATFORM true 平台模式 / false 自托管 false

IS_PLATFORM 不只是开关,它会直接改变运行策略,这一点在 playwright.config.ts 有硬性约束:

  • IS_PLATFORM=true串行运行,仅 1 个 worker,因为平台 API 有速率限制(README 原文:"Tests run serially (1 worker) due to API rate limits");
  • IS_PLATFORM=false并行运行,本地 CI 场景配 3 个 worker。

注意 README 描述与配置文件存在轻微差异:README 提到自托管默认 5 workers,而当前仓库的 playwright.config.ts 写的是 workers: env.IS_PLATFORM ? 1 : 3。以仓库实际代码为准,自托管当前是 3 个 worker。

3.2 认证变量(平台测试必需)

认证是否启用是自动推导的,无需单独开关。逻辑见 env.config.ts

  • 设置了 EMAILPASSWORD → 邮箱认证;
  • 设置了 GITHUB_USERGITHUB_PASSGITHUB_TOTP 三者 → GitHub OAuth 认证;
  • 两者都未配全 → 不认证(自托管场景天然满足)。

邮箱认证

  • EMAIL:平台账号邮箱;
  • PASSWORD:平台账号密码;
  • PROJECT_REF:项目引用 ID(可选;不填则自动创建)。
  • ⚠️ 局限:邮箱认证仅在 local 与 staging 环境可用,因为测试会 mock HCaptcha(见下文 4.2)。

GitHub 认证

  • GITHUB_USER:GitHub 用户名;
  • GITHUB_PASS:GitHub 密码;
  • GITHUB_TOTP:GitHub 2FA 的 TOTP 密钥——注意它不是一次性验证码,而是密钥本身。

关于 TOTP 密钥的获取,README 有非常实用的提示:GitHub 配置 2FA 时页面会展示二维码,点击 “enter this text code instead” 即可看到明文 secret,把它填入 GITHUB_TOTP

3.3 平台专用变量(IS_PLATFORM=true 时必需)

变量 说明 默认值
ORG_SLUG 组织标识 default
SUPA_REGION 项目部署区域 us-east-1
SUPA_PAT Personal Access Token test
BRANCH_NAME 测试项目名 e2e-test-local

3.4 可选变量

  • OPENAI_API_KEY:仅 assistant.spec.ts(AI Assistant 测试)需要;未设置时该用例会被跳过,不影响其它测试。
  • VERCEL_AUTOMATION_BYPASS_SELFHOSTED_STUDIO:Vercel 部署保护(Protection Bypass)令牌,默认 false。它会被注入请求头 x-vercel-protection-bypassx-vercel-set-bypass-cookie,用于直接访问被 Vercel 保护的自托管 Studio(见 playwright.config.ts)。

3.5 环境变量与启动命令的自动联动

.env.local 的取值组合决定了 Playwright webServer 的启动策略,README 中的表格在 playwright.config.ts 有完整实现:

场景 判断条件 动作
平台 + 本地 Studio IS_PLATFORM=trueSTUDIO_URLlocalhost/127.0.0.1 自动执行 pnpm --workspace-root run e2e:setup:platform,等待 8082 端口就绪
平台 + 远端 Studio IS_PLATFORM=true 且 URL 为远端(如 https://supabase.com/dashboard 不启动任何 webServer,直接测远端
自托管(本机开发) 非 CI 执行 pnpm --workspace-root run e2e:setup:selfhosted
自托管(CI) 非平台且 CI 已设置 执行 pnpm --workspace-root run e2e:setup:selfhosted:start-studio

其中「是否本地」通过检查 STUDIO_URL 是否包含 localhost127.0.0.1 判定(见 env.config.ts)。webServer 默认端口 8082、超时 10 分钟(均可用 WEB_SERVER_PORT / WEB_SERVER_TIMEOUT 覆盖),且 reuseExistingServer: true 允许复用已运行的 Studio。这里目录常被误读的点是:这三个根命令(e2e:setup:platforme2e:setup:selfhosted 等)实际定义在仓库根 package.json,运行时以 workspace 方式从根目录触发。

四、全局 Setup 阶段发生了什么

正式用例执行前,Playwright 会先跑 features/_global.setup.ts(在 playwright.config.ts 中通过 dependencies: ['setup'] 声明,且项目 Features 会使用 setup 阶段保存的登录态 storageState)。它按顺序做四件事:

  1. 健康检查:打开 STUDIO_URL 确认 Studio 活着;fetch(API_URL) 确认后端活着。任一失败都会打印带排查建议的报错(例如提示本地 API 需运行 npm run dev:api)。
  2. 清理临时锁:删除系统临时目录下的 playwright-locks(供 once-per-file 类工具使用)。
  3. 准备项目:调用 setupProjectForTests()——自托管直接返回 default;平台模式则按 (ORG_SLUG, SUPA_REGION, BRANCH_NAME) 查找或创建项目,并把 PROJECT_REF 写回 process.env 供后续用例使用。
  4. 按需登录:仅当检测到认证变量才执行。登录成功后 Playwright 会保存 storageStatee2e/studio/playwright/.auth/user.jsonSTORAGE_STATE_PATH),让每个用例共享已认证的 Cookie/LocalStorage,避免重复登录。

4.1 GitHub OAuth + TOTP 自动化流程

scripts/login/github.ts 把 GitHub 登录的机械操作全部脚本化,README 描述的流程与代码一一对应:

  1. 点击 “Sign In with GitHub”;
  2. 填写用户名与密码;
  3. otpauth 库按 GitHub 规范生成 TOTP:algorithm: SHA1digits: 6period: 30(见 github.ts);
  4. 处理 GitHub 授权确认页;
  5. 失败自动重试最多 3 次loginWithGithubWithRetry)。

代码里还藏着一个细节:为了绕开 auth.supabase.io 的 CORS 问题,登录脚本会 route 拦截 **/auth.supabase.io/auth/v1/user 返回 401,并处理对应 OPTIONS 预检请求——这也是 Playwright 自动化登录第三方 OAuth 时的常见套路。

4.2 邮箱登录与 HCaptcha 的 Mock

scripts/login/email.tspage.addInitScript 中注入一个假的 window.hcaptchaexecute/render/reset 全部用官方测试 token 10000000-aaaa-bbbb-cccc-000000000001 桩替代),同时 route 拦截所有 hcaptcha.com 请求并返回自研 stub。README 中 "HCaptcha is mocked during test setup" 正是此实现,注释也点明了原因:HCaptcha 能识别自动化浏览器并阻止 Playwright,且自定义 Vercel 请求头会引发 CORS 问题。这也解释了为什么邮箱认证只在 local / staging 可用。

五、运行测试:命令行与报告

直接查看 package.json 的 scripts 即可确认可用命令:

# 标准运行(按 env 配置自动选择模式)
pnpm run e2e

# 带 Playwright UI(可视化查看用例、逐步调试)
pnpm run e2e -- --ui

# 等价命令
pnpm exec playwright test
pnpm exec playwright test --ui

若只希望本地跑通且不想碰平台,把 .env.local 配成自托管模板(IS_PLATFORM=false)再执行即可。

CI 与本地报告策略不同playwright.config.ts):

  • CI 下 reporter 为 list + blob(blob 报告供后续合并分析);
  • 本地为 list + html(不自动打开)+ json(输出到 test-results/test-results.json)。

其它内置策略值得留意:单测超时 120sexpect 超时 20smaxFailures: 3(失败达 3 即熔断)、CI 下自动重试 5 次并开启 forbidOnly;视频仅在失败时保留(retain-on-failure),失败保留 trace。浏览器启动参数针对 CI/容器做了大量优化(--no-sandbox--disable-dev-shm-usage--headless=new、4GB V8 堆等),自托管测试因可能访问带自签证书的 localhost 还带上了 --allow-insecure-localhost(见 playwright.config.ts)。同时 contextOptions.reducedMotion: 'reduce' 减少动画干扰,并预设了剪贴板读写权限。

六、开发 Tips:写出可维护的用例

README 的 "Tips for development" 部分是团队沉淀的工程规范,逐条拆解如下:

  1. 研读 Playwright 官方最佳实践@playwright/test 的稳定 API 与本文框架一致)。
  2. 善用 UI 模式pnpm run e2e -- --ui 可逐步回放、分步调试用例。
  3. examples/examples.ts 作为上下文喂给 AI 辅助工具,让代码补全贴合本项目的操作范式。
  4. 给 expect 加 message,失败时一眼定位意图:
await expect(page.getByRole('heading', { name: 'Logs', exact: true }), {
  message: 'Logs heading should be visible',
}).toBeVisible()
  1. 用仓库封装的 test 而非 Playwright 原生 test。自定义实例定义在 utils/test.ts,它通过 test.extend 注入 env/ref/apiUrl 固定变量,并在 page 上预置 addInitScript 自动写入若干本地存储标记(如关闭队列操作横幅、关闭 2026-08-01 服务条款弹窗),从而保证被测 UI 的稳定初始状态。同文件还导出了 withSetupCleanup 工具,配合 await using 语法即可在用例结束时自动执行清理(典型用法是建表测试后自动删表):
import { test } from '../utils/test'

await using _ = await withSetupCleanup(
  () => createTableWithRLS('pw_table', 'pw_column'),
  async () => {
    await dropTable('pw_table')
  }
)
  1. PWDEBUG 调试
PWDEBUG=1 pnpm run e2e -- --ui

七、该测什么:用例设计的三条铁律

README 给出非常聚焦的提问式清单,回答 "What should I test?":

  • Can the feature be navigated to?——功能入口可达吗?(导航链路完整)
  • Does the feature load correctly?——功能加载正常吗?(页面不白屏、数据渲染正确)
  • Can you do the actions (filtering, sorting, opening dialogs, etc)?——核心操作可用吗?(筛选、排序、弹窗等交互闭环)

这套提问对应的正是 features 下每个 spec 的骨架:先导航进入目标页面,再断言关键 UI 就绪,最后执行代表性操作并验证结果。多个 spec 还演示了「测试的边界设计」:

八、API Mocks:不需要真实后端时如何拦截

当某个接口不稳定、成本高或数据不可控时,README 建议使用 Playwright 的 page.route mock API 请求,官方文档见 Playwright Mocking 章节。仓库中大量用例印证了这一模式,最直接的例子来自 logs.spec.ts

// 先用静态数据占位
const mockAPILogs = {
  result: [
    { event_message: 'test message', ... }
  ],
  // ...
}

// 拦截请求并返回 mock 数据
await page.route(`*/**/logs.all*`, async (route) => {
  await route.fulfill({ body: JSON.stringify(mockAPILogs) })
})

// 之后照常断言 UI
await expect(page.getByText(mockAPILogs.result[0].event_message), {
  message: 'Mocked log message should be rendered in the Logs table',
}).toBeVisible()

mock 的典型使用场景在仓库中还有不少佐证:edge-functions.spec.ts 拦截函数 CRUD 接口、enabled-features-overrides.spec.ts 拦截特性开关、cron-jobs.spec.ts 系列用 pg-meta/*/query mock 来稳定构造调度器状态。实践要点:

  • 拦截粒度尽量精确(如 **/pg-meta/*/query**),避免误伤同前缀的真实请求;
  • mock 与真实后端混用时,给 mock 场景写 test.skip 条件保持用例语义清晰;
  • route.fulfill 别忘了 contentTypestatus,否则可能引发前端解析异常。

九、写在最后

理解 Supabase Studio E2E 测试体系的关键在于抓住「双模式 + 真实环境」这条主线:IS_PLATFORM 决定跑在本地 Docker 还是云端平台,env.config.ts 把散落的配置收敛成单一数据源,全局 setup 负责把项目与登录态准备好,utils/test.ts 则统一了用例的初始化。若想在仓库外复刻这套方案,最省力的路径是:复制自托管模板 → pnpm exec playwright installpnpm run e2e;待基础跑通后再按 .env.local.email.example.env.local.github.example 补齐平台账号与 PAT,把回归面扩展到真实的云端部署。更细的源码细节可在仓库中继续深入 playwright.config.tsenv.config.ts_global.setup.ts 以及 features 下各个 spec 逐一研读。

登录后查看全文
热门项目推荐
相关项目推荐