Files
supabase/.github/instructions/studio-e2e-tests.instructions.md
Alaister Young 4295e41e81 chore(studio): migrate cursor rules to claude skills + add CLAUDE.md (#44343)
Migrates all studio-related Cursor rules to Claude skills and adds a
top-level `.claude/CLAUDE.md` for project context. Docs rules left in
place.

**Decisions:**
- Only studio + testing rules migrated — docs rules intentionally left
in `.cursor/rules/docs/`
- Vitest skill already shared via symlink (`.claude/skills/vitest` →
`.agents/skills/vitest`) — nothing to migrate
- Grouped ~21 granular cursor rules into 5 new skills + 1 updated skill
by topic
- `studio-architecture` skill fully merged into `CLAUDE.md` and deleted
to avoid overlap
- Skills are self-contained (content inlined, not relying on sub-files)
since Claude reads SKILL.md first
- Skills cross-reference each other inline where relevant (e.g.
best-practices → testing, error-handling, queries)
- No `paths` frontmatter — would auto-inject full skill content on every
matching file. Current description-based matching is more selective and
token-efficient.

**Removed:**
- `.cursor/rules/studio/` (21 rule files covering architecture, best
practices, UI patterns, queries, styling, etc.)
- `.cursor/rules/testing/` (e2e-studio + unit-integration rules)
- `.cursor/rules/studio-useStaticEffectEvent.mdc`
- `.claude/skills/studio-architecture/` — fully merged into CLAUDE.md to
avoid duplication
- `.claude/skills/studio-testing/rules/` — orphaned sub-files after
inlining content into SKILL.md

**Added:**
- `.claude/CLAUDE.md` — concise monorepo overview with structure,
commands, and conventions. Absorbs studio-architecture content.
References `studio-*` skills for detail.
- `.claude/skills/studio-best-practices/` — boolean naming, component
structure, loading/error/success patterns, state management, hooks,
TypeScript conventions. Cross-references `vercel-composition-patterns`,
`studio-ui-patterns`, `studio-queries`, `studio-error-handling`, and
`studio-testing` inline where relevant.
- `.claude/skills/studio-ui-patterns/` — layout, forms, tables, charts,
empty states, navigation, cards, alerts, sheets. Grouped from ~10
separate cursor rules into one cohesive skill.
- `.claude/skills/studio-queries/` — React Query `queryOptions` pattern,
`keys.ts` structure, mutation hook template, imperative fetching.
- `.claude/skills/use-static-effect-event/` — the `useStaticEffectEvent`
hook: when to use, when not to, patterns, implementation.

**Changed:**
- `.claude/skills/studio-e2e-tests/` — renamed from `e2e-studio-tests`
for `studio-*` naming consistency. Merged race condition, waiting
strategy, test structure, assertion, and cleanup patterns from the
cursor e2e rule.
- `.claude/skills/studio-testing/` — inlined key content from sub-rule
files directly into SKILL.md so it's self-contained. Removed broken
`AGENTS.md` reference. Deleted orphaned `rules/` sub-files.
- `.claude/skills/vercel-composition-patterns/` — added note that Studio
uses React 18, so React 19 patterns should be skipped.
- `.gitignore` — added `!.claude/CLAUDE.md` exception so it's tracked.

## To test

- Open Claude Code in the repo, verify `.claude/CLAUDE.md` loads as
project context
- Ask Claude about Studio conventions and verify it references the right
skills
- Check that `studio-*` skills appear in the skill list

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:33:04 +08:00

2.2 KiB

applyTo
applyTo
e2e/studio/**,apps/studio/**

Studio E2E Test Review Rules

All comments are advisory.

Selector Priority (best to worst)

  1. getByRole with accessible name — most robust, tests accessibility

    page.getByRole('button', { name: 'Save' })
    
  2. getByTestId — stable, explicit test hooks

    page.getByTestId('table-editor-side-panel')
    
  3. getByText with exact match — good for unique text

    page.getByText('Data API Access', { exact: true })
    
  4. locator with CSS — use sparingly, more fragile

    page.locator('[data-state="open"]')
    

Patterns to Flag

  • XPath selectors — fragile to DOM changes

    // BAD
    locator('xpath=ancestor::div[contains(@class, "space-y")]')
    
  • Parent traversal with locator('..') — breaks when structure changes

    // BAD
    element.locator('..').getByRole('button')
    
  • waitForTimeout — never use; wait for something specific instead

    // 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
    
  • force: true on clicks — make elements visible first instead

    // BAD
    await menuButton.click({ force: true })
    
    // GOOD — hover to reveal, then click
    await tableRow.hover()
    await expect(menuButton).toBeVisible()
    await menuButton.click()
    
  • Broad filter({ hasText }) on generic elements — may match multiple elements; scope to specific containers instead

Good Practices to Encourage

  • Scope selectors to containers: page.getByTestId('side-panel').getByRole('switch')
  • Add aria-label to icon-only buttons in source code for better test selectors
  • Use test.describe.configure({ mode: 'serial' }) for tests sharing database state
  • Add messages to expects: await expect(locator, 'why').toBeVisible({ timeout: 30000 })

Canonical standard: .claude/skills/studio-e2e-tests/SKILL.md