Claude Code Plugins

Community-maintained marketplace

Feedback

synthetic-monitoring

@aj-geddes/useful-ai-prompts
4
0

Implement synthetic monitoring and automated testing to simulate user behavior and detect issues before users. Use when creating end-to-end test scenarios, monitoring API flows, or validating user workflows.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name synthetic-monitoring
description Implement synthetic monitoring and automated testing to simulate user behavior and detect issues before users. Use when creating end-to-end test scenarios, monitoring API flows, or validating user workflows.

Synthetic Monitoring

Overview

Set up synthetic monitoring to automatically simulate real user journeys, API workflows, and critical business transactions to detect issues and validate performance.

When to Use

  • End-to-end workflow validation
  • API flow testing
  • User journey simulation
  • Transaction monitoring
  • Critical path validation

Instructions

1. Synthetic Tests with Playwright

// synthetic-tests.js
const { chromium } = require('playwright');

class SyntheticMonitor {
  constructor(config = {}) {
    this.baseUrl = config.baseUrl || 'https://app.example.com';
    this.timeout = config.timeout || 30000;
  }

  async testUserFlow() {
    const browser = await chromium.launch();
    const page = await browser.newPage();
    const metrics = { steps: {} };
    const startTime = Date.now();

    try {
      // Step 1: Navigate to login
      let stepStart = Date.now();
      await page.goto(`${this.baseUrl}/login`, { waitUntil: 'networkidle' });
      metrics.steps.navigation = Date.now() - stepStart;

      // Step 2: Perform login
      stepStart = Date.now();
      await page.fill('input[name="email"]', 'test@example.com');
      await page.fill('input[name="password"]', 'password123');
      await page.click('button[type="submit"]');
      await page.waitForNavigation({ waitUntil: 'networkidle' });
      metrics.steps.login = Date.now() - stepStart;

      // Step 3: Navigate to dashboard
      stepStart = Date.now();
      await page.goto(`${this.baseUrl}/dashboard`, { waitUntil: 'networkidle' });
      metrics.steps.dashboard = Date.now() - stepStart;

      // Step 4: Search for products
      stepStart = Date.now();
      await page.fill('input[placeholder="Search products"]', 'laptop');
      await page.waitForSelector('.product-list');
      metrics.steps.search = Date.now() - stepStart;

      // Step 5: Add to cart
      stepStart = Date.now();
      const firstProduct = await page.$('.product-item');
      if (firstProduct) {
        await firstProduct.click();
        await page.click('button:has-text("Add to Cart")');
        await page.waitForSelector('[data-testid="cart-count"]');
      }
      metrics.steps.addToCart = Date.now() - stepStart;

      metrics.totalTime = Date.now() - startTime;
      metrics.status = 'success';
    } catch (error) {
      metrics.status = 'failed';
      metrics.error = error.message;
      metrics.totalTime = Date.now() - startTime;
    } finally {
      await browser.close();
    }

    return metrics;
  }

  async testMobileUserFlow() {
    const browser = await chromium.launch();
    const context = await browser.createBrowserContext({
      ...chromium.devices['iPhone 12']
    });
    const page = await context.newPage();

    try {
      const metrics = { device: 'iPhone 12', steps: {} };
      const startTime = Date.now();

      let stepStart = Date.now();
      await page.goto(this.baseUrl, { waitUntil: 'networkidle' });
      metrics.steps.navigation = Date.now() - stepStart;

      const viewport = page.viewportSize();
      metrics.viewport = viewport;

      stepStart = Date.now();
      await page.click('.menu-toggle');
      await page.waitForSelector('.mobile-menu.open');
      metrics.steps.mobileInteraction = Date.now() - stepStart;

      metrics.totalTime = Date.now() - startTime;
      metrics.status = 'success';

      return metrics;
    } catch (error) {
      return { status: 'failed', error: error.message, device: 'iPhone 12' };
    } finally {
      await browser.close();
    }
  }

