From 6d207d10948044e6109db22e199ca01996d4428c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 06:34:08 +0000 Subject: [PATCH] feat(telemetry): add Playwright and smoke test aggregation - Updated `playwright.config.ts` to output JSON test results to `artifacts/test-results/results.json`. - Enhanced `scripts/agent/telemetry-aggregator.mjs` to ingest Playwright JSON reports, mapping failures to the unified error schema with PII sanitization. - Updated aggregator to detect smoke test failures via `success: false` property. - Verified aggregation flow by capturing a simulated Playwright failure. Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- playwright.config.ts | 4 +- scripts/agent/telemetry-aggregator.mjs | 75 +++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index 7ccf7d60..58d26ea0 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -9,8 +9,8 @@ export default defineConfig({ outputDir: "artifacts/test-results", timeout: 60_000, reporter: process.env.CI - ? [["github"], ["html", { open: "never" }]] - : [["list"], ["html", { open: "never" }]], + ? [["github"], ["html", { open: "never" }], ["json", { outputFile: "artifacts/test-results/results.json" }]] + : [["list"], ["html", { open: "never" }], ["json", { outputFile: "artifacts/test-results/results.json" }]], use: { baseURL: BASE_URL, viewport: { width: 1280, height: 720 }, diff --git a/scripts/agent/telemetry-aggregator.mjs b/scripts/agent/telemetry-aggregator.mjs index 615799b2..73a4afc2 100644 --- a/scripts/agent/telemetry-aggregator.mjs +++ b/scripts/agent/telemetry-aggregator.mjs @@ -196,7 +196,11 @@ function collectSmokeTests() { const content = JSON.parse(fs.readFileSync(path.join(ARTIFACTS_DIR, file), 'utf8')); // Expected format: { timestamp, status, error, logs } - if (content.status && (content.status.toLowerCase() === 'failure' || content.status.toLowerCase() === 'fail')) { + // Also handle { timestamp, success: false, logFile } from smoke-test.mjs + if ( + (content.status && (content.status.toLowerCase() === 'failure' || content.status.toLowerCase() === 'fail')) || + (content.success === false) + ) { const errorMsg = content.error || 'Unknown Smoke Test Failure'; const sanitizedError = sanitize(errorMsg); @@ -223,6 +227,68 @@ function collectSmokeTests() { return errors; } +function collectPlaywrightTests() { + const errors = []; + const resultsPath = path.join(ARTIFACTS_DIR, 'test-results', 'results.json'); + + if (!fs.existsSync(resultsPath)) return errors; + + try { + const content = JSON.parse(fs.readFileSync(resultsPath, 'utf8')); + + // Iterate over suites recursively or just check failures + // Playwright JSON structure: { suites: [ { specs: [ { tests: [ { results: [ { status, error } ] } ] } ] } ] } + + function processSuite(suite) { + if (suite.specs) { + for (const spec of suite.specs) { + processSpec(spec); + } + } + if (suite.suites) { + for (const childSuite of suite.suites) { + processSuite(childSuite); + } + } + } + + function processSpec(spec) { + for (const test of spec.tests || []) { + for (const result of test.results || []) { + if (result.status === 'failed' || result.status === 'timedOut') { + const error = result.error || {}; + const message = error.message || 'Unknown Playwright Error'; + const stack = error.stack || message; + + const sanitizedMessage = sanitize(message); + const sanitizedStack = sanitize(stack); + + errors.push({ + source: `playwright:${spec.title}`, + title: `Playwright Failure: ${spec.title}`, + details: [sanitizedMessage], + stack: sanitizedStack, + fingerprint: getFingerprint(sanitizedStack), + severity: 'High', + owner: 'QA Team' // Default owner for e2e failures + }); + } + } + } + } + + if (content.suites) { + for (const suite of content.suites) { + processSuite(suite); + } + } + } catch (err) { + console.warn('Failed to parse Playwright results:', err.message); + } + + return errors; +} + function collectFuzzReports() { const errors = []; if (!fs.existsSync(ARTIFACTS_DIR)) return errors; @@ -504,6 +570,13 @@ async function main() { errors.push(...loadTestErrors); } + // Playwright Tests + const playwrightErrors = collectPlaywrightTests(); + if (playwrightErrors.length > 0) { + console.log(`Collected ${playwrightErrors.length} Playwright test errors.`); + errors.push(...playwrightErrors); + } + // Fuzz Reports const fuzzErrors = collectFuzzReports(); if (fuzzErrors.length > 0) {