reporting-labs 0.6.4 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/template.html +12 -5
- package/dist/template.js +12 -5
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -606,7 +606,7 @@ Your Slack step can then read `results.json` for pass / fail counts and top fail
|
|
|
606
606
|
|
|
607
607
|
## Java teams
|
|
608
608
|
|
|
609
|
-
The same report, from Java: `dev.reportinglabs` on Maven Central, for TestNG and JUnit 5, with zero-code add-ons for Selenium
|
|
609
|
+
The same report, from Java: `dev.reportinglabs` on Maven Central, for TestNG and JUnit 5, with zero-code add-ons for Selenium, REST Assured and Playwright for Java, and a Cucumber JVM plugin (one row per scenario, Given/When/Then as steps). Source: [reporting-labs-java](https://github.com/naveenautomationlabs/reporting-labs-java). Guides: [reportinglabs.dev/get-started/java](https://reportinglabs.dev/get-started/java).
|
|
610
610
|
|
|
611
611
|
## Roadmap
|
|
612
612
|
|
package/dist/template.html
CHANGED
|
@@ -226,6 +226,7 @@ a{color:var(--accent)}
|
|
|
226
226
|
.step .t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
227
227
|
.step .d{font:11px var(--mono);color:var(--ink-3)}
|
|
228
228
|
.step.bad{color:var(--fail)} .step.bad .t{font-weight:500}
|
|
229
|
+
.step.skip .t,.step.skip .kw,.step.skip .d{color:var(--ink-3);font-style:italic}
|
|
229
230
|
.step .e{font:12px var(--mono);color:var(--fail);padding:2px 0 6px 28px;white-space:pre-wrap}
|
|
230
231
|
li.collapsed>ul{display:none}
|
|
231
232
|
.att{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}
|
|
@@ -1404,11 +1405,16 @@ function projects(){
|
|
|
1404
1405
|
/* ---------- main ---------- */
|
|
1405
1406
|
function main(){
|
|
1406
1407
|
const projSel = h('select',{id:'projsel',onchange:e=>{state.project=e.target.value;refresh();}}, h('option',{value:'all'},'All projects'), data.projects.map(p=>h('option',{value:p},p)));
|
|
1408
|
+
// Status filter, the same state the Overview pills, the donut legend and the "f" key drive.
|
|
1409
|
+
const counts = {}; for(const t of data.tests){ const k=isFail(t.outcome)?'failed':t.outcome; counts[k]=(counts[k]||0)+1; }
|
|
1410
|
+
const statusSel = h('select',{id:'statussel','aria-label':'Status',onchange:e=>{state.status=e.target.value;refresh();}},
|
|
1411
|
+
h('option',{value:'all'},'Any status'),
|
|
1412
|
+
[['passed','Passed'],['failed','Failed'],['flaky','Flaky'],['skipped','Skipped']].map(([k,l])=>h('option',{value:k},l+(counts[k]?' ('+counts[k]+')':''))));
|
|
1407
1413
|
return h('div',{class:'main'},
|
|
1408
1414
|
h('aside',{class:'list'},
|
|
1409
1415
|
h('div',{class:'tools'}, h('input',{type:'search',placeholder:'Search tests, tags, files…',oninput:e=>{state.q=e.target.value.toLowerCase();refresh();}}), data.projects.length>1?projSel:null,
|
|
1410
1416
|
h('div',{class:'seg'}, [['file','Spec files'],['folder','Folders'],['flat','Flat']].map(([k,l])=>h('button',{'data-g':k,'aria-pressed':state.group===k,onclick:()=>{state.group=k;refresh();}},l))),
|
|
1411
|
-
|
|
1417
|
+
h('div',{class:'dims'}, statusSel, DIMS.map(d=>h('select',{'data-dim':d,onchange:e=>{state.dims[d]=e.target.value||null;refresh();}}, h('option',{value:''},'Any '+d), dimValues(d).map(v=>h('option',{value:v},v)))))),
|
|
1412
1418
|
h('div',{class:'items',id:'items'}),
|
|
1413
1419
|
h('div',{class:'hint-kbd'}, h('span',{class:'kbd'},'j'),' / ',h('span',{class:'kbd'},'k'),' next / prev · ',h('span',{class:'kbd'},'f'),' failed only · ',h('span',{class:'kbd'},'/'),' search · ',h('span',{class:'kbd'},'1'),'–',h('span',{class:'kbd'},'5'),' switch view')),
|
|
1414
1420
|
h('section',{class:'detail',id:'detail'}));
|
|
@@ -1427,6 +1433,7 @@ function refresh(){
|
|
|
1427
1433
|
document.querySelectorAll('.dim .row').forEach(r=>{ const card=r.closest('.card'); const d=card.querySelector('h2').textContent.replace(/^By /,''); r.setAttribute('aria-pressed', state.dims[d]===r.querySelector('.k').textContent); });
|
|
1428
1434
|
document.querySelectorAll('select[data-dim]').forEach(sel=>{ sel.value=state.dims[sel.dataset.dim]||''; });
|
|
1429
1435
|
const ps=$('#projsel'); if(ps) ps.value=state.project;
|
|
1436
|
+
const ss=$('#statussel'); if(ss) ss.value=state.status;
|
|
1430
1437
|
const vis=visible(), ids=new Set(vis.map(t=>t.id));
|
|
1431
1438
|
document.querySelectorAll('.cell').forEach(c=>c.classList.toggle('dim',!ids.has(c.dataset.id)));
|
|
1432
1439
|
const box=$('#items'); box.innerHTML='';
|
|
@@ -1531,10 +1538,10 @@ function renderDetail(t){
|
|
|
1531
1538
|
}
|
|
1532
1539
|
function stepTree(steps, total){
|
|
1533
1540
|
return h('ul',{class:'steps'}, steps.map(s=>{
|
|
1534
|
-
const bad=!!s.error, kids=s.steps.length>0, pct=total?Math.min(100,s.duration/total*100):0;
|
|
1541
|
+
const bad=!!s.error, skip=s.status==='skipped', kids=s.steps.length>0, pct=total?Math.min(100,s.duration/total*100):0;
|
|
1535
1542
|
const li=h('li',{class:kids&&!hasError(s)?'collapsed':''});
|
|
1536
|
-
const row=h('div',{class:'step'+(bad?' bad':'')},
|
|
1537
|
-
h('span',{class:'tw'}, kids? '▸' : ''), data.bdd?null:h('span',{class:'cat'},s.category), gherkin(s.title), total? h('span',{class:'tb',title:Math.round(pct)+'% of the test'}, h('i',{class:pct>=30?'slow':'',style:'width:'+Math.max(pct,s.duration>0?1.5:0)+'%'})) : null, h('span',{class:'d'},ms(s.duration)));
|
|
1543
|
+
const row=h('div',{class:'step'+(bad?' bad':'')+(skip?' skip':'')},
|
|
1544
|
+
h('span',{class:'tw'}, kids? '▸' : ''), data.bdd?null:h('span',{class:'cat'},s.category), gherkin(s.title), total&&!skip? h('span',{class:'tb',title:Math.round(pct)+'% of the test'}, h('i',{class:pct>=30?'slow':'',style:'width:'+Math.max(pct,s.duration>0?1.5:0)+'%'})) : null, h('span',{class:'d'},skip?'not run':ms(s.duration)));
|
|
1538
1545
|
if(kids){ row.style.cursor='pointer'; row.addEventListener('click',()=>{li.classList.toggle('collapsed'); row.querySelector('.tw').textContent=li.classList.contains('collapsed')?'▸':'▾';}); if(!li.classList.contains('collapsed')) row.querySelector('.tw').textContent='▾'; }
|
|
1539
1546
|
li.append(row); if(bad) li.append(h('div',{class:'e'},s.error)); if(kids) li.append(stepTree(s.steps, total));
|
|
1540
1547
|
return li;
|
|
@@ -1593,7 +1600,7 @@ function bugModel(t){
|
|
|
1593
1600
|
const r=t.results[t.results.length-1], e=r&&r.errors[0], x=e&&e.explain, msg=e?e.message:'';
|
|
1594
1601
|
const ex=msg.match(/^\s*(Expected[^:\n]{0,40}):[ \t]*(.+)$/m), rc=msg.match(/^\s*((?:Received|Actual|But was)[^:\n]{0,40}):[ \t]*(.+)$/m);
|
|
1595
1602
|
const si=sinceInfo(t);
|
|
1596
|
-
const steps=[]; const walk=(list,depth)=>{ for(const st of list){ if(st.category==='hook'||/^Attach "/.test(st.title)||/^Worker Cleanup/.test(st.title)) continue; const user=st.category==='test.step'; if(user||depth===0) steps.push({title:st.title.replace(/^(Given|When|Then|And|But)\s+/,m=>m), failed:!!st.error, user}); if(user&&st.steps.length&&!st.steps.some(c=>c.category==='test.step')) continue; if(st.steps.length) walk(st.steps,depth+1); } };
|
|
1603
|
+
const steps=[]; const walk=(list,depth)=>{ for(const st of list){ if(st.category==='hook'||/^Attach "/.test(st.title)||/^Worker Cleanup/.test(st.title)) continue; const user=st.category==='test.step'; if(user||depth===0) steps.push({title:st.title.replace(/^(Given|When|Then|And|But)\s+/,m=>m)+(st.status==='skipped'?' (not run)':''), failed:!!st.error, user}); if(user&&st.steps.length&&!st.steps.some(c=>c.category==='test.step')) continue; if(st.steps.length) walk(st.steps,depth+1); } };
|
|
1597
1604
|
if(r) walk(r.steps,0);
|
|
1598
1605
|
const userSteps=steps.filter(s=>s.user); const repro=(userSteps.length?userSteps:steps).filter(s=>!/^Expect "/.test(s.title)||s.failed);
|
|
1599
1606
|
const env=[]; if(data.options.project&&data.options.project.name) env.push(['Application', data.options.project.name+(data.options.project.version?' v'+data.options.project.version:'')]);
|
package/dist/template.js
CHANGED
|
@@ -297,6 +297,7 @@ a{color:var(--accent)}
|
|
|
297
297
|
.step .t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
298
298
|
.step .d{font:11px var(--mono);color:var(--ink-3)}
|
|
299
299
|
.step.bad{color:var(--fail)} .step.bad .t{font-weight:500}
|
|
300
|
+
.step.skip .t,.step.skip .kw,.step.skip .d{color:var(--ink-3);font-style:italic}
|
|
300
301
|
.step .e{font:12px var(--mono);color:var(--fail);padding:2px 0 6px 28px;white-space:pre-wrap}
|
|
301
302
|
li.collapsed>ul{display:none}
|
|
302
303
|
.att{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}
|
|
@@ -1470,11 +1471,16 @@ function projects(){
|
|
|
1470
1471
|
/* ---------- main ---------- */
|
|
1471
1472
|
function main(){
|
|
1472
1473
|
const projSel = h('select',{id:'projsel',onchange:e=>{state.project=e.target.value;refresh();}}, h('option',{value:'all'},'All projects'), data.projects.map(p=>h('option',{value:p},p)));
|
|
1474
|
+
// Status filter, the same state the Overview pills, the donut legend and the "f" key drive.
|
|
1475
|
+
const counts = {}; for(const t of data.tests){ const k=isFail(t.outcome)?'failed':t.outcome; counts[k]=(counts[k]||0)+1; }
|
|
1476
|
+
const statusSel = h('select',{id:'statussel','aria-label':'Status',onchange:e=>{state.status=e.target.value;refresh();}},
|
|
1477
|
+
h('option',{value:'all'},'Any status'),
|
|
1478
|
+
[['passed','Passed'],['failed','Failed'],['flaky','Flaky'],['skipped','Skipped']].map(([k,l])=>h('option',{value:k},l+(counts[k]?' ('+counts[k]+')':''))));
|
|
1473
1479
|
return h('div',{class:'main'},
|
|
1474
1480
|
h('aside',{class:'list'},
|
|
1475
1481
|
h('div',{class:'tools'}, h('input',{type:'search',placeholder:'Search tests, tags, files…',oninput:e=>{state.q=e.target.value.toLowerCase();refresh();}}), data.projects.length>1?projSel:null,
|
|
1476
1482
|
h('div',{class:'seg'}, [['file','Spec files'],['folder','Folders'],['flat','Flat']].map(([k,l])=>h('button',{'data-g':k,'aria-pressed':state.group===k,onclick:()=>{state.group=k;refresh();}},l))),
|
|
1477
|
-
|
|
1483
|
+
h('div',{class:'dims'}, statusSel, DIMS.map(d=>h('select',{'data-dim':d,onchange:e=>{state.dims[d]=e.target.value||null;refresh();}}, h('option',{value:''},'Any '+d), dimValues(d).map(v=>h('option',{value:v},v)))))),
|
|
1478
1484
|
h('div',{class:'items',id:'items'}),
|
|
1479
1485
|
h('div',{class:'hint-kbd'}, h('span',{class:'kbd'},'j'),' / ',h('span',{class:'kbd'},'k'),' next / prev · ',h('span',{class:'kbd'},'f'),' failed only · ',h('span',{class:'kbd'},'/'),' search · ',h('span',{class:'kbd'},'1'),'–',h('span',{class:'kbd'},'5'),' switch view')),
|
|
1480
1486
|
h('section',{class:'detail',id:'detail'}));
|
|
@@ -1493,6 +1499,7 @@ function refresh(){
|
|
|
1493
1499
|
document.querySelectorAll('.dim .row').forEach(r=>{ const card=r.closest('.card'); const d=card.querySelector('h2').textContent.replace(/^By /,''); r.setAttribute('aria-pressed', state.dims[d]===r.querySelector('.k').textContent); });
|
|
1494
1500
|
document.querySelectorAll('select[data-dim]').forEach(sel=>{ sel.value=state.dims[sel.dataset.dim]||''; });
|
|
1495
1501
|
const ps=$('#projsel'); if(ps) ps.value=state.project;
|
|
1502
|
+
const ss=$('#statussel'); if(ss) ss.value=state.status;
|
|
1496
1503
|
const vis=visible(), ids=new Set(vis.map(t=>t.id));
|
|
1497
1504
|
document.querySelectorAll('.cell').forEach(c=>c.classList.toggle('dim',!ids.has(c.dataset.id)));
|
|
1498
1505
|
const box=$('#items'); box.innerHTML='';
|
|
@@ -1597,10 +1604,10 @@ function renderDetail(t){
|
|
|
1597
1604
|
}
|
|
1598
1605
|
function stepTree(steps, total){
|
|
1599
1606
|
return h('ul',{class:'steps'}, steps.map(s=>{
|
|
1600
|
-
const bad=!!s.error, kids=s.steps.length>0, pct=total?Math.min(100,s.duration/total*100):0;
|
|
1607
|
+
const bad=!!s.error, skip=s.status==='skipped', kids=s.steps.length>0, pct=total?Math.min(100,s.duration/total*100):0;
|
|
1601
1608
|
const li=h('li',{class:kids&&!hasError(s)?'collapsed':''});
|
|
1602
|
-
const row=h('div',{class:'step'+(bad?' bad':'')},
|
|
1603
|
-
h('span',{class:'tw'}, kids? '▸' : ''), data.bdd?null:h('span',{class:'cat'},s.category), gherkin(s.title), total? h('span',{class:'tb',title:Math.round(pct)+'% of the test'}, h('i',{class:pct>=30?'slow':'',style:'width:'+Math.max(pct,s.duration>0?1.5:0)+'%'})) : null, h('span',{class:'d'},ms(s.duration)));
|
|
1609
|
+
const row=h('div',{class:'step'+(bad?' bad':'')+(skip?' skip':'')},
|
|
1610
|
+
h('span',{class:'tw'}, kids? '▸' : ''), data.bdd?null:h('span',{class:'cat'},s.category), gherkin(s.title), total&&!skip? h('span',{class:'tb',title:Math.round(pct)+'% of the test'}, h('i',{class:pct>=30?'slow':'',style:'width:'+Math.max(pct,s.duration>0?1.5:0)+'%'})) : null, h('span',{class:'d'},skip?'not run':ms(s.duration)));
|
|
1604
1611
|
if(kids){ row.style.cursor='pointer'; row.addEventListener('click',()=>{li.classList.toggle('collapsed'); row.querySelector('.tw').textContent=li.classList.contains('collapsed')?'▸':'▾';}); if(!li.classList.contains('collapsed')) row.querySelector('.tw').textContent='▾'; }
|
|
1605
1612
|
li.append(row); if(bad) li.append(h('div',{class:'e'},s.error)); if(kids) li.append(stepTree(s.steps, total));
|
|
1606
1613
|
return li;
|
|
@@ -1659,7 +1666,7 @@ function bugModel(t){
|
|
|
1659
1666
|
const r=t.results[t.results.length-1], e=r&&r.errors[0], x=e&&e.explain, msg=e?e.message:'';
|
|
1660
1667
|
const ex=msg.match(/^\s*(Expected[^:\n]{0,40}):[ \t]*(.+)$/m), rc=msg.match(/^\s*((?:Received|Actual|But was)[^:\n]{0,40}):[ \t]*(.+)$/m);
|
|
1661
1668
|
const si=sinceInfo(t);
|
|
1662
|
-
const steps=[]; const walk=(list,depth)=>{ for(const st of list){ if(st.category==='hook'||/^Attach "/.test(st.title)||/^Worker Cleanup/.test(st.title)) continue; const user=st.category==='test.step'; if(user||depth===0) steps.push({title:st.title.replace(/^(Given|When|Then|And|But)\s+/,m=>m), failed:!!st.error, user}); if(user&&st.steps.length&&!st.steps.some(c=>c.category==='test.step')) continue; if(st.steps.length) walk(st.steps,depth+1); } };
|
|
1669
|
+
const steps=[]; const walk=(list,depth)=>{ for(const st of list){ if(st.category==='hook'||/^Attach "/.test(st.title)||/^Worker Cleanup/.test(st.title)) continue; const user=st.category==='test.step'; if(user||depth===0) steps.push({title:st.title.replace(/^(Given|When|Then|And|But)\s+/,m=>m)+(st.status==='skipped'?' (not run)':''), failed:!!st.error, user}); if(user&&st.steps.length&&!st.steps.some(c=>c.category==='test.step')) continue; if(st.steps.length) walk(st.steps,depth+1); } };
|
|
1663
1670
|
if(r) walk(r.steps,0);
|
|
1664
1671
|
const userSteps=steps.filter(s=>s.user); const repro=(userSteps.length?userSteps:steps).filter(s=>!/^Expect "/.test(s.title)||s.failed);
|
|
1665
1672
|
const env=[]; if(data.options.project&&data.options.project.name) env.push(['Application', data.options.project.name+(data.options.project.version?' v'+data.options.project.version:'')]);
|
package/dist/types.d.ts
CHANGED
|
@@ -196,6 +196,8 @@ export interface StepData {
|
|
|
196
196
|
category: string;
|
|
197
197
|
duration: number;
|
|
198
198
|
error?: string;
|
|
199
|
+
/** 'skipped' when the runner never executed it (a Cucumber step after a failed one) */
|
|
200
|
+
status?: 'skipped';
|
|
199
201
|
steps: StepData[];
|
|
200
202
|
}
|
|
201
203
|
export interface AttachmentData {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reporting-labs",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.6",
|
|
4
4
|
"description": "reportingLabs – beautiful, customizable single-file HTML test reports. One line of config. Playwright adapter included, more runners on the way.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"test-report",
|