  async testWithPerformanceMetrics() {
    const browser = await chromium.launch();
    const page = await browser.newPage();

    try {
      await page.goto(this.baseUrl, { waitUntil: 'networkidle' });

      const perfMetrics = JSON.parse(
        await page.evaluate(() => JSON.stringify(window.performance.timing))
      );

      const metrics = {
        navigationTiming: {
          domInteractive: perfMetrics.domInteractive - perfMetrics.navigationStart,
          domComplete: perfMetrics.domComplete - perfMetrics.navigationStart,
          loadComplete: perfMetrics.loadEventEnd - perfMetrics.navigationStart
        },
        status: 'success'
      };

      return metrics;
    } catch (error) {
      return { status: 'failed', error: error.message };
    } finally {
      await browser.close();
    }
  }

  async recordMetrics(testName, metrics) {
    try {
      await axios.post('http://monitoring-service/synthetic-results', {
        testName,
        timestamp: new Date(),
        metrics,
        passed: metrics.status === 'success'
      });
    } catch (error) {
      console.error('Failed to record metrics:', error);
    }
  }
}

module.exports = SyntheticMonitor;

2. API Synthetic Tests

// api-synthetic-tests.js
const axios = require('axios');

class APISyntheticTests {
  constructor(config = {}) {
    this.baseUrl = config.baseUrl || 'https://api.example.com';
    this.client = axios.create({ baseURL: this.baseUrl });
  }

  async testAuthenticationFlow() {
    const results = { steps: {}, status: 'success' };

    try {
      const registerStart = Date.now();
      const registerRes = await this.client.post('/auth/register', {
        email: `test-${Date.now()}@example.com`,
        password: 'Test@123456'
      });
      results.steps.register = Date.now() - registerStart;

      if (registerRes.status !== 201) throw new Error('Registration failed');

      const loginStart = Date.now();
      const loginRes = await this.client.post('/auth/login', {
        email: registerRes.data.email,
        password: 'Test@123456'
      });
      results.steps.login = Date.now() - loginStart;

      const token = loginRes.data.token;

      const authStart = Date.now();
      await this.client.get('/api/profile', {
        headers: { Authorization: `Bearer ${token}` }
      });
      results.steps.authenticatedRequest = Date.now() - authStart;

      const logoutStart = Date.now();
      await this.client.post('/auth/logout', {}, {
        headers: { Authorization: `Bearer ${token}` }
      });
      results.steps.logout = Date.now() - logoutStart;

      return results;
    } catch (error) {
      results.status = 'failed';
      results.error = error.message;
      return results;
    }
  }

  async testTransactionFlow() {
    const results = { steps: {}, status: 'success' };

    try {
      const orderStart = Date.now();
      const orderRes = await this.client.post('/api/orders', {
        items: [{ sku: 'ITEM-001', quantity: 2 }]
      }, {
        headers: { 'X-Idempotency-Key': `order-${Date.now()}` }
      });
      results.steps.createOrder = Date.now() - orderStart;

      const getStart = Date.now();
      const getRes = await this.client.get(`/api/orders/${orderRes.data.id}`);
      results.steps.getOrder = Date.now() - getStart;

      const paymentStart = Date.now();
      await this.client.post(`/api/orders/${orderRes.data.id}/payment`, {
        method: 'credit_card',
        amount: getRes.data.total
      });
      results.steps.processPayment = Date.now() - paymentStart;

      return results;
    } catch (error) {
      results.status = 'failed';
      results.error = error.message;
      return results;
    }
  }

