# Common Pitfalls (Top 10)

## 1. waitForTimeout

**Symptom:** Slow, flaky tests.

```typescript
// BAD
await page.waitForTimeout(3000);

// GOOD
await expect(page.getByTestId('result')).toBeVisible();
```

## 2. Non-Web-First Assertions

**Symptom:** Assertions fail on dynamic content.

```typescript
// BAD — checks once, no retry
const text = await page.textContent('.msg');
expect(text).toBe('Done');

// GOOD — retries until timeout
await expect(page.getByText('Done')).toBeVisible();
```

## 3. Missing await

**Symptom:** Random passes/failures, tests seem to skip steps.

```typescript
// BAD
page.goto('/dashboard');
expect(page.getByText('Welcome')).toBeVisible();

// GOOD
await page.goto('/dashboard');
await expect(page.getByText('Welcome')).toBeVisible();
```

## 4. Hardcoded URLs

**Symptom:** Tests break in different environments.

```typescript
// BAD
await page.goto('http://localhost:3000/login');

// GOOD — uses baseURL from config
await page.goto('/login');
```

## 5. CSS Selectors Instead of Roles

**Symptom:** Tests break after CSS refactors.

```typescript
// BAD
await page.click('#submit-btn');

// GOOD
await page.getByRole('button', { name: 'Submit' }).click();
```

## 6. Shared State Between Tests

**Symptom:** Tests pass alone, fail in suite.

```typescript
// BAD — test B depends on test A
let userId: string;
test('create user', async () => { userId = '123'; });
test('edit user', async () => { /* uses userId */ });

// GOOD — each test is independent
test('edit user', async ({ request }) => {
  const res = await request.post('/api/users', { data: { name: 'Test' } });
  const { id } = await res.json();
  // ...
});
```

## 7. Using networkidle

**Symptom:** Tests hang or timeout unpredictably.

```typescript
// BAD — waits for all network activity to stop
await page.goto('/dashboard', { waitUntil: 'networkidle' });

// GOOD — wait for specific content
await page.goto('/dashboard');
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
```

## 8. Not Waiting for Navigation

**Symptom:** Assertions run on wrong page.

```typescript
// BAD — click navigates but we don't wait
await page.getByRole('link', { name: 'Settings' }).click();
await expect(page.getByRole('heading')).toHaveText('Settings');

// GOOD — wait for URL change
await page.getByRole('link', { name: 'Settings' }).click();
await expect(page).toHaveURL('/settings');
await expect(page.getByRole('heading')).toHaveText('Settings');
```

## 9. Testing Implementation, Not Behavior

**Symptom:** Tests break on every refactor.

```typescript
// BAD — tests CSS class (implementation detail)
await expect(page.locator('.btn')).toHaveClass('btn-primary active');

// GOOD — tests what the user sees
await expect(page.getByRole('button', { name: 'Save' })).toBeEnabled();
```

## 10. No Error Case Tests

**Symptom:** App breaks on errors but all tests pass.

```typescript
// Missing: what happens when the API fails?
test('should handle API error', async ({ page }) => {
  await page.route('**/api/data', (route) =>
    route.fulfill({ status: 500 })
  );
  await page.goto('/dashboard');
  await expect(page.getByText(/error|try again/i)).toBeVisible();
});
```
