Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions tests/lib/reporting/aggregate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,22 @@ export function sumCounts(sequences) {
}

/** Build the full report object the reporters consume. Pure; timestamps passed in. */
/**
* Stable hierarchical reference IDs so a reviewer can cite a specific check
* (e.g. "3.5 looks wrong"). Each sequence gets a section number; each case gets
* `<section>.<n>`. Pre-set refs (e.g. a deeper source.dimension.check from the
* live runner) are preserved.
*/
export function assignRefs(sequences) {
sequences.forEach((seq, i) => {
seq.ref = seq.ref || String(i + 1);
(seq.cases || []).forEach((c, j) => { c.ref = c.ref || `${seq.ref}.${j + 1}`; });
});
return sequences;
}

export function buildReport({ sequences = [], startedAt, finishedAt, target = '', env = {} } = {}) {
assignRefs(sequences);
const { totals, byStatus } = sumCounts(sequences);
return {
schema: 'graphdone.unified-report/1',
Expand Down
11 changes: 11 additions & 0 deletions tests/lib/reporting/aggregate.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ test('sumCounts totals + status tally', () => {
assert.equal(byStatus.failed, 1);
});

test('buildReport assigns hierarchical refs (section + section.case), preserving presets', () => {
const r = buildReport({ sequences: [
{ title: 'A', status: 'passed', counts: { passed: 2 }, cases: [{ title: 'x', status: 'passed' }, { title: 'y', status: 'passed' }] },
{ ref: '2.4', title: 'B', status: 'warn', counts: { warned: 1 }, cases: [{ ref: '2.4.1', title: 'z', status: 'warn' }] },
] });
assert.equal(r.sequences[0].ref, '1');
assert.deepEqual(r.sequences[0].cases.map((c) => c.ref), ['1.1', '1.2']);
assert.equal(r.sequences[1].ref, '2.4'); // preset section ref preserved
assert.equal(r.sequences[1].cases[0].ref, '2.4.1'); // preset case ref preserved
});

test('buildReport rolls up status + duration', () => {
const r = buildReport({
sequences: [{ status: 'passed', counts: { passed: 2 } }, { status: 'warn', counts: { warned: 1 } }],
Expand Down
4 changes: 4 additions & 0 deletions tests/lib/reporting/html.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function caseHtml(c) {
const err = c.error ? `<pre class="err">${esc(c.error)}</pre>` : '';
return `<div class="case ${esc(c.status)}">
<span class="dot" style="background:${COLOR[c.status] || '#888'}"></span>
${c.ref ? `<code class="ref" title="cite this check">${esc(c.ref)}</code>` : ''}
<span class="ctitle">${esc(c.title)}</span>
${c.durationMs != null ? `<span class="cdur">${(c.durationMs / 1000).toFixed(1)}s</span>` : ''}
${err}${atts ? `<div class="atts">${atts}</div>` : ''}
Expand All @@ -37,6 +38,7 @@ function seqHtml(seq, i) {
return `<details class="seq ${esc(seq.status)}" ${seq.status === 'failed' ? 'open' : ''}>
<summary>
<span class="badge" style="background:${COLOR[seq.status] || '#888'}">${ICON[seq.status] || ''} ${esc(seq.status)}</span>
${seq.ref ? `<code class="sref" title="section ref">§${esc(seq.ref)}</code>` : ''}
<span class="sname">${esc(seq.title || seq.id)}</span>
<span class="counts">${c.passed || 0}✓ ${c.failed || 0}✗ ${c.warned || 0}⚠ ${c.skipped || 0}⏭</span>
${seq.durationMs != null ? `<span class="sdur">${(seq.durationMs / 1000).toFixed(1)}s</span>` : ''}
Expand Down Expand Up @@ -70,6 +72,8 @@ h1{font-size:22px;margin:0 0 4px;display:flex;align-items:center;gap:10px}
.seq summary{display:flex;align-items:center;gap:12px;cursor:pointer;list-style:none;padding:8px 0}
.seq summary::-webkit-details-marker{display:none}
.badge{padding:2px 10px;border-radius:999px;font-size:11px;font-weight:700;color:#0b1220;text-transform:uppercase}
.sref{background:#1e293b;color:#7dd3fc;border:1px solid #334155;border-radius:5px;padding:1px 7px;font-size:12px;font-weight:700;font-variant-numeric:tabular-nums}
.ref{background:#0b1220;color:#fbbf24;border:1px solid #334155;border-radius:5px;padding:0 6px;font-size:11px;font-weight:700;margin-right:8px;font-variant-numeric:tabular-nums;user-select:all}
.sname{font-weight:600;flex:1}
.counts{font-variant-numeric:tabular-nums;color:#cbd5e1;font-size:12px}
.sdur,.cdur{color:#64748b;font-size:12px}
Expand Down
Loading