Files
openobserve/tests/ui-testing/playwright-tests/utils/webhook-capture.js
T
Neha PandClaude Opus 4.7 b9846cf42e test: add metrics alert notification E2E test with self-contained ingestion (#12672)
## Summary
- Adds `alerts-metrics-notification.spec.js` — a 3-test UI suite
verifying the full metrics alert chain
- Test 1 (P1): PromQL alert triggers via scheduler, verified in history
UI — self-contained using `ensureMetricsIngested()`
- Test 2 (P2): Template body contains required alert variables
(`{alert_url}`, `{alert_name}`, `{stream_name}`)
- Test 3 (P1): Manual trigger from alert list more-options menu sends
notification
- Includes `alert-metrics-notification-findings.md` documenting manual
testing results (API schema, PromQL vs SQL, trigger indicators)

## Test plan
- [ ] Test 1: Alert triggers on freshly ingested `cpu_usage` metrics and
history rows appear in UI
- [ ] Test 2: Template editor (Monaco) shows expected variables
- [ ] Test 3: Manual trigger menu option calls PATCH /trigger and
succeeds

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-15 17:41:45 +00:00

99 lines
2.9 KiB
JavaScript

/**
* Webhook capture server — lightweight HTTP receiver for E2E tests.
*
* Spins up a local HTTP server that captures incoming POST bodies so tests
* can assert on outbound alert notification payloads (template rendering,
* variable substitution, alert_url correctness) without depending on
* external services like httpbin.org.
*
* Only works when the backend can reach localhost (e.g., CI or local dev).
*/
const http = require('http');
class WebhookCapture {
constructor() {
this.server = null;
this.port = 0;
this.payloads = [];
}
/**
* Start the capture server on a free port.
* @returns {Promise<number>} The port the server is listening on.
*/
async start() {
return new Promise((resolve, reject) => {
this.payloads = [];
this.server = http.createServer((req, res) => {
let body = '';
req.on('data', chunk => { body += chunk; });
req.on('end', () => {
try {
this.payloads.push({
method: req.method,
url: req.url,
headers: req.headers,
body: JSON.parse(body || '{}'),
rawBody: body,
timestamp: Date.now(),
});
} catch {
this.payloads.push({
method: req.method,
url: req.url,
headers: req.headers,
rawBody: body,
timestamp: Date.now(),
});
}
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ received: true }));
});
});
this.server.on('error', reject);
this.server.listen(0, '127.0.0.1', () => {
this.port = this.server.address().port;
resolve(this.port);
});
});
}
/**
* Stop the capture server.
*/
async stop() {
return new Promise((resolve) => {
if (!this.server) return resolve();
this.server.close(() => resolve());
this.server = null;
});
}
/**
* Get all captured payloads.
* @returns {Array} Array of captured request objects.
*/
getPayloads() {
return this.payloads;
}
/**
* Get the most recent captured payload body.
* @returns {Object|null}
*/
getLatestPayload() {
if (this.payloads.length === 0) return null;
return this.payloads[this.payloads.length - 1];
}
/**
* Clear all captured payloads (useful between test phases).
*/
clear() {
this.payloads = [];
}
}
module.exports = { WebhookCapture };