haven-playwright-integration
Version:
Seamless Playwright integration with HAVEN test case management
94 lines (83 loc) • 4 kB
JavaScript
const fs = require('fs');
const path = require('path');
const https = require('https');
// Shared paths provided by HAVEN runner
const automationCasesPath = "/shared/automation-cases.json";
const postBaseUrlPath = "/shared/result-post-url.txt";
const triggeredByPath = "/shared/triggered-by.txt";
const baseUrl = fs.readFileSync(postBaseUrlPath, "utf-8").trim();
let triggeredBy = null;
try { if (fs.existsSync(triggeredByPath)) triggeredBy = fs.readFileSync(triggeredByPath, 'utf-8').trim(); } catch { }
function parsePlaywrightJson(jsonPath) {
if (!jsonPath || !fs.existsSync(jsonPath)) return [];
const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8'));
const results = [];
// Playwright JSON format: look into tests/suites
function walk(node) {
if (!node) return;
if (node.title && typeof node.title === 'string') {
const m = node.title.match(/@TC-AUTO-\d+/);
if (m) {
const status = (node.status || node.outcome || 'passed').toLowerCase().includes('pass') ? 'pass' : (node.status || 'fail');
results.push({ automation_id: m[0], status });
}
}
for (const key of ['suites', 'tests', 'specs', 'entries', 'children']) {
const arr = node[key];
if (Array.isArray(arr)) arr.forEach(walk);
}
}
walk(data);
return results;
}
async function postJson(url, payload) {
return new Promise((resolve, reject) => {
const data = JSON.stringify(payload);
const req = https.request(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) } }, res => {
let body = '';
res.on('data', c => body += c);
res.on('end', () => resolve({ statusCode: res.statusCode, body }));
});
req.on('error', reject);
req.write(data);
req.end();
});
}
async function main() {
const planId = process.env.PLAN_ID || 'unknown_plan';
const runId = process.env.RUN_ID || 'unknown_run';
const testEnvironment = process.env.TEST_ENVIRONMENT || 'QA';
const jsonReportPath = process.argv[2];
const formattedResults = parsePlaywrightJson(jsonReportPath);
console.log(`Looking for results in: ${jsonReportPath}`);
console.log(`📄 Found ${formattedResults.length} result(s).`);
// not_found from automation-cases.json (optional)
let notFoundList = [];
try {
const automationCases = JSON.parse(fs.readFileSync(automationCasesPath, 'utf-8'));
const expected = new Set((automationCases || []).map(a => a.automation_id));
const found = new Set(formattedResults.map(r => r.automation_id));
notFoundList = [...expected].filter(id => !found.has(id));
} catch { }
const resultsUrl = baseUrl; // already full endpoint
const payload = { planId, runId, environment: testEnvironment, results: formattedResults, not_found: notFoundList, triggered_by: triggeredBy };
console.log('📤 Posting result payload:', JSON.stringify(payload, null, 2));
console.log(`🔗 Posting to URL: ${resultsUrl}`);
try {
const res = await postJson(resultsUrl, payload);
console.log('✅ Post status:', res.statusCode, res.body);
} catch (e) {
console.error('❌ Failed to post results:', e.message);
}
// Post summary
const summaryUrl = baseUrl.replace('/api/test-results', '/api/test-run-summary');
const summary = { planId, runId, environment: testEnvironment, total: formattedResults.length, passed: formattedResults.filter(r => r.status === 'pass').length };
console.log(`📤 Posting summary to: ${summaryUrl}`);
try {
const res = await postJson(summaryUrl, summary);
console.log('✅ Summary status:', res.statusCode, res.body);
} catch (e) {
console.error('❌ Failed to post summary:', e.message);
}
}
main().catch(e => { console.error(e); process.exit(1); });