关于 e2e-studio-tests
为 Supabase Studio 提供 Playwright 端到端测试的运行、编写和调试指南。内容涵盖命令、可靠选择器、冷启动差异及 CI 失败排查。
主要功能
- 01运行全部或指定测试
- 02按名称筛选及 UI 调试
- 03选择器编写规范
- 04避免固定等待与强制点击
- 05冷启动和 CI 故障排查
适用场景
- 01运行 Studio 端到端测试
- 02定位单个测试或测试名称
- 03排查本地通过但 CI 失败的问题
MCP 相关
提及使用 Playwright MCP 工具在本地调试时检查界面;未说明其提供或管理 MCP 服务。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ supabase/ supabase --skill e2e-studio-tests安装后在 Claude Code 中输入/e2e-studio-tests确认已加载。
详细介绍
E2E Studio 测试
运行 Studio 应用的 Playwright 端到端测试。
运行测试
必须从 e2e/studio 目录运行测试:
cd e2e/studio && pnpm run e2e
运行指定文件
cd e2e/studio && pnpm run e2e -- features/cron-jobs.spec.ts
使用 grep 筛选器运行
cd e2e/studio && pnpm run e2e -- --grep "test name pattern"
使用 UI 模式进行调试
cd e2e/studio && pnpm run e2e -- --ui
环境设置
- 测试会通过 web server 配置自动启动 Supabase 本地容器
- 自托管模式(
IS_PLATFORM=false)下,测试会并行运行(3 个工作线程) - 自托管测试无需手动设置
测试文件结构
- 测试位于
e2e/studio/features/*.spec.ts - 使用自定义测试工具:
import { test } from '../utils/test.js' - 测试夹具提供
page、ref和其他辅助工具
常见模式
使用较长的超时时间等待元素:
await expect(locator).toBeVisible({ timeout: 30000 })
在断言中添加消息以便调试:
await expect(locator).toBeVisible({ timeout: 30000 }, 'Element should be visible after page load')
对共享数据库状态的测试使用串行模式:
test.describe.configure({ mode: 'serial' })
编写可靠的选择器
选择器优先级(从优到劣)
-
带有可访问名称的
getByRole- 最可靠,可测试无障碍性page.getByRole('button', { name: 'Save' }) page.getByRole('button', { name: 'Configure API privileges' }) -
getByTestId- 稳定、明确的测试钩子page.getByTestId('table-editor-side-panel') -
精确匹配的
getByText- 适用于唯一文本page.getByText('Data API Access', { exact: true }) -
使用 CSS 的
locator- 谨慎使用,可靠性较低page.locator('[data-state="open"]')
应避免的模式
-
XPath 选择器 - 容易因 DOM 变更而失效
// BAD locator('xpath=ancestor::div[contains(@class, "space-y")]') -
通过
locator('..')遍历父级 - 结构变更时会失效// BAD element.locator('..').getByRole('button') -
对通用元素使用宽泛的
filter({ hasText })- 可能匹配多个元素// BAD - popover may have more than one combobox // Could consider scoping down the container or filtering the combobox more specifically popover.getByRole('combobox')
为组件添加可访问标签
如果组件缺少合适的可访问名称,请在源代码中添加:
// In the React component
<Button aria-label="Configure API privileges">
<Settings />
</Button>
然后在测试中使用它:
page.getByRole('button', { name: 'Configure API privileges' })
缩小搜索范围
将选择器限定在特定容器中,以避免匹配到错误的元素:
// Good - scoped to side panel
const sidePanel = page.getByTestId('table-editor-side-panel')
const toggle = sidePanel.getByRole('switch')
// Good - find unique element, then scope from there
const popover = page.locator('[data-radix-popper-content-wrapper]')
const roleSection = popover.getByText('Anonymous (anon)', { exact: true })
避免使用 waitForTimeout
不要使用 waitForTimeout,始终等待特定条件:
// BAD
await page.waitForTimeout(1000)
// GOOD - wait for UI element
await expect(page.getByText('Success')).toBeVisible()
// GOOD - wait for API response
const apiPromise = waitForApiResponse(page, 'pg-meta', ref, 'query?key=table-create')
await saveButton.click()
await apiPromise
// GOOD - wait for toast indicating operation complete
await expect(page.getByText('Table created successfully')).toBeVisible({ timeout: 15000 })
避免在点击时使用 force: true
不要强行点击隐藏元素,而是先使其可见:
// BAD
await menuButton.click({ force: true })
// GOOD - hover to reveal, then click
await tableRow.hover()
await expect(menuButton).toBeVisible()
await menuButton.click()
调试
查看跟踪
cd e2e/studio && pnpm exec playwright show-trace <path-to-trace.zip>
查看 HTML 报告
cd e2e/studio && pnpm exec playwright show-report
错误上下文
错误上下文文件保存在 test-results/ 目录中。
Playwright MCP 工具
在本地调试时,使用 Playwright MCP 工具检查 UI。
CI 与本地开发
主要区别在于冷启动与热状态:
CI(冷启动)
测试从空白数据库开始。每次测试运行都会重置数据库并启动全新的容器。默认情况下不会启用 pg_cron 等扩展。
使用 pnpm dev:studio-local 进行本地开发
使用正在运行的开发服务器进行调试时,数据库可能已经包含之前运行留下的状态(已启用的扩展、测试数据)。
处理冷启动问题
本地运行正常但在 CI 中失败的测试,通常是因为假设已有特定状态。
常见问题
- 扩展未启用(必须在测试设置中启用)
- 并行测试尝试修改共享状态时发生竞态条件(使用
test.describe.configure({ mode: 'serial' })) - 页面状态未设置时页面结构不同,导致定位器匹配到错误的元素
在本地复现 CI 行为
运行 pnpm run e2e 时,测试框架会自动重置数据库。这与 CI 行为一致。
如果使用 pnpm dev:studio-local 进行 Playwright MCP 调试,请记住此时的状态与 CI 不同。
CI 失败时的调试工作流
- 首先,在本地通过
pnpm run e2e -- features/<file>.spec.ts运行测试(冷启动) - 检查
test-results/目录中的错误上下文 - 如果需要检查 UI 状态,请启动
pnpm dev:studio-local并使用 Playwright MCP 工具 - 请记住:开发服务器中看到的状态可能在 CI 中并不存在