@testream/vitest-reporter 1.2.1 → 1.2.3

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 CHANGED
@@ -1,8 +1,17 @@
1
- # @testream/vitest-reporter
1
+ # @testream/vitest-reporter: Vitest test reporting for Jira
2
2
 
3
- Bridges Vitest test runs from your codebase into Jira with Testream. Once configured, it uploads results automatically.
3
+ `@testream/vitest-reporter` publishes fast Vitest unit and frontend test results from CI/CD to Testream as durable, Jira-visible evidence. Vitest remains the execution source, so teams do not need to recreate every automated test as a manual Jira case.
4
4
 
5
- ## Quick Start
5
+ ## What the reporter sends to Testream and Jira
6
+
7
+ - Passed, failed, skipped, and pending Vitest results
8
+ - Failure messages, stack traces, source locations, and bounded snippets
9
+ - Branch, commit, build, environment, and CI metadata
10
+ - Suite changes and trends for Jira work and release reviews
11
+
12
+ It fits Vite-based React, Vue, Angular, and other JavaScript or TypeScript projects that need automated test reporting connected to Jira.
13
+
14
+ ## Install and configure
6
15
 
7
16
  ```bash
8
17
  npm install --save-dev @testream/vitest-reporter
@@ -25,8 +34,24 @@ export default defineConfig({
25
34
  })
26
35
  ```
27
36
 
28
- The reporter enables Vitest `includeTaskLocation` automatically so generated
29
- CTRF reports include `line` metadata and shared snippet enrichment can populate
30
- `snippet` for JS/TS tests.
37
+ The reporter enables Vitest `includeTaskLocation` automatically so generated CTRF reports include line metadata and shared snippet enrichment can populate source evidence for JavaScript and TypeScript tests.
38
+
39
+ ## Vitest evidence in CI/CD
40
+
41
+ Keep your normal Vitest command and store `TESTREAM_API_KEY` as a protected secret. The reporter publishes the completed run from GitHub Actions, GitLab CI/CD, Azure Pipelines, Jenkins, or another command-based CI provider. Testream then connects the results to Jira work and release context.
42
+
43
+ ## Frequently asked questions
44
+
45
+ ### Do we need to recreate automated tests as manual Jira cases?
46
+
47
+ No. Your Vitest suite remains the code-first execution source. Testream makes the results inspectable in Jira without introducing duplicate manual cases.
48
+
49
+ ### Does it work outside React projects?
50
+
51
+ Yes. The reporter works with Vitest itself, including Vue, Angular, Vite, and other projects that use Vitest for unit or frontend testing.
52
+
53
+ ## Official Testream resources
31
54
 
