diff --git a/.claude-skills/frontend-debugging_skill/SKILL.md b/.claude-skills/frontend-debugging_skill/SKILL.md index f8b7de2..c9d41cc 100644 --- a/.claude-skills/frontend-debugging_skill/SKILL.md +++ b/.claude-skills/frontend-debugging_skill/SKILL.md @@ -19,76 +19,122 @@ ### Phase 1: Health Check ```bash task frontend:dev -# Check browser console +# Check browser console for errors +# Verify page loads without JavaScript errors ``` ### Phase 2: Type Safety ```bash task frontend:typecheck task frontend:lint +# Ensure no TypeScript or linting errors ``` ### Phase 3: Encore Client Sync ```bash task founder:workflows:regen-client -# Verify ~encore/clients imports +# Verify ~encore/clients imports work +# Check generated types are latest ``` ### Phase 4: Svelte 5 Runes -- Check proper rune usage -- $state for reactive state -- $derived for computed values -- $effect for side effects -- $props for component props +- ✅ Check proper rune usage ($state, $derived, $effect, $props) +- ✅ Verify runes only in `.svelte` files (not `.ts`) +- ✅ Ensure top-level declarations +- ✅ Check for conditional rune usage (not allowed) ### Phase 5: Routing -- Verify +page.svelte structure -- Check +layout.svelte hierarchy -- Review load functions - -### Phase 6: API Calls -- Always use Encore generated client -- Never manual `fetch()` calls -- Full type safety guaranteed +- ✅ Verify file structure: `+page.svelte`, `+layout.svelte` +- ✅ Check dynamic routes: `[id]/+page.svelte` +- ✅ Review load functions return correct shape +- ✅ Test URL navigation with `goto()` or click + +### Phase 6: API Calls & Data Loading +- ✅ Always use Encore generated client +- ✅ Never manual `fetch()` calls +- ✅ Full type safety guaranteed +- ✅ Verify load functions execute on server + client +- ✅ Check WebSocket streams connected properly ### Phase 7: SSR/CSR Issues -- Check server vs browser context -- Verify `browser` checks when needed +- ✅ Check server vs browser context +- ✅ Verify `browser` checks when needed +- ✅ Test `+page.server.ts` vs `+page.ts` load functions +- ✅ Ensure no DOM API calls during SSR ### Phase 8: Component Isolation -- Test component in isolation -- Check props/slots/events +- ✅ Test component in isolation +- ✅ Check $props destructuring correct +- ✅ Verify slot/snippet usage +- ✅ Test with different prop values -### Phase 9: Build Testing +### Phase 9: E2E Testing ```bash -task frontend:build -# Test production build +task frontend:test +# Run Playwright tests in headed mode +HEADLESS=false bun run test:e2e:headed ``` +**Key E2E patterns:** +- Race navigation + API with `Promise.all([page.waitForURL(...), button.click()])` +- Use data attributes for reliable selectors: `data-testid="name"` +- Wait for final output (rendered screenshots), not intermediate states +- Avoid sequential waits (waitForResponse → waitForURL) which cause hangs + ### Phase 10: Browser DevTools -- Use Svelte DevTools extension -- Check component state/props -- Review network requests +- ✅ Svelte DevTools extension: inspect component state +- ✅ Network tab: verify API calls, WebSocket connections +- ✅ Console: check for errors/warnings +- ✅ Performance: check for rendering slowdowns --- -## Common Issues +## Common Issues & Fixes + +### E2E Test Hangs +**Problem:** `page.waitForResponse()` + `page.waitForURL()` in sequence causes timeout + +**Fix:** +```typescript +// ❌ BAD: Sequential waits +await button.click(); +await page.waitForResponse(...); // HANGS +await page.waitForURL(...); + +// ✅ GOOD: Parallel waits +await Promise.all([ + page.waitForURL(/\/run\/[a-f0-9-]+/i, { + waitUntil: "domcontentloaded", + timeout: 30000 + }), + button.click() +]); +``` ### Rune Misuse -- Can't use runes in `.ts` files (only `.svelte`) -- Must be top-level declarations -- No conditional runes +- ❌ Can't use runes in `.ts` files (only `.svelte`) +- ❌ Must be top-level declarations (no inside functions) +- ❌ No conditional runes +- ✅ Use reactive event handlers with `$effect` instead ### API Type Errors -- Regenerate client after backend changes -- Verify import paths use `~encore/clients` - -### SSR Hydration -- Match server/client rendered output -- Check for browser-only code in wrong places - -### Routing Issues -- File-based routing: check file structure -- Dynamic routes: `[slug]/+page.svelte` -- Verify load functions return correct shape +- ❌ Forgot to regenerate client after backend changes +- ❌ Wrong import path (should be `~encore/clients` not `./encore-client`) +- ✅ Run `task founder:workflows:regen-client` after backend API changes + +### SSR Hydration Mismatch +- ❌ Server renders different HTML than client +- ❌ Using browser-only APIs in +page.ts (should be +page.server.ts) +- ✅ Check timestamp/random values match between server and client render + +### Navigation Not Working +- ❌ Using manual `goto()` without waiting for page ready +- ❌ Link navigation blocked by unsaved form data +- ✅ Test selector matches actual button: use `getByRole()` or `data-testid` + +### WebSocket/Streaming Failures +- ❌ CORS issues with WebSocket endpoint +- ❌ Backend endpoint not registered (needs server restart) +- ✅ Check browser console for connection errors +- ✅ Verify endpoint exists via `browser.snapshot()` inspection diff --git a/.claude-skills/frontend-development_skill/SKILL.md b/.claude-skills/frontend-development_skill/SKILL.md index 6a2208c..90457d8 100644 --- a/.claude-skills/frontend-development_skill/SKILL.md +++ b/.claude-skills/frontend-development_skill/SKILL.md @@ -608,6 +608,110 @@ console.log('User logged in:', user); --- +## E2E Testing Patterns + +### 1. **Testing User Flows (Playwright)** + +Write deterministic E2E tests that verify complete user journeys: + +```typescript +// ✅ GOOD: Test complete user flow +test("run validation", async ({ page }) => { + // 1. Navigate to landing + await page.goto("/"); + await expect(page).toHaveTitle(/ScreenGraph/i); + + // 2. Start run via CTA + const button = page.getByRole("button", { name: /detect.*drift/i }); + await expect(button).toBeVisible(); + + // 3. Handle navigation + API response together + await Promise.all([ + page.waitForURL(/\/run\/[a-f0-9-]+/i, { + waitUntil: "domcontentloaded", + timeout: 30000 + }), + button.click() + ]); + + // 4. Verify UI fully loaded + const heading = page.getByRole("heading", { name: /run timeline/i }); + await expect(heading).toBeVisible(); + + // 5. Verify data appears (events, screenshots) + const events = page.locator('[data-testid="run-events"]'); + await expect(events).toBeVisible(); +}); +``` + +### 2. **Test Selectors with Data Attributes** + +Always use data attributes for reliable test selectors: + +```svelte + +