
Studio E2e Tests
Run, author, and stabilize Playwright end-to-end tests for the Supabase Studio web app in local and CI-like setups.
Install
npx skills add https://github.com/supabase/supabase --skill studio-e2e-testsWhat is this skill?
- Documents run commands from `e2e/studio` including file-scoped runs, `--grep`, and `--ui` debug mode
- Covers environment setup with auto-started local Supabase containers and parallel workers in self-hosted mode
- Explains test layout in `features/*.spec.ts` with custom `test` utility and fixture helpers
- Recommends generous `expect` timeouts (e.g. 30s) and descriptive assertion messages for flaky debugging
- Addresses CI vs local differences, waiting strategies, and avoiding race conditions
Adoption & trust: 106 installs on skills.sh; 104k GitHub stars; 3/3 security scanners passed (skills.sh audits).
Recommended Skills
Agent Browservercel-labs/open-agents
Tddmattpocock/skills
Use My Browserxixu-me/skills
Test Driven Developmentobra/superpowers
Verification Before Completionobra/superpowers
Webapp Testinganthropics/skills
Journey fit
Primary fit
End-to-end verification belongs on the ship shelf because it validates the Studio UI after features land, before or alongside release gates. Testing is the canonical subphase for Playwright specs, race-condition fixes, selectors, and e2e command workflows.
Common Questions / FAQ
Is Studio E2e Tests safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Studio E2e Tests
# E2E Studio Tests Run Playwright end-to-end tests for the Studio application. ## Running Tests Tests must be run from the `e2e/studio` directory: ```bash cd e2e/studio && pnpm run e2e ``` ### Run specific file ```bash cd e2e/studio && pnpm run e2e -- features/cron-jobs.spec.ts ``` ### Run with grep filter ```bash cd e2e/studio && pnpm run e2e -- --grep "test name pattern" ``` ### UI mode for debugging ```bash cd e2e/studio && pnpm run e2e -- --ui ``` ## Environment Setup - Tests auto-start Supabase local containers via web server config - Self-hosted mode (`IS_PLATFORM=false`) runs tests in parallel (3 workers) - No manual setup needed for self-hosted tests ## Test File Structure - Tests are in `e2e/studio/features/*.spec.ts` - Use custom test utility: `import { test } from '../utils/test.js'` - Test fixtures provide `page`, `ref`, and other helpers ## Common Patterns Wait for elements with generous timeouts: ```typescript await expect(locator).toBeVisible({ timeout: 30000 }) ``` Add messages to expects for debugging: ```typescript await expect(locator).toBeVisible({ timeout: 30000 }, 'Element should be visible after page load') ``` Use serial mode for tests sharing database state: ```typescript test.describe.configure({ mode: 'serial' }) ``` ## Writing Robust Selectors ### Selector priority (best to worst) 1. **`getByRole` with accessible name** - Most robust, tests accessibility ```typescript page.getByRole('button', { name: 'Save' }) page.getByRole('button', { name: 'Configure API privileges' }) ``` 2. **`getByTestId`** - Stable, explicit test hooks ```typescript page.getByTestId('table-editor-side-panel') ``` 3. **`getByText` with exact match** - Good for unique text ```typescript page.getByText('Data API Access', { exact: true }) ``` 4. **`locator` with CSS** - Use sparingly, more fragile ```typescript page.locator('[data-state="open"]') ``` ### Patterns to avoid - **XPath selectors** - Fragile to DOM changes ```typescript // BAD locator('xpath=ancestor::div[contains(@class, "space-y")]') ``` - **Parent traversal with `locator('..')`** - Breaks when structure changes ```typescript // BAD element.locator('..').getByRole('button') ``` - **Broad `filter({ hasText })` on generic elements** - May match multiple elements ```typescript // BAD - popover may have more than one combobox // Could consider scoping down the container or filtering the combobox more specifically popover.getByRole('combobox') ``` ### Add accessible labels to components When a component lacks a good accessible name, add one in the source code: ```tsx // In the React component <Button aria-label="Configure API privileges"> <Settings /> </Button> ``` Then use it in tests: ```typescript page.getByRole('button', { name: 'Configure API privileges' }) ``` ### Narrowing search scope Scope selectors to specific containers to avoid matching wrong elements: ```typescript // 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 }) ``` ## Avoiding Race Conditions **Set up API waiters BEFORE triggering actions.** This is the most common source of flaky tests. ```ts // ❌ Race condition — response may complete before waiter is set up await page.getByRole('button', { name: 'Save' }).click() await waitForApiResponse(page, 'pg-meta', ref, 'query?key=table-create') // ✅ Waiter is read