#!/usr/bin/env node const fs = require('fs'); const [, , resultsPath] = process.argv; // This runs with `if: always()`, so it also fires when an earlier step failed and // no results file was ever written. Report that plainly and exit 0 — the job still // fails on the real step, and a stack trace here would only bury it. if (!fs.existsSync(resultsPath)) { report([`## Playwright E2E Results`, '', `No results file at \`${resultsPath}\` — the test step failed before writing one.`, '']); process.exit(0); } const raw = fs.readFileSync(resultsPath, 'utf-8'); const data = JSON.parse(raw); const stats = data.stats || {}; const lines = []; lines.push('## Playwright E2E Results'); lines.push(''); lines.push('| | Count |'); lines.push('|---|---|'); lines.push(`| ✅ Passed | ${stats.expected || 0} |`); lines.push(`| ❌ Failed | ${stats.unexpected || 0} |`); lines.push(`| ⚠️ Flaky | ${stats.flaky || 0} |`); lines.push(`| ⏭️ Skipped | ${stats.skipped || 0} |`); lines.push(''); function collectFailures(suites, path) { path = path || []; let failures = []; for (const suite of suites || []) { const currentPath = path.concat(suite.title).filter(Boolean); for (const spec of suite.specs || []) { for (const test of spec.tests || []) { for (const result of test.results || []) { if (result.status !== 'passed' && result.status !== 'skipped') { failures.push(`${currentPath.join(' > ')} > ${spec.title}: ${result.status}`); } } } } if (suite.suites) failures = failures.concat(collectFailures(suite.suites, currentPath)); } return failures; } const failures = collectFailures(data.suites); if (failures.length) { lines.push('### Failures'); lines.push(''); for (const f of failures) lines.push(`- ${f}`); lines.push(''); } report(lines); process.exit((stats.unexpected || 0) > 0 ? 1 : 0); function report(out) { const summaryPath = process.env.GITEA_STEP_SUMMARY || process.env.GITHUB_STEP_SUMMARY; if (summaryPath) { fs.appendFileSync(summaryPath, out.join('\n') + '\n'); } else { console.log(out.join('\n')); } }