32
- Need more configuration options? See the full guide at https://docs.testream.app/reporters/vitest.
55
+ - [Vitest Jira integration](https://testream.app/vitest-jira-integration)
56
+ - [Complete Vitest reporter setup guide](https://docs.testream.app/reporters/vitest)
57
+ - [Install Testream – Automated Test Management for Jira](https://marketplace.atlassian.com/3048460704)
@@ -1,4 +1,4 @@
1
- var ue=Object.create;var j=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var de=Object.getPrototypeOf,pe=Object.prototype.hasOwnProperty;var _=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,r)=>(typeof require<"u"?require:t)[r]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var R=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var fe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of le(t))!pe.call(e,i)&&i!==r&&j(e,i,{get:()=>t[i],enumerable:!(n=ce(t,i))||n.enumerable});return e};var V=(e,t,r)=>(r=e!=null?ue(de(e)):{},fe(t||!e||!e.__esModule?j(r,"default",{value:e,enumerable:!0}):r,e));var G=R(K=>{"use strict";Object.defineProperty(K,"__esModule",{value:!0})});var M=R(A=>{"use strict";Object.defineProperty(A,"__esModule",{value:!0});A.detectCIContext=Ee;function P(e,t){if(e)return e.startsWith(t)?e.slice(t.length):e}function he(){return globalThis.process?.env??{}}function me(e){if(!(!e.GITHUB_SERVER_URL||!e.GITHUB_REPOSITORY))return`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}`}function Te(e){if(!(!e.GITHUB_SERVER_URL||!e.GITHUB_REPOSITORY||!e.GITHUB_RUN_ID))return`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}/actions/runs/${e.GITHUB_RUN_ID}`}function ge(e){if(e.GITHUB_HEAD_REF)return e.GITHUB_HEAD_REF;if(e.GITHUB_REF?.startsWith("refs/heads/"))return e.GITHUB_REF_NAME??P(e.GITHUB_REF,"refs/heads/")}function Re(e){return{branch:ge(e),commitSha:e.GITHUB_SHA,repositoryUrl:me(e),buildNumber:e.GITHUB_RUN_NUMBER,buildUrl:Te(e)}}function be(e){return{branch:e.CI_COMMIT_BRANCH||e.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME,commitSha:e.CI_COMMIT_SHA,repositoryUrl:e.CI_PROJECT_URL,buildNumber:e.CI_PIPELINE_IID,buildUrl:e.CI_PIPELINE_URL}}function ye(e){return{branch:P(e.BUILD_SOURCEBRANCH,"refs/heads/"),commitSha:e.BUILD_SOURCEVERSION,repositoryUrl:e.BUILD_REPOSITORY_URI,buildNumber:e.BUILD_BUILDNUMBER,buildUrl:e.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI&&e.SYSTEM_TEAMPROJECT&&e.BUILD_BUILDID?`${e.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI}${e.SYSTEM_TEAMPROJECT}/_build/results?buildId=${e.BUILD_BUILDID}`:void 0}}function Ie(e){return{branch:e.CIRCLE_BRANCH,commitSha:e.CIRCLE_SHA1,repositoryUrl:e.CIRCLE_REPOSITORY_URL,buildNumber:e.CIRCLE_BUILD_NUM,buildUrl:e.CIRCLE_BUILD_URL}}function Ce(e){return{branch:P(e.GIT_BRANCH,"origin/"),commitSha:e.GIT_COMMIT,repositoryUrl:e.GIT_URL,buildNumber:e.BUILD_NUMBER,buildUrl:e.BUILD_URL}}function _e(e){return{branch:e.BITBUCKET_BRANCH,commitSha:e.BITBUCKET_COMMIT,repositoryUrl:e.BITBUCKET_GIT_HTTP_ORIGIN,buildNumber:e.BITBUCKET_BUILD_NUMBER,buildUrl:e.BITBUCKET_REPO_FULL_NAME&&e.BITBUCKET_BUILD_NUMBER?`https://bitbucket.org/${e.BITBUCKET_REPO_FULL_NAME}/pipelines/results/${e.BITBUCKET_BUILD_NUMBER}`:void 0}}var Ue=[{isMatch:e=>e.GITHUB_ACTIONS==="true",detect:Re},{isMatch:e=>e.GITLAB_CI==="true",detect:be},{isMatch:e=>e.TF_BUILD==="True",detect:ye},{isMatch:e=>e.CIRCLECI==="true",detect:Ie},{isMatch:e=>!!e.JENKINS_URL,detect:Ce},{isMatch:e=>!!e.BITBUCKET_BUILD_NUMBER,detect:_e}];function Ee(){let e=he();for(let t of Ue)if(t.isMatch(e))return t.detect(e);return{}}});var E=R(b=>{"use strict";var Se=b&&b.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(b,"__esModule",{value:!0});b.resolveSourceSnippetOptions=v;b.enrichReportWithSourceSnippets=Le;var Ne=_("node:fs/promises"),U=Se(_("node:path")),Be=2e3,we=40;function v(e){return{sourceRoot:U.default.resolve(e?.sourceRoot??process.cwd()),maxChars:W(e?.maxChars,Be),maxLines:W(e?.maxLines,we)}}async function Le(e,t){let r=v(t),n=new Map;await Promise.all(e.results.tests.map(async i=>{if(i.snippet||!i.filePath||!i.line)return;let o=await Oe(i,r,n);o&&(i.snippet=o)}))}async function Oe(e,t,r){let n=U.default.resolve(t.sourceRoot,e.filePath);if(!De(n,t.sourceRoot))return;let i=await xe(n,r);if(i)return Pe(i,e.line,t)}function xe(e,t){let r=t.get(e);return r||(r=(0,Ne.readFile)(e,"utf-8").catch(()=>{}),t.set(e,r)),r}function Pe(e,t,r){let n=e.split(/\r?\n/),i=Math.max(0,Math.min(n.length-1,t-1)),o=Ae(n,i);if(o==null)return;let a=[],u=0,s=!1;for(let p=o;p<n.length&&a.length<r.maxLines;p++){let l=n[p];a.push(l);for(let f of l)f==="{"?(u++,s=!0):f==="}"&&u--;if(s&&u<=0&&Me(l))break}let c=a.join(`
1
+ var ue=Object.create;var j=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var de=Object.getPrototypeOf,pe=Object.prototype.hasOwnProperty;var _=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,r)=>(typeof require<"u"?require:t)[r]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var R=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(r){throw t=0,r}};var fe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of le(t))!pe.call(e,i)&&i!==r&&j(e,i,{get:()=>t[i],enumerable:!(n=ce(t,i))||n.enumerable});return e};var V=(e,t,r)=>(r=e!=null?ue(de(e)):{},fe(t||!e||!e.__esModule?j(r,"default",{value:e,enumerable:!0}):r,e));var G=R(K=>{"use strict";Object.defineProperty(K,"__esModule",{value:!0})});var M=R(A=>{"use strict";Object.defineProperty(A,"__esModule",{value:!0});A.detectCIContext=Ee;function P(e,t){if(e)return e.startsWith(t)?e.slice(t.length):e}function he(){return globalThis.process?.env??{}}function me(e){if(!(!e.GITHUB_SERVER_URL||!e.GITHUB_REPOSITORY))return`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}`}function Te(e){if(!(!e.GITHUB_SERVER_URL||!e.GITHUB_REPOSITORY||!e.GITHUB_RUN_ID))return`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}/actions/runs/${e.GITHUB_RUN_ID}`}function ge(e){if(e.GITHUB_HEAD_REF)return e.GITHUB_HEAD_REF;if(e.GITHUB_REF?.startsWith("refs/heads/"))return e.GITHUB_REF_NAME??P(e.GITHUB_REF,"refs/heads/")}function Re(e){return{branch:ge(e),commitSha:e.GITHUB_SHA,repositoryUrl:me(e),buildNumber:e.GITHUB_RUN_NUMBER,buildUrl:Te(e)}}function be(e){return{branch:e.CI_COMMIT_BRANCH||e.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME,commitSha:e.CI_COMMIT_SHA,repositoryUrl:e.CI_PROJECT_URL,buildNumber:e.CI_PIPELINE_IID,buildUrl:e.CI_PIPELINE_URL}}function ye(e){return{branch:P(e.BUILD_SOURCEBRANCH,"refs/heads/"),commitSha:e.BUILD_SOURCEVERSION,repositoryUrl:e.BUILD_REPOSITORY_URI,buildNumber:e.BUILD_BUILDNUMBER,buildUrl:e.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI&&e.SYSTEM_TEAMPROJECT&&e.BUILD_BUILDID?`${e.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI}${e.SYSTEM_TEAMPROJECT}/_build/results?buildId=${e.BUILD_BUILDID}`:void 0}}function Ie(e){return{branch:e.CIRCLE_BRANCH,commitSha:e.CIRCLE_SHA1,repositoryUrl:e.CIRCLE_REPOSITORY_URL,buildNumber:e.CIRCLE_BUILD_NUM,buildUrl:e.CIRCLE_BUILD_URL}}function Ce(e){return{branch:P(e.GIT_BRANCH,"origin/"),commitSha:e.GIT_COMMIT,repositoryUrl:e.GIT_URL,buildNumber:e.BUILD_NUMBER,buildUrl:e.BUILD_URL}}function _e(e){return{branch:e.BITBUCKET_BRANCH,commitSha:e.BITBUCKET_COMMIT,repositoryUrl:e.BITBUCKET_GIT_HTTP_ORIGIN,buildNumber:e.BITBUCKET_BUILD_NUMBER,buildUrl:e.BITBUCKET_REPO_FULL_NAME&&e.BITBUCKET_BUILD_NUMBER?`https://bitbucket.org/${e.BITBUCKET_REPO_FULL_NAME}/pipelines/results/${e.BITBUCKET_BUILD_NUMBER}`:void 0}}var Ue=[{isMatch:e=>e.GITHUB_ACTIONS==="true",detect:Re},{isMatch:e=>e.GITLAB_CI==="true",detect:be},{isMatch:e=>e.TF_BUILD==="True",detect:ye},{isMatch:e=>e.CIRCLECI==="true",detect:Ie},{isMatch:e=>!!e.JENKINS_URL,detect:Ce},{isMatch:e=>!!e.BITBUCKET_BUILD_NUMBER,detect:_e}];function Ee(){let e=he();for(let t of Ue)if(t.isMatch(e))return t.detect(e);return{}}});var E=R(b=>{"use strict";var Se=b&&b.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(b,"__esModule",{value:!0});b.resolveSourceSnippetOptions=v;b.enrichReportWithSourceSnippets=Le;var Ne=_("node:fs/promises"),U=Se(_("node:path")),Be=2e3,we=40;function v(e){return{sourceRoot:U.default.resolve(e?.sourceRoot??process.cwd()),maxChars:W(e?.maxChars,Be),maxLines:W(e?.maxLines,we)}}async function Le(e,t){let r=v(t),n=new Map;await Promise.all(e.results.tests.map(async i=>{if(i.snippet||!i.filePath||!i.line)return;let o=await Oe(i,r,n);o&&(i.snippet=o)}))}async function Oe(e,t,r){let n=U.default.resolve(t.sourceRoot,e.filePath);if(!De(n,t.sourceRoot))return;let i=await xe(n,r);if(i)return Pe(i,e.line,t)}function xe(e,t){let r=t.get(e);return r||(r=(0,Ne.readFile)(e,"utf-8").catch(()=>{}),t.set(e,r)),r}function Pe(e,t,r){let n=e.split(/\r?\n/),i=Math.max(0,Math.min(n.length-1,t-1)),o=Ae(n,i);if(o==null)return;let a=[],u=0,s=!1;for(let p=o;p<n.length&&a.length<r.maxLines;p++){let l=n[p];a.push(l);for(let f of l)f==="{"?(u++,s=!0):f==="}"&&u--;if(s&&u<=0&&Me(l))break}let c=a.join(`
2
2
  `).trim();if(c)return c.length<=r.maxChars?c:c.slice(0,r.maxChars)}function Ae(e,t){for(let r=t;r>=0;r--)if(/\b(?:test|it)(?:\.(?:only|skip|fixme|slow))?\s*\(/.test(e[r]))return r}function Me(e){let t=e.length-1;for(;t>=0&&/\s/.test(e[t]);)t--;for(t>=0&&e[t]===";"&&t--;t>=0&&/\s/.test(e[t]);)t--;if(t<1||e[t]!==")")return!1;for(t--;t>=0&&/\s/.test(e[t]);)t--;return t>=0&&e[t]==="}"}function De(e,t){let r=U.default.relative(t,e);return r.length>0&&!r.startsWith("..")&&!U.default.isAbsolute(r)}function W(e,t){return typeof e=="number"&&Number.isInteger(e)&&e>0?e:t}});var Y=R(y=>{"use strict";Object.defineProperty(y,"__esModule",{value:!0});y.ensureReportId=q;y.uploadTestRun=We;y.mapAttachmentsToTestResults=ve;y.uploadArtifacts=qe;var $e=M(),Fe=E(),ke="https://api.testream.app";function q(e){if(typeof e.reportId=="string"&&e.reportId.trim().length>0)return e.reportId;let t=crypto.randomUUID();return e.reportId=t,t}function J(e){let t=z(e);if(t)return t;let r=He();return r||ke}function He(){if(!(typeof process>"u"||!process?.env))return z(process.env.TESTREAM_API_URL)}function z(e){if(!e)return;let t=e.trim();if(!t)return;let r=t;for(;r.endsWith("/");)r=r.slice(0,-1);return r}function je(e){return e.errorCode==="report_already_exists"}function Ve(e){let t=e.detail||e.title||e.rawBody||"Unknown error",r=e.errorCode?`, code=${e.errorCode}`:"";return`Upload failed (HTTP ${e.statusCode}${r}): ${t}`}async function Ke(e){let t=await e.text();if((e.headers.get("content-type")||"").toLowerCase().includes("json")&&t.trim().length>0)try{let n=JSON.parse(t);return{statusCode:e.status,title:n.title,detail:n.detail||n.details||n.error,errorCode:n.errorCode,rawBody:t}}catch{}return{statusCode:e.status,rawBody:t}}function Ge(e){let t=(0,$e.detectCIContext)();return{commitSha:e.commitSha??t.commitSha,branch:e.branch??t.branch,repositoryUrl:e.repositoryUrl??t.repositoryUrl,buildName:e.buildName,buildNumber:e.buildNumber??t.buildNumber,buildUrl:e.buildUrl??t.buildUrl,testEnvironment:e.testEnvironment,appName:e.appName,appVersion:e.appVersion,testType:e.testType}}async function We(e){let{report:t,apiKey:r}=e,n=J(e.apiUrl),i=q(t),o=Ge(e);await(0,Fe.enrichReportWithSourceSnippets)(t);let a={report:t,reportId:i,...o};console.log("Uploading test results...");let u;try{u=await fetch(`${n}/api/v1/ingest`,{method:"POST",headers:{"X-API-KEY":r,"Content-Type":"application/json"},body:JSON.stringify(a)})}catch(c){let l=`Connection failed: ${c instanceof Error?c.message:String(c)}`;return console.error(l),{success:!1,reportId:i,error:l}}if(!u.ok){let c=await Ke(u);if(u.status===409&&je(c))return console.warn("Report already exists (workflow may have been re-run)"),{success:!0,reportId:i,summary:{passed:t.results.summary.passed,failed:t.results.summary.failed,skipped:t.results.summary.skipped,total:t.results.summary.tests},alreadyExists:!0,statusCode:c.statusCode,errorCode:c.errorCode};let p=Ve(c);return console.error(p),{success:!1,reportId:i,error:p,statusCode:c.statusCode,errorCode:c.errorCode,errorDetail:c.detail||c.rawBody}}let s=await u.json();return console.log("\u2713 Test results uploaded successfully"),console.log(` Report ID: ${s.reportId}`),console.log(` Test Run ID: ${s.testRunId}`),console.log(` Tests: ${s.summary.passed}/${s.summary.total} passed`),{success:!0,reportId:s.reportId,testRunId:s.testRunId,summary:{passed:s.summary.passed,failed:s.summary.failed,skipped:s.summary.skipped,total:s.summary.total},testResults:s.testResults}}function ve(e,t){let r=new Map;for(let i of t){let o=r.get(i.name)??[];o.push(i.id),r.set(i.name,o)}let n=[];for(let i of e){let a=r.get(i.name)?.shift();if(!(!i.attachments||i.attachments.length===0)){if(!a){console.warn(`Skipping artifact upload: could not match test result for "${i.name}"`);continue}n.push({testResultId:a,attachments:i.attachments})}}return n}async function qe(e){let{reportId:t,apiKey:r,testResults:n}=e,i=J(e.apiUrl),o=0;for(let a of n)for(let u of a.attachments)try{await Je({testResultId:a.testResultId,attachment:u,reportId:t,apiKey:r,apiUrl:i})&&o++}catch(s){let c=s instanceof Error?s.message:String(s);console.error(`Failed to upload artifact ${u.name}: ${c}`)}return o>0&&console.log(`\u2713 Uploaded ${o} artifact(s)`),o}async function Je(e){let{testResultId:t,attachment:r,reportId:n,apiKey:i,apiUrl:o}=e,a=await import("node:fs/promises"),u=await import("node:path"),s=u.resolve(r.path);try{await a.access(s)}catch{return console.warn(`Artifact not found: ${u.basename(s)}`),!1}let c,p,l=u.basename(s),f=r.contentType||"application/octet-stream";try{c=await a.readFile(s),p=c.byteLength}catch(h){let g=h instanceof Error?h.message:String(h);throw new Error(`Failed to read file: ${g}`)}try{return await ze({testResultId:t,reportId:n,apiKey:i,apiUrl:o,attachmentName:r.name,fileName:l,contentType:f,sizeBytes:p,fileBuffer:c})}catch(h){if(!(h instanceof S))throw h;return await Ye({testResultId:t,attachmentName:r.name,reportId:n,apiKey:i,apiUrl:o,fileName:l,contentType:f,fileBuffer:c})}}var S=class extends Error{constructor(){super("Legacy upload endpoint required")}};async function ze(e){let{testResultId:t,reportId:r,apiKey:n,apiUrl:i,attachmentName:o,fileName:a,contentType:u,sizeBytes:s,fileBuffer:c}=e,p={testResultId:t,ctrfAttachmentName:o,fileName:a,contentType:u,sizeBytes:s},l=await fetch(`${i}/api/v1/artifacts/${r}/upload-url`,{method:"POST",headers:{"X-API-KEY":n,"Content-Type":"application/json"},body:JSON.stringify(p)});if(Xe(l.status))throw new S;if(!l.ok){let I=await l.text();throw new Error(`Failed to create direct upload URL (HTTP ${l.status}): ${I}`)}let f=await l.json(),h={...f.requiredHeaders};Qe(h,"Content-Type")||(h["Content-Type"]=u);let g=await fetch(f.uploadUrl,{method:"PUT",headers:h,body:c});if(!g.ok){let I=await g.text();throw new Error(`Direct artifact upload failed (HTTP ${g.status}): ${I}`)}let H={testResultId:t,ctrfAttachmentName:o,fileName:a,contentType:u,sizeBytes:s,storageKey:f.storageKey},x=await fetch(`${i}/api/v1/artifacts/${r}/complete`,{method:"POST",headers:{"X-API-KEY":n,"Content-Type":"application/json"},body:JSON.stringify(H)});if(!x.ok){let I=await x.text();throw new Error(`Failed to finalize artifact upload (HTTP ${x.status}): ${I}`)}return!0}async function Ye(e){let{testResultId:t,attachmentName:r,reportId:n,apiKey:i,apiUrl:o,fileName:a,contentType:u,fileBuffer:s}=e,c=new Blob([new Uint8Array(s)],{type:u}),p=new FormData;p.append("testResultId",t),p.append("ctrfAttachmentName",r),p.append("file",c,a);let l=await fetch(`${o}/api/v1/artifacts/${n}`,{method:"POST",headers:{"X-API-KEY":i},body:p});if(!l.ok){let f=await l.text();throw new Error(`Legacy artifact upload failed (HTTP ${l.status}): ${f}`)}return!0}function Xe(e){return e===404||e===405||e===501}function Qe(e,t){let r=t.toLowerCase();return Object.keys(e).some(n=>n.toLowerCase()===r)}});var re=R(C=>{"use strict";var Ze=C&&C.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(C,"__esModule",{value:!0});C.enrichReportWithJsTestNameSourceSnippets=nt;var et=_("node:fs/promises"),D=Ze(_("node:path")),tt=E(),rt=3,X=/\b(describe|it|test)(?:\.(only|skip))?\s*\(\s*(['"`])/g;async function nt(e,t){let r=(0,tt.resolveSourceSnippetOptions)(t),n=new Map;await Promise.all(e.results.tests.map(async i=>{if(i.snippet||!i.filePath)return;let o=D.default.resolve(r.sourceRoot,i.filePath);if(!yt(o,r.sourceRoot))return;let a=await it(o,n);if(!a)return;let u=at(i,a).slice(0,rt);u.length!==0&&(i.line??(i.line=u[0].line),i.snippet=ut(u,r))}))}function it(e,t){let r=t.get(e);return r||(r=(0,et.readFile)(e,"utf-8").then(n=>ot(n)).catch(()=>{}),t.set(e,r)),r}function ot(e){let t=mt(e),r=st(e,t),n=r.filter(i=>i.kind==="describe");return r.filter(i=>i.kind==="test").map(i=>{let o=n.filter(a=>a.startIndex<i.startIndex&&a.endIndex>=i.endIndex).sort((a,u)=>a.startIndex-u.startIndex).map(a=>a.title);return{title:i.title,describeTitles:o,fullName:[...o,i.title].join(" ").trim(),line:i.startLine,snippet:i.snippet}})}function st(e,t){let r=[];X.lastIndex=0;let n;for(;(n=X.exec(e))!==null;){if(gt(e,n.index))continue;let i=dt(e,n.index+n[0].length,n[3]);if(!i)continue;let o=pt(e,i.endIndex+1);if(o==null)continue;let a=n[1]==="describe"?"describe":"test",u=n.index,s=ct(e,o+1);if(s==null)continue;let c=lt(e,s);if(c==null)continue;let p=ft(e,c),l=e.slice(u,p).trim();l&&r.push({kind:a,title:i.value.trim(),startIndex:u,endIndex:p,startLine:Tt(t,u),snippet:l})}return r}function at(e,t){let r=m(e.name),n=bt(e.suite),i=t.filter(a=>m(a.fullName)===r);if(i.length>0)return i;if(n){let a=t.filter(u=>m(u.title)===r&&m(u.describeTitles.join(" "))===n);if(a.length>0)return a}let o=t.filter(a=>m(a.title)===r);return o.length>0?o:t.filter(a=>{let u=m(a.title);if(!r.endsWith(u))return!1;let s=r.slice(0,r.length-u.length).trim();return s.length>0&&m(a.describeTitles.join(" "))===s})}function ut(e,t){let n=(e.length===1?e[0].snippet:e.map((i,o)=>`Candidate ${o+1} (line ${i.line})
3
3
  ${i.snippet}`).join(`
4
4
 
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@testream/vitest-reporter",
3
- "version": "1.2.1",
4
- "description": "Vitest reporter to upload test results to Testream",
3
+ "version": "1.2.3",
4
+ "description": "Publish Vitest test results, failures, source locations, and CI metadata to Testream and Jira.",
5
+ "homepage": "https://testream.app/vitest-jira-integration",
5
6
  "main": "dist/cjs/index.js",
6
7
  "module": "dist/esm/index.mjs",
7
8
  "types": "dist/index.d.ts",
@@ -29,14 +30,20 @@
29
30
  "url": "git+https://github.com/testream/docs.git"
30
31
  },
31
32
  "keywords": [
33
+ "testream",
32
34
  "vitest",
33
- "reporter",
34
- "testing",
35
- "test-management",
36
- "test-results",
35
+ "vitest-reporter",
36
+ "vitest-jira",
37
37
  "jira",
38
+ "test-management",
39
+ "automated-test-management",
40
+ "test-reporting",
41
+ "ci-cd",
38
42
  "ctrf",
39
- "testream"
43
+ "vite",
44
+ "react",
45
+ "vue",
46
+ "angular"
40
47
  ],
41
48
  "author": "Testream",
42
49
  "license": "SEE LICENSE IN LICENSE",
@@ -49,14 +56,14 @@
49
56
  "devDependencies": {
50
57
  "@jira-test-manager/shared-types": "*",
51
58
  "@vercel/ncc": "^0.38.1",
52
- "esbuild": "^0.28.0",
53
- "vitest": "^3.0.0",
54
- "@types/node": "^20.10.6",
59
+ "esbuild": "^0.28.1",
60
+ "vitest": "^4.1.9",
61
+ "@types/node": "^25.9.3",
55
62
  "@typescript-eslint/eslint-plugin": "^6.17.0",
56
63
  "@typescript-eslint/parser": "^6.17.0",
57
64
  "eslint": "^8.56.0",
58
65
  "prettier": "^3.1.1",
59
- "typescript": "^5.3.3"
66
+ "typescript": "^6.0.3"
60
67
  },
61
68
  "engines": {
62
69
  "node": ">=18.0.0"