  async testUnderLoad(concurrentUsers = 10, duration = 60000) {
    const startTime = Date.now();
    const results = {
      totalRequests: 0,
      successfulRequests: 0,
      failedRequests: 0,
      averageResponseTime: 0,
      p95ResponseTime: 0
    };

    const responseTimes = [];

    const makeRequest = async () => {
      const reqStart = Date.now();
      try {
        await this.client.get('/api/health');
        results.successfulRequests++;
        responseTimes.push(Date.now() - reqStart);
      } catch {
        results.failedRequests++;
      }
      results.totalRequests++;
    };

    const userSimulations = Array(concurrentUsers).fill(null).map(async () => {
      while (Date.now() - startTime < duration) {
        await makeRequest();
        await new Promise(r => setTimeout(r, Math.random() * 1000));
      }
    });

    await Promise.all(userSimulations);

    responseTimes.sort((a, b) => a - b);
    results.averageResponseTime =
      responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length;
    results.p95ResponseTime =
      responseTimes[Math.floor(responseTimes.length * 0.95)];

    return results;
  }
}

module.exports = APISyntheticTests;

3. Scheduled Synthetic Monitoring

// scheduled-monitor.js
const cron = require('node-cron');
const SyntheticMonitor = require('./synthetic-tests');
const APISyntheticTests = require('./api-synthetic-tests');
const axios = require('axios');

class ScheduledSyntheticMonitor {
  constructor(config = {}) {
    this.eMonitor = new SyntheticMonitor(config);
    this.apiTests = new APISyntheticTests(config);
    this.alertThreshold = config.alertThreshold || 5000;
  }

  start() {
    cron.schedule('*/5 * * * *', () => this.runE2ETests());
    cron.schedule('*/2 * * * *', () => this.runAPITests());
    cron.schedule('0 * * * *', () => this.runLoadTest());
  }

  async runE2ETests() {
    try {
      const metrics = await this.eMonitor.testUserFlow();
      await this.recordResults('e2e-user-flow', metrics);

      if (metrics.totalTime > this.alertThreshold) {
        await this.sendAlert('e2e-user-flow', metrics);
      }
    } catch (error) {
      console.error('E2E test failed:', error);
    }
  }

  async runAPITests() {
    try {
      const authMetrics = await this.apiTests.testAuthenticationFlow();
      const transactionMetrics = await this.apiTests.testTransactionFlow();

      await this.recordResults('api-auth-flow', authMetrics);
      await this.recordResults('api-transaction-flow', transactionMetrics);

      if (authMetrics.status === 'failed' || transactionMetrics.status === 'failed') {
        await this.sendAlert('api-tests', { authMetrics, transactionMetrics });
      }
    } catch (error) {
      console.error('API test failed:', error);
    }
  }

  async runLoadTest() {
    try {
      const results = await this.apiTests.testUnderLoad(10, 30000);
      await this.recordResults('load-test', results);

      if (results.failedRequests > 0) {
        await this.sendAlert('load-test', results);
      }
    } catch (error) {
      console.error('Load test failed:', error);
    }
  }

  async recordResults(testName, metrics) {
    try {
      await axios.post('http://monitoring-service/synthetic-results', {
        testName,
        timestamp: new Date(),
        metrics
      });
      console.log(`Recorded: ${testName}`, metrics);
    } catch (error) {
      console.error('Failed to record results:', error);
    }
  }

  async sendAlert(testName, metrics) {
    try {
      await axios.post('http://alerting-service/alerts', {
        type: 'synthetic_monitoring',
        testName,
        severity: 'warning',
        message: `Synthetic test '${testName}' has issues`,
        metrics,
        timestamp: new Date()
      });
      console.log(`Alert sent for ${testName}`);
    } catch (error) {
      console.error('Failed to send alert:', error);
    }
  }
}

module.exports = ScheduledSyntheticMonitor;

Best Practices

✅ DO

  • Test critical user journeys
  • Simulate real browser conditions
  • Monitor from multiple locations
  • Track response times
  • Alert on test failures
  • Rotate test data
  • Test mobile and desktop
  • Include error scenarios

❌ DON'T

  • Test with production data
  • Reuse test accounts
  • Skip timeout configurations
  • Ignore test maintenance
  • Test too frequently
  • Hard-code credentials
  • Ignore geographic variations
  • Test only happy paths

Key Metrics

  • Response time
  • Success rate
  • Availability
  • Core Web Vitals
  • Error rate