mirror of
https://github.com/supabase/supabase.git
synced 2026-05-06 22:18:00 +08:00
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>
87 lines
2.2 KiB
Markdown
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`
|