async function init() { const params = new URLSearchParams(window.location.search); const idA = params.get('test1'); const idB = params.get('test2'); if (!idA || !idB) { document.getElementById('loading').textContent = 'Error: Missing test IDs.'; return; } try { const [resA, resB] = await Promise.all([ fetch(`/reports/${idA}.json`).then(r => r.json()), fetch(`/reports/${idB}.json`).then(r => r.json()) ]); renderComparison(resA, resB); } catch (err) { console.error(err); document.getElementById('loading').textContent = 'Error loading test results.'; } } function renderComparison(a, b) { document.getElementById('loading').style.display = 'none'; document.getElementById('comparison-content').style.display = 'block'; // Render Headers renderHeader('a', a); renderHeader('b', b); // Render Metrics Table const metrics = [ { key: 'performance', label: 'Performance Score', path: 'scores.performance', isScore: true }, { key: 'lcp', label: 'LCP (ms)', path: 'metrics.lcp' }, { key: 'tbt', label: 'TBT (ms)', path: 'metrics.tbt' }, { key: 'cls', label: 'CLS', path: 'metrics.cls', isDecimal: true }, { key: 'accessibility', label: 'Accessibility', path: 'scores.accessibility', isScore: true }, { key: 'seo', label: 'SEO', path: 'scores.seo', isScore: true } ]; const tbody = document.getElementById('metrics-body'); tbody.innerHTML = metrics.map(m => renderMetricRow(m, a, b)).join(''); // Render Filmstrips renderFilmstrip('a', a.filmstrip); renderFilmstrip('b', b.filmstrip); } function getVal(obj, path) { return path.split('.').reduce((o, i) => o?.[i], obj); } function renderHeader(col, data) { document.getElementById(`title-${col}`).innerHTML = ` ${data.url}
${new Date(data.timestamp).toLocaleString()} `; // Grade const score = data.scores.performance; const grade = score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : 'D'; const el = document.getElementById(`grade-${col}`); el.className = `grade-circle grade-${grade.toLowerCase()}`; el.querySelector('.grade-letter').textContent = grade; } function renderMetricRow(m, a, b) { const valA = getVal(a, m.path) || 0; const valB = getVal(b, m.path) || 0; const diff = valB - valA; let diffStr = ''; let diffClass = 'diff-neutral'; // Logic: Higher is better for Scores, Lower is better for Metrics (LCP, TBT, CLS) const higherIsBetter = m.isScore; if (diff !== 0) { const isBetter = higherIsBetter ? diff > 0 : diff < 0; diffClass = isBetter ? 'diff-better' : 'diff-worse'; const prefix = diff > 0 ? '+' : ''; diffStr = `${prefix}${m.isDecimal ? diff.toFixed(2) : Math.round(diff)}`; } return ` ${m.label} ${m.isDecimal ? valA.toFixed(2) : Math.round(valA)} ${m.isDecimal ? valB.toFixed(2) : Math.round(valB)} ${diffStr} `; } function renderFilmstrip(col, frames) { const el = document.getElementById(`filmstrip-${col}`); if (!frames || frames.length === 0) { el.innerHTML = 'No filmstrip data'; return; } el.innerHTML = frames.map(f => ``).join(''); } document.addEventListener('DOMContentLoaded', init);