| 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
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 {
let stepStart = Date.now();
await page.goto(`${this.baseUrl}/login`, { waitUntil: 'networkidle' });
metrics.steps.navigation = Date.now() - stepStart;
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;
stepStart = Date.now();
await page.goto(`${this.baseUrl}/dashboard`, { waitUntil: 'networkidle' });
metrics.steps.dashboard = Date.now() - stepStart;
stepStart = Date.now();
await page.fill('input[placeholder="Search products"]', 'laptop');
await page.waitForSelector('.product-list');
metrics.steps.search = Date.now() - stepStart;
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
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();
loginStart = .();
loginRes = ..(, {
: registerRes..,
:
});
results.. = .() - loginStart;
token = loginRes..;
authStart = .();
..(, {
: { : }
});
results.. = .() - authStart;
logoutStart = .();
..(, {}, {
: { : }
});
results.. = .() - logoutStart;
results;
} (error) {
results. = ;
results. = error.;
results;
}
}
() {
results = { : {}, : };
{
orderStart = .();
orderRes = ..(, {
: [{ : , : }]
}, {
: { : }
});
results.. = .() - orderStart;
getStart = .();
getRes = ..();
results.. = .() - getStart;
paymentStart = .();
..(, {
: ,
: getRes..
});
results.. = .() - paymentStart;
results;
} (error) {
results. = ;
results. = error.;
results;
}
}
() {
startTime = .();
results = {
: ,
: ,
: ,
: ,
:
};
responseTimes = [];
= () => {
reqStart = .();
{
..();
results.++;
responseTimes.(.() - reqStart);
} {
results.++;
}
results.++;
};
userSimulations = (concurrentUsers).().( () => {
(.() - startTime < duration) {
();
( (r, .() * ));
}
});
.(userSimulations);
responseTimes.( a - b);
results. =
responseTimes.( a + b, ) / responseTimes.;
results. =
responseTimes[.(responseTimes. * )];
results;
}
}
. = ;
3. Scheduled Synthetic Monitoring
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() {
{
metrics = ..();
.(, metrics);
(metrics. > .) {
.(, metrics);
}
} (error) {
.(, error);
}
}
() {
{
authMetrics = ..();
transactionMetrics = ..();
.(, authMetrics);
.(, transactionMetrics);
(authMetrics. === || transactionMetrics. === ) {
.(, { authMetrics, transactionMetrics });
}
} (error) {
.(, error);
}
}
() {
{
results = ..(, );
.(, results);
(results. > ) {
.(, results);
}
} (error) {
.(, error);
}
}
() {
{
axios.(, {
testName,
: (),
metrics
});
.(, metrics);
} (error) {
.(, error);
}
}
() {
{
axios.(, {
: ,
testName,
: ,
: ,
metrics,
: ()
});
.();
} (error) {
.(, error);
}
}
}
. = ;
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