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

87 lines
2.2 KiB
Markdown

---
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
```typescript
page.getByRole('button', { name: 'Save' })
```
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 Flag
- **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')
```
- **`waitForTimeout`** — never use; wait for something specific instead
```typescript
// 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
```typescript
// 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`