@currents/node-test-reporter 1.1.0 → 2.0.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.0](https://github.com/currents-dev/currents-reporter/compare/%40currents%2Fnode-test-reporter-v1.1.0...%40currents%2Fnode-test-reporter-v2.0.0) (2026-11-05)
4
+
5
+ The reporter requires Node.js 22.13 or later. On an older Node.js, `node --test` fails to load the reporter with a message that says to upgrade Node.js or to use `@currents/node-test-reporter@1`. It uses xmlbuilder2 4, which writes the same JUnit XML as before and no longer installs js-yaml 3, so `npm audit` reports no findings for the reporter.
6
+
7
+ ### ⚠ BREAKING CHANGES
8
+
9
+ * @currents/node-test-reporter requires Node.js 22.13 or later. Upgrade Node.js, or stay on @currents/node-test-reporter 1.x.
10
+
11
+ ### Features
12
+
13
+ * require Node.js 22.13 or later ([#477](https://github.com/currents-dev/currents-reporter/issues/477)) ([ea0c07a](https://github.com/currents-dev/currents-reporter/commit/ea0c07acfe4d930996093a53991eea9dff8414b9))
14
+
15
+ ### Bug Fixes
16
+
17
+ * update xmlbuilder2 to 4.0.3 ([#393](https://github.com/currents-dev/currents-reporter/issues/393)) ([d9d645a](https://github.com/currents-dev/currents-reporter/commit/d9d645a83267d9474d394699c94d6226f6e45cc9))
18
+
3
19
  # 1.1.0 (2025-04-16)
4
20
 
5
21
 
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  This reporter generates a JUnit XML file compatible with the Currents API. It ensures the output contains sufficient information for seamless conversion into the Currents format, enabling smooth integration and reporting to the Currents API.
4
4
 
5
+ Requires Node.js 22.13 or later.
6
+
5
7
  ## Nesting Approach
6
8
 
7
9
  The Node.js test runner operates based on test events. Each event provides the necessary data to reconstruct the test structure but does not explicitly differentiate between a test and a suite.
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import v from"debug";var c=v("currents");import{hostname as M}from"os";import{create as x}from"xmlbuilder2";var f=c.extend("lib"),E=M();function h(t){return{name:t,timestamp:new Date().toISOString(),children:[],hostname:E,stats:{failures:0,skipped:0,time:0}}}function b(t){f("Creating JUnit XML");let s=x({version:"1.0",encoding:"UTF-8"}).ele("testsuites",{name:"root",...t.summary?k(t.summary):{}});return Object.values(t.testFiles).forEach(e=>{f("Creating test suite element for file",e.name),A({file:e,summary:t.fileSummaries[e.name],parentElement:s})}),f("Ending XML document"),s.end({prettyPrint:!0})}function p(t){return Number((t/1e3).toFixed(6))}function F(t,s){for(let e of t){f("Flattening test",e.name,e.status);let m=e.status==="skipped"||e.status==="todo",r=e.isSuite&&m,n=!e.isSuite;if(r)s.ele("testcase",{name:e.name,time:e.time,testNumber:e.testNumber}).ele("skipped",S(e));else if(n){let l=s.ele("testcase",{name:e.name,time:e.time});if(e.status==="failed"){let u=`${e.failure?.message}
2
- ${N(e.failure?.stack)}`,i=l.ele("failure",{type:e.failure?.name,message:u});typeof e.failure?.stack=="object"?i.dat(N(e.failure.stack)):i.txt(e.failure?.stack)}else m&&l.ele("skipped",S(e))}e.children?.length&&F(e.children,s)}}function S(t){return{type:t.status==="todo"?"todo":void 0}}function A({file:t,summary:s,parentElement:e}){let m=s?k(s):{},r="time"in m?m.time:t.stats.time,n=e.ele("testsuite",{name:L(t.name),timestamp:t.timestamp,hostname:t.hostname,...m,...t.stats,time:r});F(t.children,n)}function k(t){return{success:t.success,time:p(t.duration_ms||0)}}function N(t){return t?`${JSON.stringify(t,null,2)}
3
- `:""}function L(t){return t.replace(process.cwd(),"").replace(/"/g,"&quot;").replace(/^\//,"")}async function*g(t){let s={summary:null,fileSummaries:{},testFiles:{}},e=[];for await(let m of t){let{type:r,data:n}=m;if(r==="test:summary"){let o=n?.file;o?s.fileSummaries[o]=n:s.summary=n,c("Summary event received",m.data);continue}if(!n||typeof n.nesting!="number")continue;let{name:l,nesting:u,file:i}=n;if(!i||!l)continue;let d=l.replace(/"/g,"&quot;");if(!["test:start","test:pass","test:fail"].includes(r))continue;for(s.testFiles[i]||(s.testFiles[i]=h(i),c("Test file entry created",i,s.testFiles[i]));e.length<=u;)e.push({}),c("Nested test stack expanded to accommodate nesting level",i,d);let y=e[u-1]||s.testFiles[i];if(c('Parent node for nesting level %d - "%s"',u,y.name),r==="test:start"){let o=u===0?d:`${e[u-1].name} > ${d}`;c('Creating test node for "%s"',o);let T={name:o,status:"pending",children:[]};y.children.push(T),e[u]=T;continue}let a=e[u];if(!a||!a.name.endsWith(d)){console.warn(`Warning: Test node not found for event type "${r}" with name "${l}".`);continue}if(a.time=n.details?.duration_ms?p(n.details.duration_ms):void 0,s.testFiles[i].stats.time+=a.time||0,a.isSuite=n.details?.type==="suite",a.testNumber=n.testNumber,a.status=r==="test:pass"?"passed":"failed",n.skip&&(s.testFiles[i].stats.skipped+=1,a.status="skipped"),n.todo&&(s.testFiles[i].stats.skipped+=1,a.status="todo"),r==="test:fail"){s.testFiles[i].stats.failures+=1;let o=n.details?.error;a.failure={name:o?.failureType||o?.code,message:o?.message,stack:o}}}c("Final state:",s),yield b(s)}var P=g;export{P as default};
1
+ var l={name:"@currents/node-test-reporter",version:"2.0.0",main:"dist/index.js",author:{name:"Currents Software Inc",email:"hello@currents.dev"},type:"module",license:"MIT",repository:{type:"git",url:"https://github.com/currents-dev/currents-reporter"},description:"Currents reporter for Node Test",scripts:{test:"vitest --run --passWithNoTests",rm:"rimraf dist",types:"tsc --noEmit",build:"tsup-node --minify --dts",dev:"tsup-node --watch --dts",release:"release-it","publish:npm":"npm run rm && npm run build && ./publish.js"},engines:{node:">=22.13"},files:["dist","!**/*.map","!**/*/*.map","LICENSE.md","README.md","CHANGELOG.md","AUTHORS"],keywords:["node","node test","node dashboard","cloud dashboard","reporter","currents","tests reporter","ci"],dependencies:{debug:"^4.4.0",xmlbuilder2:"^4.0.3"},devDependencies:{"@release-it/conventional-changelog":"^12.0.0",commander:"^13.1.0","release-it":"^21.0.2",rimraf:"^6.0.1",tsup:"^8.4.0",vitest:"^4.1.11"},"release-it":{npm:{publish:!1},github:{release:!0,releaseName:"${npm.name} v${version}"},plugins:{"@release-it/conventional-changelog":{preset:{name:"conventionalcommits"},header:"# Changelog",ignoreVersion:!0,infile:"./CHANGELOG.md",gitRawCommitsOpts:{path:"."},commitsOpts:{path:"."}}},git:{commitMessage:"chore: release ${npm.name} v${version}",tagName:"@currents/node-test-reporter-v${version}"},hooks:{"after:bump":"node ../../scripts/set-lockfile-version.js ${version}"}}};function N(t=process.versions.node){let[s,e=0]=g(l.engines.node.replace(">=","")),[i,o]=g(t);if(i>s||i===s&&o>=e)return;let n=g(l.version)[0]-1;throw new Error(`${l.name} requires Node.js ${s}.${e} or later. This is Node.js ${t}. Upgrade Node.js, or use ${l.name}@${n} with older Node.js versions.`)}function g(t){return t.replace(/^v/,"").split(".").map(Number)}N();import w from"debug";var d=w("currents");import{hostname as x}from"os";import{create as j}from"xmlbuilder2";var f=d.extend("lib"),A=x();function k(t){return{name:t,timestamp:new Date().toISOString(),children:[],hostname:A,stats:{failures:0,skipped:0,time:0}}}function F(t){f("Creating JUnit XML");let s=j({version:"1.0",encoding:"UTF-8"}).ele("testsuites",{name:"root",...t.summary?E(t.summary):{}});return Object.values(t.testFiles).forEach(e=>{f("Creating test suite element for file",e.name),C({file:e,summary:t.fileSummaries[e.name],parentElement:s})}),f("Ending XML document"),s.end({prettyPrint:!0})}function h(t){return Number((t/1e3).toFixed(6))}function $(t,s){for(let e of t){f("Flattening test",e.name,e.status);let i=e.status==="skipped"||e.status==="todo",o=e.isSuite&&i,n=!e.isSuite;if(o)s.ele("testcase",{name:e.name,time:e.time,testNumber:e.testNumber}).ele("skipped",b(e));else if(n){let c=s.ele("testcase",{name:e.name,time:e.time});if(e.status==="failed"){let u=`${e.failure?.message}
2
+ ${S(e.failure?.stack)}`,r=c.ele("failure",{type:e.failure?.name,message:u});typeof e.failure?.stack=="object"?r.dat(S(e.failure.stack)):r.txt(e.failure?.stack)}else i&&c.ele("skipped",b(e))}e.children?.length&&$(e.children,s)}}function b(t){return{type:t.status==="todo"?"todo":void 0}}function C({file:t,summary:s,parentElement:e}){let i=s?E(s):{},o="time"in i?i.time:t.stats.time,n=e.ele("testsuite",{name:L(t.name),timestamp:t.timestamp,hostname:t.hostname,...i,...t.stats,time:o});$(t.children,n)}function E(t){return{success:t.success,time:h(t.duration_ms||0)}}function S(t){return t?`${JSON.stringify(t,null,2)}
3
+ `:""}function L(t){return t.replace(process.cwd(),"").replace(/"/g,"&quot;").replace(/^\//,"")}async function*y(t){let s={summary:null,fileSummaries:{},testFiles:{}},e=[];for await(let i of t){let{type:o,data:n}=i;if(o==="test:summary"){let m=n?.file;m?s.fileSummaries[m]=n:s.summary=n,d("Summary event received",i.data);continue}if(!n||typeof n.nesting!="number")continue;let{name:c,nesting:u,file:r}=n;if(!r||!c)continue;let p=c.replace(/"/g,"&quot;");if(!["test:start","test:pass","test:fail"].includes(o))continue;for(s.testFiles[r]||(s.testFiles[r]=k(r),d("Test file entry created",r,s.testFiles[r]));e.length<=u;)e.push({}),d("Nested test stack expanded to accommodate nesting level",r,p);let T=e[u-1]||s.testFiles[r];if(d('Parent node for nesting level %d - "%s"',u,T.name),o==="test:start"){let m=u===0?p:`${e[u-1].name} > ${p}`;d('Creating test node for "%s"',m);let v={name:m,status:"pending",children:[]};T.children.push(v),e[u]=v;continue}let a=e[u];if(!a||!a.name.endsWith(p)){console.warn(`Warning: Test node not found for event type "${o}" with name "${c}".`);continue}if(a.time=n.details?.duration_ms?h(n.details.duration_ms):void 0,s.testFiles[r].stats.time+=a.time||0,a.isSuite=n.details?.type==="suite",a.testNumber=n.testNumber,a.status=o==="test:pass"?"passed":"failed",n.skip&&(s.testFiles[r].stats.skipped+=1,a.status="skipped"),n.todo&&(s.testFiles[r].stats.skipped+=1,a.status="todo"),o==="test:fail"){s.testFiles[r].stats.failures+=1;let m=n.details?.error;a.failure={name:m?.failureType||m?.code,message:m?.message,stack:m}}}d("Final state:",s),yield F(s)}var z=y;export{z as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@currents/node-test-reporter",
3
- "version": "1.1.0",
3
+ "version": "2.0.0",
4
4
  "main": "dist/index.js",
5
5
  "author": {
6
6
  "name": "Currents Software Inc",
@@ -8,6 +8,10 @@
8
8
  },
9
9
  "type": "module",
10
10
  "license": "MIT",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/currents-dev/currents-reporter"
14
+ },
11
15
  "description": "Currents reporter for Node Test",
12
16
  "scripts": {
13
17
  "test": "vitest --run --passWithNoTests",
@@ -19,7 +23,7 @@
19
23
  "publish:npm": "npm run rm && npm run build && ./publish.js"
20
24
  },
21
25
  "engines": {
22
- "node": ">=18.20.4"
26
+ "node": ">=22.13"
23
27
  },
24
28
  "files": [
25
29
  "dist",
@@ -42,14 +46,15 @@
42
46
  ],
43
47
  "dependencies": {
44
48
  "debug": "^4.4.0",
45
- "xmlbuilder2": "^3.1.1"
49
+ "xmlbuilder2": "^4.0.3"
46
50
  },
47
51
  "devDependencies": {
48
- "@release-it/conventional-changelog": "^10.0.0",
52
+ "@release-it/conventional-changelog": "^12.0.0",
49
53
  "commander": "^13.1.0",
54
+ "release-it": "^21.0.2",
50
55
  "rimraf": "^6.0.1",
51
56
  "tsup": "^8.4.0",
52
- "vitest": "^3.0.8"
57
+ "vitest": "^4.1.11"
53
58
  },
54
59
  "release-it": {
55
60
  "npm": {
@@ -61,15 +66,26 @@
61
66
  },
62
67
  "plugins": {
63
68
  "@release-it/conventional-changelog": {
64
- "preset": "angular",
69
+ "preset": {
70
+ "name": "conventionalcommits"
71
+ },
65
72
  "header": "# Changelog",
66
73
  "ignoreVersion": true,
67
- "infile": "./CHANGELOG.md"
74
+ "infile": "./CHANGELOG.md",
75
+ "gitRawCommitsOpts": {
76
+ "path": "."
77
+ },
78
+ "commitsOpts": {
79
+ "path": "."
80
+ }
68
81
  }
69
82
  },
70
83
  "git": {
71
84
  "commitMessage": "chore: release ${npm.name} v${version}",
72
- "tagName": "${npm.name}-v${version}"
85
+ "tagName": "@currents/node-test-reporter-v${version}"
86
+ },
87
+ "hooks": {
88
+ "after:bump": "node ../../scripts/set-lockfile-version.js ${version}"
73
89
  }
74
90
  }
75
91
  }