# Performance Monitoring in Playwright Tests

Performance monitoring is more than just numbers — it’s about understanding **how your users experience your app** during automated test runs.
This guide will teach you not just how to set it up, but also **why each step matters**.

---

## Why Performance Monitoring Matters

Think of Playwright tests as quality control for your app’s speed and responsiveness.
By adding performance monitoring, you can:

- 🚨 **Catch regressions early** before users feel them
- 🎯 **Keep user experience consistent** across releases
- 🔎 **Spot bottlenecks** in login, navigation, or heavy data flows
- 📊 **Make informed decisions** with hard data, not guesses
- 🏆 **Maintain performance standards** as features grow

> **Key Insight:** Without metrics, “fast” is just a feeling. With metrics, it’s a fact.

---

## How It Works: The Architecture

The monitoring system has **four pillars**:

1. **PerformanceCollector Class** – Collects raw metrics
2. **Performance Utilities** – Easy-to-use helper functions
3. **Test Integration** – Hooks directly into Playwright tests
4. **Report Generation** – Creates JSON reports you can analyze later

Here’s a mental model:

```
Playwright Test
      |
      v
PerformanceCollector (collects data)
      |
      v
Report Generation → JSON / HTML / CI attachments
```

### Core Collector

```typescript
// performanceUtils.ts
export class PerformanceCollector {
  private page: Page;
  public metrics: any;
  public navigationMetrics: any[];
  private cdpSession: any;

  // Methods for collecting various metrics
  async collectNavigationMetrics(label: string)
  async collectWebVitals()
  async measureUserAction(actionName: string, actionFn: () => Promise<void>)
  generateReport()
}
```

👉 **Teaching Point:** `measureUserAction` wraps a user action and times it, giving you reproducible benchmarks.

---

## Quick Start: A Simple Example

```typescript
import { createPerformanceCollector, attachPerformanceData } from './performanceUtils';

test('My test with performance monitoring', async ({ page }, testInfo) => {
  const perfCollector = await createPerformanceCollector(page);

  // Measure user action
  await perfCollector.measureUserAction('click-button', async () => {
    await page.click('#my-button');
  });

  // Attach data to the test report
  await attachPerformanceData(testInfo, perfCollector);
});
```

✅ After this test runs, you’ll find performance data **directly in the Playwright report**.

---

## Advanced Example: A Complete User Flow

```typescript
test('Complex user flow with performance tracking', async ({ page }, testInfo) => {
  const perfCollector = await createPerformanceCollector(page);

  await perfCollector.collectNavigationMetrics('initial-load');

  await perfCollector.measureUserAction('login', async () => {
    await page.fill('#username', 'user');
    await page.fill('#password', 'pass');
    await page.click('#login-button');
  });

  await perfCollector.measureUserAction('navigate-to-dashboard', async () => {
    await page.goto('/dashboard');
  });

  await attachPerformanceData(testInfo, perfCollector);
});
```

> **Pro Tip:** Use descriptive labels like `'login'` or `'navigate-to-dashboard'`
to make reports easy to scan.

---

## What Metrics You’ll See

### Navigation Metrics (Page Load)

- `domContentLoaded` → When DOM is ready
- `loadComplete` → When page is fully loaded
- `firstPaint` → When users first *see* something
- `serverResponse` → How quickly the backend responds

### User Action Metrics

- `duration` → How long the action took
- `metrics` → Detailed performance snapshots

### Memory Usage

- `used`, `total`, `limit` → Helps catch leaks and spikes

### Web Vitals

- **LCP** → Largest Contentful Paint
- **FID** → First Input Delay
- **CLS** → Layout stability

---

## Reading the Data: A Beginner’s Lens

Here’s what a **healthy test run** might look like:

```json
{
  "label": "home-page-load",
  "metrics": {
    "domContentLoaded": 294,
    "loadComplete": 295,
    "serverResponse": 27.6,
    "resourceCount": 96
  }
}
```

**Interpretation:**

- DOM loaded fast (<500ms) ✅
- Server response is excellent (<100ms) ✅
- Resource count is reasonable for a SPA ✅

Now, here’s a **problematic run**:

```json
{
  "label": "slow-page-load",
  "metrics": {
    "domContentLoaded": 2500,
    "loadComplete": 5000,
    "serverResponse": 800,
    "resourceCount": 200
  }
}
```

**Interpretation:**

- DOM took 2.5s ❌
- Full load took 5s ❌
- Too many resources (200) ❌

> **Lesson:** Slow page loads often mean large bundles, too many requests, or server lag.

---

## Performance Threshold Cheat Sheet

| Metric | Excellent | Good | Poor |
|--------|-----------|------|------|
| domContentLoaded | < 500ms | < 1000ms | > 2000ms |
| loadComplete | < 1000ms | < 2000ms | > 3000ms |
| userAction duration | < 100ms | < 300ms | > 500ms |
| memory usage | < 50MB | < 100MB | > 150MB |

👉 Use these thresholds to set alerts in your regression tests.

---

## Common Patterns

1. **Initial Page Load**
   - ✅ DOM in <500ms
   - ✅ Load in <1000ms
   - ⚠️ Watch out for large bundles

2. **User Interaction**
   - ✅ Actions under 100ms
   - ✅ Few/no extra requests
   - ⚠️ Avoid bloated API calls

3. **Navigation**
   - ✅ <200ms between pages
   - ⚠️ Inconsistency usually means missing cache headers

---

## Best Practices

- 📏 **Consistency** – Measure the same flows every run
- 🧪 **Realism** – Test with production-like data
- 🏗 **Environment Control** – Use stable test environments
- 📉 **Set Thresholds** – Define what “slow” means for your team
- 🔁 **Continuous Monitoring** – Run in CI/CD and watch trends

> **Remember:** A fast app last release doesn’t guarantee it’s fast today.

---

## Migration Tip

**Before (Manual Timing):**
```typescript
const start = Date.now();
await page.click('#button');
console.log(Date.now() - start);
```

**After (Structured Monitoring):**

```typescript
await perfCollector.measureUserAction('button-click', async () => {
  await page.click('#button');
});
```

✅ Cleaner, more consistent, and automatically reported.

---

## Key Takeaway

Performance monitoring in Playwright isn’t just about collecting data — it’s
about making your tests **teach you** how users experience your app.
The **PerformanceCollector** class plus good testing habits give you a clear,
data-driven picture of app health.
