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 <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-01-29 06:34:08 +00:00
1 parent b48320fc9a
commit 6d207d1094
2 files changed
+76 -3

No files matched your search

+2 -2
View File
@@ -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 },
+74 -1
View File
@@ -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) {