diff --git a/.agents/skills/write-tests/SKILL.md b/.agents/skills/write-tests/SKILL.md index 924388b13215..12bcfeb5a93f 100644 --- a/.agents/skills/write-tests/SKILL.md +++ b/.agents/skills/write-tests/SKILL.md @@ -465,6 +465,22 @@ test('captures transactions for all routes', async ({ baseURL }) => { }); ``` +### SSR hydration timing + +In SSR apps (Nuxt, SvelteKit, Next.js), elements are visible before framework event handlers attach. +Playwright's actionability checks pass on server-rendered HTML, so `.click()` can fire before +hydration, making it a no-op and timing out `waitForError`. Wait for the Sentry SDK before +interacting: + +```typescript +await page.goto(`/test-param/1234`); +await page.waitForFunction(() => typeof window.__SENTRY__ === 'object'); +await page.locator('#errorBtn').click(); +``` + +Don't use `networkidle`. Playwright discourages it. Use `waitForFunction` with a condition that +directly proves readiness. + ### Common pitfalls - **Proxy name mismatch:** `APP_NAME` must match `proxyServerName` in `start-event-proxy.mjs`. diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.client.test.ts index 123b6f9a332a..0bf456015834 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/errors.client.test.ts @@ -35,6 +35,7 @@ test.describe('client-side errors', async () => { }); await page.goto(`/test-param/1234`); + await page.waitForFunction(() => typeof window.__SENTRY__ === 'object'); await page.locator('#errorBtn').click(); const error = await errorPromise;